shell表达式以及运算符
在Linux系统中,命令执行完成后会返回一个退出状态,如果为0表示退出成功,如何不为0,表示未成功。
退出状态及其含义如下:
| 退出状态 | 含义 |
| 0 | 表示命令执行成功,没有问题 |
| 1~125 | 执行失败,脚本命令、系统命令或参数传递错误 |
| 126 | 存在该命令,但是无法执行 |
| 127 | 未找到该命令 |
| >128 | 命令被系统强制结束 |
例如:分别使用cat命令以及cdt(不存在),作为测试,如图:

测试命令:
测试命令用于测试表达式真假,如果为真,则返回0,如果为假,则返回非0数值,测试命令有两种格式:
- test expression
- [ expression ]
上面两种格式的使用效果相同,但是一般使用第二种方式,第二种方式一般配置if、case、while等语句一起使用,shell脚本中的if [ ]中if后面的即为测试命令
注意:[ expressiom ]中的expression和中括号之间前后存在空格
整数比较运算符:
整数比较运算符用于整数比较,不能用于比较字符串以及文件,如果比较结果满足提交,则结果为真(测试条件用0表示),如果不满足则为假。
整数比较运算符
| 运算符 | 含义 |
| a -eq b | 如果a等于b,测试结果为0 |
| a -ge b | 如果a大于等于b,测试结果为0 |
| a -gt b | 如果a大于b,测试结果为0 |
| a -le b | 如果a小于等于b,测试结果为0 |
| a -lt b | 如果a小于b,测试结果为0 |
| a -ne b | 如果a不等于b,测试结果为0 |
例如:比较两个数值的大小,注意在引用的时候使用双引号,如图:

也可以将测试命令与输出命令放在一起书写,中间通过&&连接,表示前面的执行成功才会执行后面命令,如图:

整数比较运算符不适用浮点数的比较,如图:

字符串运算符:
字符串运算符用来测试字符串是否为空,两个字符串是否相等或者不相等。
字符串运算符及其含义
| 字符串运算符 | 含义 |
| string | 测试字符串string是否不为空 |
| == | 只是用来判断相等 |
| -n string | 测试字符串string是否不为空 |
| -z string | 测试字符串string是否为空 |
| string1 = string2 | 字符串string1是否与string2相同, = 除了可用于判断变量是否相等外,还可以表示赋值 |
| string1 != string2 | 测试字符串string1是否与字符串string2不相同 |
字符串比较的时候,建议使用双引号,即使变量为空,也要使用双引号。

下面比较字符串是否相等,设置两个字符串变量var1和var2,如图:

编写程序的时候,要注意空格问题,空格会造成测试结果不相等,如图:

shell编程是严格区分大小写的,hello不等于Hello,如图所示:

字符串赋值和整数赋值没有区别,在进行整数比较的时候,不要使用字符串比较运算符,使用的运算符不同,结果不同,如图:

判断字符串是否相等,前面判断成功才会执行后面,如图:

使用-n和-z来判断字符串是否为空的时候,需要加双引号,否则无法准确判断
例如:下面例子中,没有定义任何变量,直接通过-n和-z判断可以发现都是成功的,如图:

下面的是加了双引号之后可以看到能够准确判断,如图:

如果使用了[[]],那么就不用再使用双引号,如图:

文件操作符:
shell提供了大量的文件操作符,这样可以完成文件的各种测试工作,常用格式如下:
- test 文件操作符 文件
- [ 文件操作符 文件 ]
常用文件操作符以及含义如下:
| 文件操作符 | 含义 |
| -d file | 测试文件是否为目录 |
| -e file | 测试文件是否存在 |
| -f file | 测试文件是否为普通文件 |
| -r file | 测试文件是否是进程可读文件 |
| -s file | 测试文件长度是否不为0 |
| -w file | 测试文件是否是进程可写文件 |
| -x file | 测试文件是否是进程可执行文件 |
| -L file | 测试文件是否是符号链接文件 |
例如,测试文件夹abc以及文件aa.txt是否存在,如图:

下面测试一下文件的权限情况,如图:

逻辑运算符:
逻辑运算符用于测试多个条件是否为真或者假
逻辑运算符及其含义如下:
| 逻辑运算符 | 含义 |
| ! expression | 如果expression为真,测试结果为假 |
| expression1 -a expression2 | 如果expression1和2同时为真,那么结果为真 |
| expression1 -o expression2 | 如果expression1和2有一个为真,结果为真 |
逻辑运算符真假表
| expr1 | exp2 | !exp1 | !exp2 | expr1 -a expr2 | expr1 -o expr2 |
| 真 | 真 | 假 | 假 | 真 | 真 |
| 真 | 假 | 假 | 真 | 假 | 真 |
| 假 | 真 | 真 | 假 | 假 | 真 |
| 假 | 假 | 真 | 真 | 假 | 假 |

逻辑判断符
| 判断符 | 描述 |
| && | 逻辑和,在[[]]和(())表达式中或判断表达式是否为真时使用 |
| || | 逻辑或,在[[]]和(())表达式中 或判断表达式是否为真时使用 |


判断:
所谓判断就是对语句中的不同条件进行测试,从而执行不同的命令,例如if/else语句,如图:

上图中判断10是否小于12,如果成立,打印小于12,否则大于12,图中的中括号后如果直接加then,此时需要在中括号和then之间加分号;如果不加可以将then写在下面,如图:

exit命令一般伴随着命令结束,表示一个退出状态,如图:

上述命令中,read表示读取一个键盘输入内容,判断是否为空,如果为空,退出状态1,否则为0
注意:退出状态可以自行指定的,特定的值都有特定的用途,不要乱用

上图中,用变量$1表示用户输入的字符串,此字符串表示一个文件,然后进行判断文件是否存在,如果文件不存在,退出状态1,否则存在。
if/else也经常使用嵌套循环,如图:

上图中-z表示测试字符串是否为空,!表示非空,如果非空,那么打印不是空,再次进行判断文件是否存在,如果存在打印存在,反之不存在。
接下来看一组if/elif/else的例子,如图:

注意,在上图中,fi只需要在结尾出现一次就可以啦,其余地方不用
case结构
case命令常用于多分支语句,常根据表达式的值来选择要执行的语句

上图中变量$1表示传入的参数,在执行脚本的时候加入参数,如果匹配1那么打印值为1,以此类推,如果都不匹配,则打印*配置的内容,值未知,注意最后要以esac结尾。
下图中表示根据输入不同参数,输出不同内容,如图:

下面例子表示使用case结构配合for循环来实现清理elk索引以及数据,如下:
#!/bin/bash
: '
@function: clean elk log
@author: gongguan
@date: 2022-04-01
@说明: 本例子中只写出了2022年的,后续可以继续扩展到2023、2024年等,清理时候根据提示输入年份
和月份即可
'
cleanLog(){
for i in $(curl 'localhost:9200/_cat/indices?v' | awk '{print $3}')
do
result=$(echo $i | grep ''${month}'')
if [ -n "${result}" ];then
curl -XDELETE http://localhost:9200/${result}
fi
done
}
read -p "请输入要清楚的年份(2022/2023):" year
case $year in
2022)
read -p "请输入要清除的月份(01/02/03....):" month
case $month in
01)
cleanLog
;;
02)
cleanLog
;;
03)
cleanLog
;;
04)
cleanLog
;;
05)
cleanLog
;;
06)
cleanLog
;;
07)
cleanLog
;;
08)
cleanLog
;;
09)
cleanLog
;;
10)
cleanLog
;;
01)
cleanLog
;;
12)
cleanLog
;;
*)
echo "输入的月份不匹配"
esac
;;
*)
echo "年份不匹配,请重新输入....."
;;
esac
算术运算符
| 运算符 | 举例 | 结果 |
| +(加运算) | 3+5 | 8 |
| -(减运算) | 5-3 | 2 |
| *(乘运算) | 5*3 | 15 |
| /(除运算) | 8/2 | 4 |
| %(取余) | 8%3 | 2 |
| **(幂运算) | 5**3 | 125 |
1、在进行整数运算的时候,最终结果将是商的整数部分,忽略四舍五入,忽略小数部分,如图:

上图中,9除2等于4,8除以5等于1。
2、接下来看下取余数以及幂运算的例子,如图:

注意:在除法以及取余的过程中,除数不能为0,否则会报错。
运算表达式:
| 表达式 | 示例 |
| $(()) | $(()) |
| $[] | $[1+1] |
除了使用let,还可以通过$[]或者$(())
3、下面脚本例子通过$[] 来进行加法运算,循环执行10次,如图:

执行结果如下:

4、下面脚本例子通过$(()) 来进行加法运算,循环执行10次,如图:

结果如下:

注意:$[] 和$(()) 等效,提供同样的功能, 但是都不支持浮点运算
$(())表达式还有一个用途,三目运算:
5、下面例子,如果条件为真输出1,否则输出0,如图:

6、下面例子,如果条件为真,输出冒号前面的数字,否则输出后面的数字,如图:

注意:返回值不支持字符串
其他运算工具(let/expr/bc) :
除了 Shell 本身的算数运算表达式,还有几个命令支持复杂的算数运算:
| 命令 | 描述 |
| let | 赋值并运算,支持++、– |
| expr | 乘法*需要加反斜杠转义\* |
| bc | 计算器,支持浮点运算、 平方等 |
#let命令的例子如下:
let VAR=(1+2)*3 ; echo $VAR
x=10 ; y=5
let x++;echo $x 每执行一次 x 加 1
let y--;echo $y 每执行一次 y 减 1
let x+=2 每执行一次 x 加 2
let x-=2 每执行一次 x 减 2
#expr命令示例如下:
expr 1 \* 2 运算符两边必须有空格
expr \( 1 + 2 \) \* 2 使用双括号时要转义
#bc命令示例如下:
bc 本身就是一个计算器,可直接输入命令,进入解释器。
echo 1 + 2 |bc 将管道符前面标准输出作为 bc 的标准输入
echo "1.2+2" |bc
echo "10^10" |bc
echo 'scale=2;10/3' |bc 用 scale 保留两位小数点
由于 Shell 不支持浮点数比较,可以借助 bc 来完成需求:

上图中运算如果为真返回 1,否则返回 0
7、下面例子表示通过bc计算除法,并保留两位小数,如图:

算术复合运算符
| 运算符 | 举例 | 等价表达式 |
| += | a+=5 | a=a+5 |
| -= | a-=5 | a=a-5 |
| *= | a*=5 | a=a*5 |
| /= | a/=3 | a=a/3 |
| %= | a%=5 | a=a%5 |

Shell 括号用途总结:
| 命令 | 用途 |
| () | 用途 1:在运算中,先计算小括号里面的内容 用途 2:数组 用途 3:匹配分组 |
| (()) | 用途 1:表达式,不支持-eq 这类的运算符。不支持-a 和-o,支持<=、>=、<、>这类 比较符和&&、|| 用途 2:C 语言风格的 for(())表达式 |
| $() | 执行 Shell 命令,与反引号等效 |
| $(()) | 用途 1:简单算数运算 用途 2:支持三目运算符 $(( 表达式?数字:数字 )) |
| [] | 条件表达式,里面不支持逻辑判断符 &&、||,支持-a、-o |
| [[]] | 条件表达式,里面不支持-a 和-o,不支持<=和>=比较符,支持-eq、<、>这类比较 符。支持=~模式匹配,也可以不用双引号也不会影响原意,比[]更加通用 |
| $[] | 简单算数运算 |
| {} | 对逗号(,)和点点(…)起作用,比如 touch {1,2}创建 1 和 2 文件,touch {1..3}创建 1、2 和 3 文件 |
| ${} | 用途 1:引用变量 用途 2:字符串处理 |


