一、Shell 运算符,到底是啥?
Shell 运算符是 Shell 编程中的重要组成部分,它允许你在脚本中进行各种数学运算、逻辑判断和字符串处理。掌握 Shell 运算符,就相当于掌握了一门强大的工具,可以让你的 Shell 脚本更加灵活和高效。
二、算数运算符:基础计算的基石
在 Shell 编程中,原生 bash 并不支持直接进行数学运算 ,我们可以借助一些工具来实现这一功能,其中expr和awk就是常用的得力助手,而expr更是其中的佼佼者,最为常用。expr是一款强大的表达式计算工具,能够帮助我们轻松完成各种表达式的求值操作。
下面,我们来认识一下常见的算数运算符:
运算符 | 释义 |
+ | 两个数相加 |
- | 两个数相减,也可表示负数 |
* | 两个数相乘 |
/ | 两个数相除,得到的结果是整数部分,会舍弃小数部分 |
% | 两个数相除后的余数 |
接下来,我们通过一些实例来看看这些运算符的实际应用。
加法运算,使用expr命令来计算两个数的和:
val=`expr 3 + 5`
echo "两数之和为 : $val"
运行上述代码,你会得到输出结果:两数之和为 : 8。
减法运算:
val=`expr 9 - 4`
echo "两数之差为 : $val"
这里的输出结果是:两数之差为 : 5。
乘法运算:
val=`expr 4 \* 6`
echo "两数之积为 : $val"
注意,在expr中,乘法运算符*需要转义,用\*表示。运行后输出:两数之积为 : 24 。
除法运算:
val=`expr 10 / 2`
echo "两数之商为 : $val"
输出结果为:两数之商为 : 5。
取余运算:
val=`expr 7 % 3`
echo "两数取余结果为 : $val"
输出:两数取余结果为 : 1 。
在使用算数运算符时,有一些注意事项需要牢记。
首先,表达式和运算符之间必须要有空格 ,例如2+2是错误的写法,必须写成2 + 2,这与我们熟悉的大多数编程语言有所不同,需要特别注意。其次,完整的表达式要被反引号(` `)包含,这个反引号位于 Esc 键下边,不是常用的单引号,千万不要弄混了。
三、关系运算符:数字比较的利器
在 Shell 编程中,关系运算符就像是我们的数字比较小助手,专门用于比较两个数字的大小关系,不过要注意哦,它只支持数字的比较 ,如果是字符串,只有当字符串的值是数字时才支持。
下面来认识一下常见的关系运算符:
运算符 | 释义 |
-eq | 检测两个数是否相等,相等返回true |
-ne | 检测两个数是否不相等,不相等返回true |
-gt | 检测左边的数是否大于右边的,如果是,则返回true |
-lt | 检测左边的数是否小于右边的,如果是,则返回true |
-ge | 检测左边的数是否大于等于右边的,如果是,则返回true |
-le | 检测左边的数是否小于等于右边的,如果是,则返回true |
通常,我们会使用if语句搭配关系运算符来进行比较和判断。例如,我们想判断两个数是否相等,可以这样写:
a=10
b=15
if [ $a -eq $b ]
then
echo "$a 等于 $b"
else
echo "$a 不等于 $b"
fi
运行上述代码,输出结果是:10 不等于 15。
再比如,判断一个数是否大于另一个数:
a=20
b=10
if [ $a -gt $b ]
then
echo "$a 大于 $b"
else
echo "$a 不大于 $b"
fi
这里的输出结果为:20 大于 10 。
需要特别注意的是,在使用关系运算符时,条件表达式一定要放在方括号[ ]之间 ,并且方括号与表达式之间要有空格,这是很多新手容易犯错的地方,例如[a -gt b]是错误的,必须写成[ $a -gt $b ] ,大家一定要牢记哦!
四、布尔与逻辑运算符:复杂条件判断的关键
(1)布尔运算符
在 Shell 编程中,布尔运算符为我们提供了一种强大的逻辑判断能力,能帮助我们处理复杂的条件判断。常见的布尔运算符有!(非运算)、-o(或运算)、-a(与运算) 。
运算符 | 释义 |
! | 非运算,表达式为 true 则返回 false,否则返回 true。 |
-o | 或运算,有一个表达式为 true 则返回 true。 |
-a | 与运算,两个表达式都为 true 才返回 true。 |
!运算符表示非运算,当表达式为true时,经过!运算后返回false,反之,当表达式为false时,返回true。比如我们要判断一个文件是否不存在,可以这样使用:
if [ ! -e file.txt ]; then
echo "文件 file.txt 不存在"
fi
这里-e是文件测试运算符,用于检测文件是否存在,! -e file.txt就表示文件file.txt不存在的情况。
-o运算符实现或运算,只要有一个表达式为true,整个表达式就返回true。例如,我们要判断两个数中是否有一个大于 10:
a=5
b=15
if [ $a -gt 10 -o $b -gt 10 ]; then
echo "a 或 b 大于10"
fi
在这个例子中,因为b大于 10,所以整个表达式为true,会输出a 或 b 大于10
-a运算符代表与运算,只有当两个表达式都为true时,整个表达式才返回true。比如判断一个数是否大于 5 且小于 15:
num=8
if [ $num -gt 5 -a $num -lt 15 ]; then
echo "num 大于5且小于15"
fi
由于num的值满足大于 5 且小于 15,所以表达式为true,会输出相应的信息。
在使用布尔运算符时,要特别注意表达式与运算符之间必须要有空格 ,这是很多新手容易忽略的细节。例如[!-e file.txt]是错误的,必须写成[ ! -e file.txt ] ,否则会导致语法错误,大家一定要牢记这个规则哦!
(2)逻辑运算符
逻辑运算符在 Shell 脚本中起着至关重要的作用,它主要用于控制脚本的执行流程,根据不同的条件来决定后续命令的执行。其中,最常用的逻辑运算符是&&(逻辑与)和||(逻辑或)。
运算符 | 释义 |
&& | 逻辑的 AND |
|| | 逻辑的 OR |
&&运算符表示逻辑与,只有当&&前面的命令执行成功(返回值为 0,在 Shell 中,命令执行成功通常返回 0,失败返回非 0 值 )时,才会执行后面的命令。我们来看一个实际的例子,假设我们要先创建一个目录,然后在这个目录下创建一个文件:
mkdir new_dir && touch new_dir/new_file.txt
在这个命令中,如果mkdir new_dir命令执行成功,也就是成功创建了new_dir目录,那么才会执行touch new_dir/new_file.txt命令,在new_dir目录下创建new_file.txt文件。如果mkdir new_dir命令执行失败,比如目录已经存在或者没有权限创建目录,那么后面的touch命令就不会执行。
||运算符表示逻辑或,当||前面的命令执行失败(返回值非 0)时,就会执行后面的命令。例如,我们尝试执行一个可能不存在的命令,如果执行失败就输出提示信息:
nonexistent_command || echo "命令执行失败,可能该命令不存在"
在这个例子中,如果nonexistent_command命令执行失败(因为这个命令很可能不存在),就会执行echo命令,输出提示信息。如果nonexistent_command命令执行成功(假设这个命令实际上是存在的),那么echo命令就不会执行。
通过合理使用&&和||逻辑运算符,我们可以根据命令的执行结果来灵活控制脚本的流程,实现更加智能化和自动化的脚本编写 。无论是在系统管理、自动化部署还是数据处理等场景中,逻辑运算符都发挥着不可或缺的作用,掌握它们的使用方法是成为一名优秀 Shell 脚本编写者的必备技能。
五、字符串运算符:文本处理的好帮手
在 Shell 编程中,字符串运算符是处理文本的得力工具,它可以帮助我们进行字符串的比较、长度判断等操作 ,在文本处理和脚本编写中发挥着重要作用。
下面来认识一下常见的字符串运算符:
运算符 | 释义 |
= | 检测两个字符串是否相等,相等返回true |
!= | 检测两个字符串是否不相等,不相等返回true |
-z | 检测字符串长度是否为 0,为 0 返回true |
-n | 检测字符串长度是否不为 0,不为 0返回true |
例如,我们要判断两个字符串是否相等(=),可以这样写:
str1="hello"
str2="world"
if [ $str1 = $str2 ]
then
echo "$str1 等于 $str2"
else
echo "$str1 不等于 $str2"
fi
运行上述代码,输出结果是:hello 不等于 world。
再比如,判断一个字符串是否为空(!=):
str=""
if [ -z $str ]
then
echo "字符串为空"
else
echo "字符串不为空"
fi
这里的输出结果为:字符串为空 。
需要注意的是,在使用字符串运算符时,条件表达式同样要放在方括号[ ]之间 ,并且方括号与表达式之间要有空格。同时,字符串运算符对大小写敏感,比如"Hello"和"hello"会被视为不相等的字符串 ,在编写脚本时一定要注意这一点哦!
六、文件测试运算符:文件属性检测的工具
在 Unix/Linux 系统中,文件测试运算符是非常重要的一类运算符,它就像是文件的 “体检医生”,专门用于检测文件的各种属性 ,在编写文件操作相关的脚本时经常会用到。
常见的文件测试运算符有:
运算符 | 释义 |
-r | 检测文件是否可读,如果当前用户对该文件有读权限,则返回true |
-w | 检测文件是否可写,如果当前用户对该文件有写权限,则返回true |
-x | 检测文件是否可执行,如果当前用户对该文件有执行权限,则返回true |
-f | 检测文件是否是普通文件(既不是目录,也不是设备文件等) ,如果是普通文件,则返回true |
-d | 检测文件是否是目录,如果是目录,则返回true |
-r:检测文件是否可读,如果当前用户对该文件有读权限,则返回true 。比如在一个备份脚本中,我们需要读取配置文件的内容,如果配置文件不可读,备份操作可能就无法正确执行,这时就可以用-r来检测。
-w:检测文件是否可写,如果当前用户对该文件有写权限,则返回true 。假设我们要创建一个日志文件并写入数据,如果文件不可写,那么日志记录就无法完成,通过-w可以提前判断。
-x:检测文件是否可执行,如果当前用户对该文件有执行权限,则返回true 。当我们编写一个可执行脚本,需要确保脚本有可执行权限才能正常运行,就可以用-x来检查。
-f:检测文件是否是普通文件(既不是目录,也不是设备文件等) ,如果是普通文件,则返回true。在处理文件时,我们需要明确文件的类型,比如在批量处理文件时,可能只处理普通文件,这时-f就能派上用场。
-d:检测文件是否是目录,如果是目录,则返回true 。在遍历目录结构或者创建目录时,我们需要判断某个路径是否是目录,-d就可以帮助我们做出判断。
例如,我们要判断一个文件是否可读:
file="test.txt"
if [ -r $file ]
then
echo "$file 可读"
else
echo "$file 不可读"
fi
如果test.txt文件存在且当前用户有读权限,就会输出test.txt 可读,否则输出test.txt 不可读。
再比如,判断一个路径是否是目录:
dir="/home/user/dir"
if [ -d $dir ]
then
echo "$dir 是目录"
else
echo "$dir 不是目录"
fi
如果/home/user/dir是一个目录,就会输出/home/user/dir 是目录,否则输出/home/user/dir 不是目录。
文件测试运算符在文件操作脚本中起着关键作用,通过合理使用它们,可以让我们的脚本更加健壮和智能 ,避免在处理文件时出现不必要的错误。在使用文件测试运算符时,同样要注意条件表达式放在方括号[ ]之间,并且方括号与表达式之间要有空格 哦!
七、实战演练:运算符的综合运用
为了让大家更深入地理解 Shell 运算符的实际应用,我们来看一个服务器资源监控脚本的例子。这个脚本可以实时监控服务器的 CPU 使用率、内存使用量和文件系统空间 ,并根据预设的阈值进行相应的操作。
#!/bin/bash
# 获取CPU使用率
cpu_usage=$(top -bn1 | grep '%Cpu' | awk '{print $2}')
# 获取内存使用量
mem_total=$(free | awk '/Mem/{print $2}')
mem_used=$(free | awk '/Mem/{print $3}')
mem_usage=$(echo "scale=2; $mem_used / $mem_total * 100" | bc)
# 获取文件系统空间
fs_usage=$(df -h / | awk 'NR==2{print $5}' | sed 's/%//')
# 设置阈值
cpu_threshold=80
mem_threshold=80
fs_threshold=90
# 判断CPU使用率是否超过阈值
if (( $(echo "$cpu_usage > $cpu_threshold" | bc -l) )); then
echo "CPU使用率过高: $cpu_usage%"
# 这里可以添加发送警报邮件的命令,例如使用mail命令
# mail -s "CPU使用率过高" admin@example.com <<< "当前CPU使用率为: $cpu_usage%"
fi
# 判断内存使用量是否超过阈值
if (( $(echo "$mem_usage > $mem_threshold" | bc -l) )); then
echo "内存使用量过高: $mem_usage%"
# 这里可以添加清理临时文件等操作的命令
# rm -rf /tmp/*
fi
# 判断文件系统空间是否超过阈值
if (( $(echo "$fs_usage > $fs_threshold" | bc -l) )); then
echo "文件系统空间不足: $fs_usage%"
# 这里可以添加删除不必要文件或扩容文件系统的提示或操作命令
echo "请及时清理文件或扩容文件系统"
fi
在这个脚本中:
1. 算数运算符:使用bc命令结合算数运算符进行了内存使用率的计算,如echo "scale=2; $mem_used / $mem_total * 100" | bc ,这里用到了除法(/)和乘法(*)运算符。
2. 关系运算符:通过(( $(echo "$cpu_usage > $cpu_threshold" | bc -l) ))这样的表达式来判断 CPU 使用率是否超过阈值,这里使用了大于(>)关系运算符,同理用于内存使用量和文件系统空间的判断 。
3. 逻辑运算符:在判断条件中,虽然没有显式出现逻辑运算符,但在实际应用中,可以通过逻辑运算符将多个条件组合起来,例如if (( $(echo "$cpu_usage > $cpu_threshold" | bc -l) )) && (( $(echo "$mem_usage > $mem_threshold" | bc -l) )); then ,表示当 CPU 使用率和内存使用量都超过阈值时执行相应操作 。
通过这个实战案例,我们可以看到不同类型的 Shell 运算符如何协同工作,帮助我们实现复杂的系统监控和管理任务。在实际编写脚本时,大家可以根据具体需求灵活运用各种运算符,让脚本更加智能和高效 。
八、总结与展望
在 Shell 编程的世界里,我们探索了多种基本运算符,它们就像构建脚本大厦的基石,每一种都有着独特的作用。算数运算符帮助我们进行基础的数学计算,虽然原生 bash 需要借助工具,但expr等工具让我们能够顺利完成各种数值操作;关系运算符专注于数字的比较,为我们的条件判断提供了重要依据;布尔与逻辑运算符则是处理复杂条件的关键,它们能够将多个条件巧妙地组合起来,控制脚本的执行流程;字符串运算符在文本处理中发挥着重要作用,让我们能够对字符串进行比较、长度判断等操作;文件测试运算符就像是文件的守护者,帮助我们检测文件的各种属性,确保文件操作的安全和正确。
通过服务器资源监控脚本这个实战案例,我们看到了这些运算符如何协同工作,实现复杂的系统管理任务。在实际的编程过程中,大家一定要多动手练习,只有通过不断的实践,才能真正掌握这些运算符的使用技巧 。同时,也要注意运算符使用中的一些细节,比如表达式与运算符之间的空格、条件表达式的括号使用等,这些看似微小的细节,往往会影响脚本的正确性。