学习运维第七天:bash shell 脚本编程

编程基础

程序组成
程序

一组计算机能识别和执行的指令,运行于电子计算机上,满足人们某种需求的信息化工具。它以某些程 序设计语言编写,运行于某种目标结构体系上。

算法

算法是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,代表着用系统的方法描述解决 问题的策略机制。

数据结构

数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素 的集合。通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率。

数据

是程序的核心,程序为数据提供服务,也是互联网公司最重要的资产。

程序编程风格
面向过程
  • 做一件事情,排出个步骤,第一步干什么,第二步干什么,如果出现情况A,做什么处理,如果出 现了情况B,做什么处理

  • 问题规模小,可以步骤化,按部就班处理

  • 以指令为中心,数据服务于指令

  • C,shell

面向对象
  • 将编程看成是一个事物,对外界来说,事物是直接使用的,不用关心事物内部的情况。而编程就是 设置事物能够完成功能。

  • 一种认识世界、分析世界的方法论。将万事万物抽象为各种对象

  • 类是抽象的概念,是万事万物的抽象,是一类事物的共同特征的集合

  • 对象是类的具体实现,是一个实体

  • 问题规模大,复杂系统

  • 以数据为中心,指令服务于数据

  • java,C#,python,golang等

编程逻辑处理方式
三种处理逻辑:
  • 顺序执行:程序按从上到下顺序执行

  • 选择执行:程序执行过程中,根据条件的不同,进行选择不同分支继续执行

  • 循环执行:程序执行过程中需要重复执行多次某段语句

shell 脚本语言的基本用法

shell 脚本的用途
  • 将简单的命令组合完成复杂的工作,自动化执行命令,提高工作效率

  • 减少手工命令的输入,一定程度上避免人为错误

  • 将软件或应用的安装及配置实现标准化

  • 用于实现日常性的,重复性的,非交互式的运维工作,如:文件打包压缩备份,监控系统运行状态 并实现告警等

shell 脚本基本结构

shell是基于过程式、解释执行的语言。

shell脚本是包含一些命令或声明,并符合一定格式的文本文件。

一个shell脚本文件中主要包含以下内容

  • 各种系统命令的组合

  • 数据存储:变量、数组

  • 表达式:a + b

  • 控制语句:if

格式要求:首行shebang机制

#!/bin/bash 
#!/usr/bin/python
#!/usr/bin/perl 
#!/usr/bin/ruby
#!/usr/bin/lua
shell脚本创建过程
  1. 用编辑器创建新文件,首行必须是 shell 声明(shebang),编辑完成后保存退出

  2. 添加可执行权限

  3. 运行脚本

#新建文件
[root@ubuntu2204 ~]# vim test.sh
#!/bin/bash
echo "hello world"

#加可执行权限
[root@ubuntu2204 ~]# chmod +x test.sh

#执行,相对路径
[root@ubuntu2204 ~]# ./test.sh 
hello world

#执行,绝对路径
[root@ubuntu2204 ~]# /root/test.sh 
hello world

#相当于执行命令,会在 $PATH 路径下去找,找不到就报错
[root@ubuntu2204 ~]# test.sh 
test.sh: command not found
shell 脚本注释规范

一般要注明作者,创建(修改)时间,文件名,版本号,该程序的功能及作用,目地,版权信息,作者联系 方式等

配置vim 自动生成注释

[root@ubuntu2204 ~]# vim .vimrc
set nu
set ts=4
autocmd BufNewFile *.sh exec ":call SetTitle()"
func SetTitle()
    if expand("%:e") == 'sh'
       call setline(1,"#!/bin/bash")
       call setline(2,"#")
       call setline(3,"#****************************************************")
       call setline(4,"#Author:           jose")
       call setline(5,"#QQ:               123456")
       call setline(6,"#Date:             ".strftime("%Y-%m-%d"))
       call setline(7,"#FileName:         ".expand("%"))
       call setline(8,"#URL:               http://www.baidu.com")
       call setline(9,"#Description:       test")
       call setline(10,"#Copyright(C):     ".strftime("%Y")." All right")
       call setline(11,"#***************************************************")
       call setline(12,"")
       call setline(13,"")
       call setline(14,"")
   endif
endfunc
autocmd BufNewFile * normal G

第一个 shell 脚本

#当前进程中执行
root@ubuntu2204 ~]# . hello.sh 
hello, world
Hello, world!

#子进程中执行
root@ubuntu2204 ~]# ./hello.sh 
hello, world
Hello, world!

#本地执行远程脚本 - 脚本文件在远程主机,在本机执行并在本机生效,执行结果影响的是本机
root@ubuntu2204 ~]# curl http://10.0.0.157/test.sh -s | bash
hello, world
Hello, world!

root@ubuntu2204 ~]# curl http://10.0.0.157/test.sh 2>/dev/null | bash
hello, world
Hello, world!

root@ubuntu2204 ~]# wget -qO - http://10.0.0.157/test.sh | bash
hello, world
Hello, world!

#在远程主机运行本地脚本 - 脚本文件在本地,在远程主机执行并生效,执行结果影响的是远程主机,但终端中的输出在本地显示
#本地执行
root@ubuntu2204 ~]# bash test2.sh 
10.0.0.150
#远程主机上执行
root@ubuntu2204 ~]# ssh [email protected] /bin/bash < test2.sh 
[email protected]'s password: 
10.0.0.157
shell 脚本调试

1.执行前先做语法检查 此选项只能检测脚本中的语法错误,不能检测命令错误,也不会执行脚本

bash -n test.sh

2.调试并执行 逐行输出命令,并输出执行结果

bash -x test.sh

总结:脚本错误常见的有三种

  • 语法错误:会导致后续的命令不继续执行,可以用 bash -n 检查错误,提示的出错行数不一定是准 确的

  • 命令错误:默认后续的命令还会继续执行,用 bash -n 无法检查出来 ,可以使用 bash -x 进行观察

  • 逻辑错误:只能使用 bash -x 进行观察

变量

变量表示命名的内存空间,将数据放在内存空间中,通过变量名引用,获取数据

数据要存在内存空间中,而内存空间又是通过内存地址来访问的,但内存地址一般是16进制的编号;

为了方便使用,就有了变量名,当访问一个变量时,实际是访问其对应的内存地址的那块内存空间;

变量类型

变量类型:

  • 内置变量,如:PS1,PATH,UID,HOSTNAME,$$,BASHPID,PPID,$?,HISTSIZE

  • 用户自定义变量

不同的变量存放的数据不同,决定了以下

  • 数据存储方式

  • 参与的运算

  • 表示的数据范围

变量数据类型:

  • 字符

  • 数值:整型、浮点型,bash 不支持浮点数

  • 布尔

  • 指针

  • 结构体:自定义的复合类型的数据类型

  • ......

变量定义和引用

变量的生效范围等标准划分变量类型

普通变量:生效范围为当前shell进程;对当前shell之外的其它shell进程,包括当前shell的子shell 进程均无效

环境变量:生效范围为当前shell进程及其子进程

本地变量:生效范围为当前shell进程中某代码片断,通常指函数

变量赋值:
name='value'

#value 可以是以下多种形式
name='root' #直接字串
name="$USER" #变量引用
name=`COMMAND` #命令引用
name=$(COMMAND) #命令引用
#注意:变量赋值是临时生效,当退出终端后,变量会自动删除,无法持久保存,脚本中的变量会随着脚本结束,也会自动删除
变量引用:
$name
${name}  #标准写法

弱引用和强引用

  • "$name" 弱引用,其中的变量引用会被替换为变量值

  • '$name' 强引用,其中的变量引用不会被替换为变量值,而保持原字符串

保留格式

[root@ubuntu2204 ~]# seq 5
1
2
3
4
5
[root@ubuntu2204 ~]# NUM=`seq 5`
[root@ubuntu2204 ~]# echo $NUM
1 2 3 4 5
[root@ubuntu2204 ~]# echo "$NUM"
1
2
3
4
5
显示已定义的所有变量:
set
删除变量:
unset 
环境变量
  • 可以使子进程(包括孙子进程)继承父进程的变量,但是无法让父进程使用子进程的变量

  • 一旦子进程修改从父进程继承的变量,将会新的值传递给孙子进程

  • 一般只在系统配置文件中使用,在脚本中较少使用

变量声明和赋值:

#声明并赋值
export name=VALUE
declare -x name=VALUE

#或者分两步实现
name=VALUE
export name

显示所有环境变量:

env
printenv
export
declare -x

查看指定进程的环境变量

cat /proc/$PID/environ
只读变量

只读变量:只能声明定义,但后续不能修改和删除,即常量

声明只读变量:

readonly name
declare -r name

查看只读变量

readonly [-p]
declare -r
位置变量

位置变量:在bash shell中内置的变量,在脚本代码中调用通过命令行传递给脚本的参数

$1,$2,... 		#对应第1个、第2个等参数,shift [n]换位置
$0 				#命令本身,包括路径
$* 				#传递给脚本的所有参数,全部参数合为一个字符串
$@ 				#传递给脚本的所有参数,每个参数为独立字符串
$# 				#传递给脚本的参数的个数

#清空所有位置变量
set --

$*和$@的区别

$*和$@ 都表示传递给函数或脚本的所有参数。它们之间的区别在于:

  • $*将所有参数从整体上看做一份数据,不把每个参数都看做独立的。

  • $@仍然将每个参数都看作一份数据,彼此之间是独立的。

退出状态码变量

进程执行后,将使用变量 $? 保存状态码的相关数字,不同的值反应成功或失败,$?取值范例 0-255

$?   	#0代表成功,1-255代表失败

用户可以在脚本中使用以下命令自定义退出状态码

exit [n]

注意:

  • 脚本中一旦遇到exit命令,脚本会立即终止;终止退出状态取决于exit命令后面的数字

  • 如果exit后面无数字,终止退出状态取决于exit命令前面命令执行结果

  • 如果没有exit命令,即未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后 一 条命令的状态码

展开命令行
展开命令执行顺序
把命令行分成单个命令词
展开别名
展开大括号的声明{}
展开波浪符声明 ~
命令替换$() 和 ``
再次把命令行分成命令词
展开文件通配符*、?、[abc]等等
准备I/0重导向 <、>
运行命令

防止扩展

\ 		#反斜线 会使随后的字符按原意解释
'' 		#单引号 防止所有扩展
""		#双引号 也可防止扩展,但是以下情况例外 $

变量扩展

`` 		#反引号,命令替换
\ 		#反斜线,禁止单个字符扩展
! 		#叹号,历史命令替换
脚本安全和 set

set 命令:可以用来定制 shell 环境

$- 变量
选项 含义 备注
h hashall 开启hash表缓存外部命令路径
i interactive-comments 表示当前是交互是shell
m monitor 开启监控模式,可通过 Job control来控制进程的停止、继续,后台 或者前台执行等
B braceexpand 是否支持大括号扩展
H history 是否可用 ! 快速展开history命令
#查看命令行下的配置
[root@ubuntu2204 ~]# echo $-
himBHs

#示例:#关闭hash缓存功能
[root@ubuntu22:~]# echo $-
himBHs
[root@ubuntu22:~]# hash
hits	command
   1	/usr/bin/mesg
   1	/usr/bin/seq
[root@ubuntu22:~]# set +h
[root@ubuntu22:~]# echo $-
imBHs
[root@ubuntu22:~]# hash
-bash: hash: hashing disabled
[root@ubuntu22:~]# set -h
[root@ubuntu22:~]# echo $-
himBHs
[root@ubuntu22:~]# hash
hits	command
   1	/usr/bin/mesg
   1	/usr/bin/seq
set 命令实现脚本安全
字符 作用
u 开启此项,在使用一个没有声明的变量时,会报错,并且终止程序,同 set -o nounset
e 开启此项,命令返回非0就退出,不再继续执行后面的代码,同 set -o errexit
o set -o 显示所有; set -o option 开启 option 项; set +o option 关闭 option 项
x set -x 打印命令及其参数
  • -u 在扩展一个没有设置的变量时,显示错误信息, 等同set -o nounset

  • -e 如果一个命令返回一个非0退出状态值(失败)就退出, 等同set -o errexit

  • -o option 显示,打开或者关闭选项 显示选项:set -o 打开选项:set -o 选项 关闭选项:set +o 选 项

  • -x 当执行命令时,打印命令及其参数,类似 bash -x

格式化输出 printf

相当于增强版的 echo, 实现丰富的格式化输出

格式

printf format args...
常用格式替换符
替换符 功能
%s 字符串
%d,%i 十进制整数
%f 浮点格式
%c ASCII字符,即显示对应参数的第一个字符
%b 相对应的参数中包含转义字符时,可以使用此替换符进行替换,对应的转义字符会被转义
%o 八进制值
%u 不带正负号的十进制
%x 十六进制的值(a-f)
%X 十六进制值(A-F)
%% 表示%本身

说明:

%[N]s 			# N表示输出宽度,不够补空格 -N 表示左对齐
%[0][N]d 		# 0表示宽度不够时在左边补0,N表示输出宽度
%[.N]f 			# .N 表示保留的小数位
常用转义字符
转义符 功能
\a 警告字符,通常为ASCII的BEL字符
\b 后退
\f 换页
\n 换行
\r 回车
\t 水平制表符
\v 垂直制表符
\ 表示\本身

算术运算

Shell允许在某些情况下对算术表达式进行求值,比如:let和declare 内置命令,(( ))复合命令和算术扩 展。求值以固定宽度的整数进行,不检查溢出,尽管除以0 被标记为错误。运算符及其优先级,关联性 和值与C语言相同。以下运算符列表分组为等优先级运算符级别。级别按降序排列优先。

注意:bash 只支持整数,不支持小数

+ -   		#addition, subtraction加、减
* / % 		#multiplication, division, remainder, %表示取模,即取余数,示例:9%4=1,5%3=2 
i++ i-- 	#variable post-increment and post-decrement变量的后递增和后递减
++i --i 	#variable pre-increment and pre-decrement变量的预递增和预递减
= *= /= %= += -= <<= >>= &= ^= |=   #assignment赋值
- +   	#unary minus and plus
! ~   	#logical and bitwise negation
**     	#exponentiation 乘方,即指数运算
<< >> #left and right bitwise shifts
<= >= < >     #comparison
== != #equality and inequality
&     	#bitwise AND
|     	#bitwise OR
^     	#bitwise exclusive OR
&&     	#logical AND
||     	#logical OR
expr?expr:expr     #conditional operator
expr1 , expr2     #comma

乘法符号有些场景中需要转义

实现算术运算:

let var=expression
((var=expression))
var=$[expression]
var=$((expression))
var=$(expr arg1 arg2 ...)
declare -i var=number
echo expression|bc

#expr 命令
#表达式中间要有空格
[root@ubuntu2204 ~]# expr 10+20
10+20
[root@ubuntu2204 ~]# expr 10 + 20
30
[root@ubuntu2204 ~]# expr 10 \* 20
200

#内核的随机数生成器变量
$RANDOM   		#取值范围:0-32767
echo -e "\033[1;$[RANDOM%7+31]mhello\033[0m"    #随机字体颜色

增强型赋值:

+= 			# i+=10 相当于 i=i+10
-= 			# i-=j 相当于 i=i-j
*=
/=
%=
++ 			# i++,++i   相当于 i=i+1
-- 			# i--,--i   相当于 i=i-1
逻辑运算
与或非

学习运维第七天:bash shell 脚本编程_第1张图片

true, false
bool值 二进制表示 说明
true 1
false 0

与:&

& 和0相与结果为0,和1相与结果保留原值, 一假则假,全真才真

变量1 变量2 与运算 与运算结果
0 0 0&0 0
0 1 0&1 0
1 0 1&0 0
1 1 1&1 1

或:|

| 和1相或结果为1,和0相或结果保留原值,一真则真,全假才假

变量1 变量2 与运算 与运算结果
0 0 0|0 0
0 1 0|1 1
1 0 1|0 1
1 1 1|1 1

非:!
变量 运算 非运算结果
1 !1 0
0 !0 1

异或:^

异或的两个值,相同为假,不同为真。两个数字X,Y异或得到结果Z,Z再和任意两者之一X异或,将得 出另一个值Y

变量1 变量2 异或运算 与运算结果
0 0 0^0 0
0 1 0^1 1
1 0 1^0 1
1 1 1^1 0

短路运算
短路与 &&
command1值 command2值 短路与运算 短路与运算结果
true true cmd1 && cmd2 true
true false cmd1 && cmd2 false
false cmd1 && cmd2 false

当 cmd1 的结果为 false 时,整个表达式就是 false, cmd2 不参与运算,这就是所谓的短路

短路或 ||
command1值 command2值 短路与运算 短路与运算结果
true cmd1 || cmd2 true
false true cmd1 || cmd2 true
false false cmd1 || cmd2 false

当 cmd1 的结果为 true 时,整个表达式就是 true, cmd2 不参与运算,这就是所谓的短路

短路与和或组合
command1 值 command2 值 command3值 短路运算 短路与运算结果
true true true cmd1 && cmd2 || cmd3 true
true true false cmd1 && cmd2 || cmd3 true
true false true cmd1 && cmd2 || cmd3 true
true false false cmd1 && cmd2 || cmd3 false
false true true cmd1 && cmd2 || cmd3 true
false true false cmd1 && cmd2 || cmd3 false
false false true cmd1 && cmd2 || cmd3 true
false false false cmd1 && cmd2 || cmd3 false

当cmd1 的结果为true时,会执行 cmd2;

当cmd1 的结果为false时,会执行 cmd3;

cmd1 || cmd2 && cmd3 这种语法是错误的,不使用;

条件测试命令

条件测试:

判断某需求是否满足,需要由测试机制来实现,专用的测试表达式需要由测试命令辅助完成测试过程, 实现评估布尔声明,以便用在条件性环境下进行执行

若真,则状态码变量 $? 返回0

若假,则状态码变量 $? 返回1

条件测试命令

test expr
[ arg... ] 			#同 test
[[ expression ]] 	#增加版的[],支持[],支持扩展正则表达式和通配符

注意:[] 中的表达式,前后要有空格

常用选项:
文件判断相关
-a FILE     #如果文件存在则为真
-b FILE     #如果文件为块特殊文件则为真
-c FILE     #如果文件为字符特殊文件则为真
-d FILE     #如果文件为目录则为真
-e FILE     #如果文件存在则为真
-f FILE     #如果文件存在且为常规文件则为真
-g FILE     #如果文件的组属性设置打开则为真
-h FILE     #如果文件为符号链接则为真
-L FILE     #如果文件为符号链接则为真
-k FILE     #如果文件的粘滞 (sticky) 位设定则为真
-p FILE     #如果文件为命名管道则为真
-r FILE     #如果当前用户对文件有可读权限为真
-s FILE     #如果文件存在且不为空则为真
-S FILE     #如果文件是套接字则为真
-t FD       #如果文件描述符在一个终端上打开则为真
-u FILE   	#如果文件设置了SUID特殊权限则为真
-w FILE     #如果当前用户对文件有可写权限为真
-x FILE     #如果当前用户对文件有可执行权限为真
-O FILE     #如果当前用户是文件属主为真
-G FILE     #如果当前用户对文件属组为真
-N FILE     #如果文件上次被读取之后修改过则为真
FILE1 -nt FILE2 #如果 file1 文件新于 file2 文件 则为真(根据修改日期)
FILE1 -ot FILE2 #如果 file1 文件旧于 file2 文件则为真
FILE1 -ef FILE2 #如果 file1 文件是 file2 文件的硬链接则为真

字符串判断相关

-z STRING     	#判断字符串是否为空,为空则为真
-n STRING 		#如果字符串不为空则为真
STRING 			#同上
#两个字符串变量比较,一定要有空格,如果没有空格,就变成赋值了
STRING1 = STRING2 	#如果 string1 和 string2 字符串相同则为真
STRING1 != STRING2 	#如果 string1 和 string2 字符串不相同则为真
STRING1 < STRING2   #只比较第一个字符,以字母表顺序来比较,string1在string2 之前则为真,< 要转义
STRING1 > STRING2   #只比较第一个字符,以字母表顺序来比较,string1在string2 之后则为真, > 要转义

数学相关

#数字相关 格式 arg1 OP arg2
-eq 		#等于
-ne 		#不等于
-lt 		#小于
-le 		#小于等于
-gt 		#大于
-ge 		#大于等于
#算术表达式比较
== 			#相等
!= 			#不相等
<= 			#小于或等于
>= 			#大于或等于
< 			#小于
> 			#大于

其他

o OPTION     		#如果在shell 中开启了某项,则为真
-v VAR         		#如果变量被设置为为真
-R VAR         		#如果变量被设置且被引用则为真
! EXPR         		#表达式结果取反
EXPR1 -a EXPR2 		#如果 expr1 和 expr2 都为真则为真 &&
EXPR1 -o EXPR2 		#如果 expr1 和 expr2 有一个为真则为真
变量测试

范例:判断变量是否被定义

[root@ubuntu2204 ~]# unset x
[root@ubuntu2204 ~]# test -v x 
[root@ubuntu2204 ~]# echo $?
1

[root@ubuntu2204 ~]# x=10
[root@ubuntu2204 ~]# test -v x 
[root@ubuntu2204 ~]# echo $?
0

[root@ubuntu2204 ~]# y=
[root@ubuntu2204 ~]# test -v y
[root@ubuntu2204 ~]# echo $?
0

#注意 [ ] 中需要空格,否则会报下面错误
[root@ubuntu2204 ~]# [-v name]
-bash: [-v: command not found
[root@ubuntu2204 ~]# [ -v name ]
[root@ubuntu2204 ~]# echo $?
0
数值测试
#示例
[root@ubuntu2204 ~]# i=10
[root@ubuntu2204 ~]# j=8
[root@ubuntu2204 ~]# [ $i -lt $j ] 
[root@ubuntu2204 ~]# echo $?
1
[root@ubuntu2204 ~]# [ $i -gt $j ] 
[root@ubuntu2204 ~]# echo $?
0
[root@ubuntu2204 ~]# [ i -gt j ] 
-bash: [: i: integer expression expected
字符串测试
test和 [ ] 字符串测试用法
-z STRING     	#判断字符串是否为空,为空则为真
-n STRING 		#如果字符串不为空则为真
STRING 			#同上
	
	
#两个字符串变量比较,一定要有空格,如果没有空格,就变成赋值了
STRING1 = STRING2 		#如果 string1 和 string2 字符串相同则为真
STRING1 != STRING2 		#如果 string1 和 string2 字符串不相同则为真
STRING1 < STRING2   	#只比较第一个字符,以字母表顺序来比较,string1在string2 之前则为真,< 要转义
STRING1 > STRING2   	#只比较第一个字符,以字母表顺序来比较,string1在string2 之后则为真, > 要转义
[[ ]] 字符串测试用法
[[ expression ]] 用法
== 		#左侧字符串是否和右侧的PATTERN相同
   		#注意:此表达式用于[[ ]]中,PATTERN为通配符
   
=~ 		#左侧字符串是否能够被右侧的正则表达式的PATTERN所匹配
   		#注意: 此表达式用于[[ ]]中为扩展的正则表达式

建议:当使用正则表达式或通配符使用[[ ]],其它情况一般使用 [ ]

文件测试
#文件是否不存在
[root@ubuntu2204 ~]# [ -a /etc/nologin ] 
[root@ubuntu2204 ~]# echo $?
1
[root@ubuntu2204 ~]# ! [ -a /etc/nologin ] 
[root@ubuntu2204 ~]# echo $?
0
#文件是否存在
[root@ubuntu2204 ~]# [ -a /etc/issue ]
[root@ubuntu2204 ~]# echo $?
0
#取反后结果却没有变化
[root@ubuntu2204 ~]# [ ! -a /etc/issue ]
[root@ubuntu2204 ~]# echo $?
0
[root@ubuntu2204 ~]#! [ -a /etc/issue ]
[root@ubuntu2204 ~]# echo $?
1
#文件是否存在
[root@ubuntu2204 ~]#! [ -e /etc/issue ]
[root@ubuntu2204 ~]# echo $?
1
#此为推荐写法
[root@ubuntu2204 ~]# [ ! -e /etc/issue ]
[root@ubuntu2204 ~]# echo $?
1
[root@ubuntu2204 ~]# [ -d /etc ]
[root@ubuntu2204 ~]# echo $?
0
[root@ubuntu2204 ~]# [ -d /etc/issue ]
[root@ubuntu2204 ~]# echo $?
1
[root@ubuntu2204 ~]# [ -L /bin ]
[root@ubuntu2204 ~]# echo $?
0
[root@ubuntu2204 ~]# [ -L /bin/ ]
[root@ubuntu2204 ~]# echo $?
1
文件权限测试:

注意:最终结果由用户对文件的实际权限决定,而非文件属性决定

[root@ubuntu2204 ~]# [ -w /etc/shadow ] 
[root@ubuntu2204 ~]# echo $?
0

[root@ubuntu2204 ~]# [ -x /etc/shadow ] 
[root@ubuntu2204 ~]# echo $?
1

[root@ubuntu2204 ~]# [ -w test.txt ]
[root@ubuntu2204 ~]# echo $?
0

[root@ubuntu2204 ~]# chattr +i test.txt 
[root@ubuntu2204 ~]# lsattr test.txt
----i---------e------- test.txt
[root@ubuntu2204 ~]# [ -w test.txt ]
[root@ubuntu2204 ~]# echo $?
1
[root@ubuntu2204 ~]# chattr -i test.txt 
[root@ubuntu2204 ~]# [ -w test.txt ]
[root@ubuntu2204 ~]# echo $?
0
关于 () 和 {}
( cmd1;cmd2;... ) 和 { cmd1;cmd2;...; } 都可以将多个命令组合在一起,批量执行
( list ) 会开启子shell,并且list中变量赋值及内部命令执行后,将不再影响后续的环境
{ list; } 不会开启子shell, 在当前shell中运行,会影响当前shell环境,左侧要有空格,右侧要有; 结束
组合测试条件
第一种方式
[ EXPRESSION1 -a EXPRESSION2 ] #并且,EXPRESSION1和EXPRESSION2都是真,结果才为真
[ EXPRESSION1 -o EXPRESSION2 ] #或者,EXPRESSION1和EXPRESSION2只要有一个真,结果就为真
[ ! EXPRESSION ] #取反

说明: -a 和 -o 需要使用测试命令进行,[[ ]] 不支持

第二种方式
条件表达式
COMMAND1 && COMMAND2 #并且,短路与,代表条件性的AND THEN
#如果COMMAND1成功,将执行COMMAND2,否则,将不执行COMMAND2

COMMAND1 || COMMAND2 #或者,短路或,代表条件性的OR ELSE
#如果COMMAND1 成功,将不执行COMMAND2,否则,将执行COMMAND2

! COMMAND   #非,取反

你可能感兴趣的:(学习,运维,bash)