1.使用if-then语句
最简单的结构化语句是if-then语句,其语法格式如下:
1if 命令 2then 3 命令 4fi
if-then语句另一种的写法:
1if 命令; then 2命令 3fi
执行流程:
(1).如果if后面那个命令的退出状态码为0,则then之后命令会被执行;
(2).如果if后面那个命令的退出状态码是其他值,则then之后命令不会被执行,bash shell会继续执行脚本中的下一个命令;
(3).fi语句用来表示if-then语句到此结束;
示例如下:
1#!/bin/bash 2# testing the if statement 3 4if pwd 5then 6 echo "It Worked" 7fi 8 9# 结果 10[njust@njust tutorials]$ ./curry.sh 11/home/njust/tutorials 12It Worked
bash shell会跳过then部分的echo语句,同时运行if语句中的那个错误命令所生成的错误消息依然会显示在脚本的输出中。错误示例如下:
1#!/bin/bash 2 3if notCommand 4then 5 echo "It worked" 6fi 7 8echo "skipped 'then' statement" 9 10# 结果 11[njust@njust tutorials]$ ./durant.sh 12./durant.sh:行3: notCommand: 未找到命令 13skipped 'then' statement
在then部分,可以使用不止一条命令。bash shell会将这些命令当成一个语句块。示例如下:
1#!/bin/bash 2 3testuser=njust 4 5if grep $testuser /etc/passwd # grep命令在/etc/passwd文件中查找某个用户当前是否在系统上使用 6then 7echo This is my first command 8echo This is my second command 9echo I can even put in other commands besides echo: 10ls -l /home/$testuser/.b* # 显示一些文本信息并列出该用户HOME目录的bash文件 11fi 12 13# 结果 14This is my first command 15This is my second command 16I can even put in other commands besides echo: 17-rw-------. 1 njust njust 6013 3月 12 10:50 /home/njust/.bash_history 18-rw-r--r--. 1 njust njust 18 8月 8 2019 /home/njust/.bash_logout 19-rw-r--r--. 1 njust njust 193 8月 8 2019 /home/njust/.bash_profile 20-rw-r--r--. 1 njust njust 231 8月 8 2019 /home/njust/.bashrc
2.if-then-else语句
if-then语句中,不管命令是否成功执行,都只有一种选择。如果if后面的命令返回一个非零退出状态码,bash shell就会继续执行脚本中的下一条命令。if-then-else语句就是解决返回非零退出状态码的情况。语法格式:
1if 命令 2then 3 命令 4else 5 命令 6fi
执行流程:
(1).当if语句中的命令返回状态码为0时,then部分的命令会被执行;
(2).当if语句中的命令返回状态码非0时,else部分的命令会被执行;
示例如下:
1#!/bin/bash 2 3testuser=njuster 4 5if grep $testuser /etc/passwd 6then 7echo This is my first command 8echo This is my second command 9echo I can even put in other commands besides echo: 10ls -l /home/$testuser/.b* 11else 12echo The user $testuser does not exist on this system. 13echo 14fi 15# 结果 16[njust@njust tutorials]$ ./harden.sh 17The user njuster does not exist on this system.
3.嵌套if-then
可以使用elif代替多个if-then语句。具体示例如下:
1#!/bin/bash 2 3testuser=njuster 4 5if grep $testuser /etc/passwd 6then 7echo The user $testuser exists on this system. 8elif ls -d /home/$testuser 9then 10echo The user $testuser does not exist on this system. 11echo However, $testuser has a directory. 12else 13echo The user $testuser does not exist on this system. 14echo And,$testuser does not have a directory. 15fi 16 17# 结果 18[njust@njust tutorials]$ ./harden.sh 19ls: 无法访问/home/njuster: 没有那个文件或目录 20The user njuster does not exist on this system. 21And,njuster does not have a directory.
可以继续将多个elif命令串起来,形成一个大的if-then-elif嵌套组合。具体形式如下:
1if 命令 2then 3命令 4elif 命令 5then 6命令 7elif 命令 8then 9命令 10...... 11fi
尽管elif语句的代码看起来很清晰,但脚本的逻辑不好。后面会使用case命令代替if-then语句的大量嵌套。
4.test命令
目前为止,if语句中看到的都是普通的shell命令。由于if-then语句不能测试命令退出状态码之外的条件。因此,bash shell中有个工具可以帮你通过if-then语句测试其他条件。test命令提供了在if-then语句中测试不同条件的路径。如果test命令中列出的条件成立,test命令就会退出并返回退出状态码;如果条件不成立,test命令就会退出并返回非零的退出状态码。于是,if-then语句就不会被执行。语法格式如下:
1test 测试条件
测试条件是test命令要测试的一系列参数和值。当用在if-then语句中时,形式如下所示:
1if test 测试条件 2then 3命令 4fi
如果不写test语句中的测试条件,它会以非零的退出状态码退出,并执行else语句块,示例如下:
1#!/bin/bash 2 3# Testing the test command 4 5if test 6then 7echo No expression returns a ture 8else 9echo No expression returns a false 10fi 11 12# 结果 13[njust@njust tutorials]$ ./james.sh 14No expression returns a false
当加入一个条件时,test命令会测试该条件。例如,可以使用test命令确定变量中是否有内容,如下所示:
1#!/bin/bash 2 3my_variable="Curry" 4 5if test $my_variable 6then 7echo The $my_variable expression returns a true. 8else 9echo The $my_variable expression returns a false. 10fi 11 12# 结果 13[njust@njust tutorials]$ ./tlu.sh 14The Curry expression returns a true.
bash shell 提供了另一种条件测试方法。无需在if-then语句中声明test命令。语法格式如下:
1if [ 测试条件 ] 2then 3命令 4fi
方括号定义了测试条件。注意:测试条件的左右两侧都要留一个空格,否则会出错。test命令可以判断三类条件:(1).数值比较(2).字符串比较(3).文件比较
4.1 数值比较
test命令最常见于对两个数值进行比较。测试两个值时可以使用的条件参数如下所示:
1比较 描述 2num1 -eq num2 等于 3num1 -ge num2 大于或等于 4num1 -gt num2 大于 5num1 -le num2 小于或等于 6num1 -lt num2 小于 7num1 -ne num2 不等于
数值比较测试示例:
1#!/bin/bash 2 3# using numeric test evaluations 4 5value1=10 6value2=20 7 8if [ $value1 -gt 5 ] 9then 10echo The test value $value1 is greater than 5. 11fi 12 13if [ $value1 -eq $value2 ] 14then 15echo The values are equal. 16else 17echo The values are different. 18fi 19 20# 结果 21[njust@njust tutorials]$ ./num.sh 22The test value 10 is greater than 5. 23The values are different.
但是,涉及浮动值时,数值条件测试会有一个限制。原因:bash shell只能处理整数,如果你只是要通过echo语句来显示这个结果,那没问题。示例如下:
1#!/bin/bash 2 3value=3.1415926 4 5echo The test value is $value. 6 7if [ $value1 -gt 5 ] 8then 9echo The test value $value is greater than 5. 10fi 11 12# 结果 13[njust@njust tutorials]$ ./num2.sh 14The test value is 3.1415926. 15./num2.sh: 第 7 行:[: -gt: 期待一元表达式
4.2 字符串比较
条件测试还允许比较字符串的值。测试两个字符串之间的比较语法如下:
1比较 描述 2str1 = str2 检查两者是否相同 3str1 != str2 检查两者是否不同 4str1 < str2 检查str1是否小于str2 5str1 > str2 检查str1是否大于str2 6-n str1 检查str1的长度是否非0 7-z str1 检查str1的长度是否为0
比较字符串的相等性时,比较测试会将所有的标点和大小写情况都考虑在内。字符串的相等性示例如下:
1#!/bin/bash 2 3testuser=njust 4 5if [ $USER = $testuser ] 6then 7echo welcome $testuser 8fi 9 10# 结果 11[njust@njust tutorials]$ ./str1.sh 12welcome njust 检查str1的长度是否为0
字符串的不等条件判断示例如下:
1#!/bin/bash 2 3testuser=baduser 4 5if [ $USER != $testuser ] 6then 7echo This is not $testuser 8else 9echo welcome $testuser 10fi 11 12# 结果 13[njust@njust tutorials]$ ./str1.sh 14This is not baduser
字符串顺序:要测试一个字符串是否比另一个字符串大或小时,经常要考虑下面两个问题:
a.大于号或小于号必须转义,否则shell会把它们当作重定向符号,把字符串值当作文件名;
b.大于和小于顺序和sort命令所采用的不同;
字符串比较是常出现的错误示例及解决方法:
1#!/bin/bash 2 3value1=baseball 4value2=football 5 6if [ $value1 > $value2 ] 7then 8echo $value1 is greater than $value2. 9else 10echo $value1 is less than $value2. 11fi 12 13# 结果 14[njust@njust tutorials]$ ./str2.sh 15baseball is greater than football. 16 17# 解决方法:对大于号进行转义 18#!/bin/bash 19 20value1=baseball 21value2=football 22 23if [ $value1 \> $value2 ] 24then 25echo $value1 is greater than $value2. 26else 27echo $value1 is less than $value2. 28fi 29 30# 结果 31[njust@njust tutorials]$ ./str2.sh 32baseball is less than football.
原因分析:脚本中的大于号被解释成了输出重定向,因此创建了一个名为football的文件。由于重定向的顺利执行,test命令返回了退出状态码0,if语句误以为所有命令都已经执行完成了。
1[njust@njust tutorials]$ ls -l football 2-rw-rw-r--. 1 njust njust 0 3月 17 14:33 football
第二个问题一般出现在经常处理大小写的场合。sort命令处理大写字母的方法刚好和test命令相反。具体原因:比较测试中使用的是标准的ASCII顺序,根据每个字符的ASCII数值来决定排序结果。sort命令使用的是系统的本地化语言设置中定义的排序顺序。具体示例如下:
1#!/bin/bash 2 3value1=Curry 4value2=curry 5 6if [ $value1 \> $value2 ] 7then 8echo $value1 is greater than $value2. 9else 10echo $value1 is less than $value2. 11fi 12 13# 结果 14[njust@njust tutorials]$ ./str2.sh 15Curry is less than curry. 16 17######## sort命令 ######### 18[njust@njust tutorials]$ cat testfile 19Curry 20curry 21 22# 结果 23[njust@njust tutorials]$ sort testfile 24curry 25Curry
字符串大小:-n和-z可以检查一个变量中是否为空。具体示例如下:
1#!/bin/bash 2 3val1=testing 4val2="" 5 6if [ -n $val1 ] 7then 8echo "The string '$val1' is not empty." 9else 10echo "The string '$val1' is empty." 11fi 12 13if [ -z $val2 ] 14then 15echo "The string '$val2' is empty." 16else 17echo "The string '$val2' is not empty." 18fi 19 20if [ -z $val3 ] 21then 22echo "The string '$val3' is empty." 23else 24echo "The string '$val3' is not empty." 25fi 26 27# 结果 28[njust@njust tutorials]$ ./str3.sh 29The string 'testing' is not empty. 30The string '' is empty. 31The string '' is empty.
4.3 文件比较
文件比较可能是shell编程中最强大、用的最多的比较形式。它允许你测试Linux文件系统上文件和目录的状态。文件比较功能语法如下:
1比较 描述 2-d file 检查file是否存在并是一个目录 3-e file 检查file是否存在 4-f file 检查file是否存在并是一个文件 5-r file 检查file是否存在并可读 6-s file 检查file是否存在并非空 7-w file 检查file是否存在并可写 8-x file 检查file是否存在并可执行 9-O file 检查file是否存在并属于当前用户所有 10-G file 检查file是否存在并且默认组与当前组相同 11file1 -nt file2 检查file1是否比file2新 12file1 -ot file2 检查file1是否比file2旧
检查目录:-d测试会检查指定的目录是否存在于系统中。一般用于将文件写入目录或准备切换到某个目录中。
1#!/bin/bash 2 3dst_dir=/home/curry 4 5if [ -d $dst_dir ] 6then 7echo "The $dst_dir directory exists" 8cd $dst_dir 9ls 10else 11echo "The $dst_dir directory does not exists" 12fi 13 14# 结果 15[njust@njust tutorials]$ ./file1.sh 16The /home/curry directory does not exists
检查对象是否存在:-e允许你的脚本代码在使用文件或目录前先检查它们是否存在。
1#!/bin/bash 2 3location=$HOME 4 5file_name="sentinel" 6mid_path="tutorials" 7 8if [ -e $location ] 9then 10echo "OK on the $location directory." 11echo "Now checking on the file, $file_name." 12if [ -e $location/$mid_path/$file_name ] 13then 14 echo "OK on the filename" 15 echo "Updating Current Date..." 16 date >> $location/$mid_path/$file_name 17else 18 echo "File does not exist" 19 echo "Nothing to update" 20fi 21 22else 23echo "The $location directory does not exist." 24echo "Nothing to update" 25fi 26 27# 结果 28[njust@njust tutorials]$ ./file2.sh 29OK on the /home/njust directory. 30Now checking on the file, sentinel. 31File does not exist 32Nothing to update 33 34[njust@njust tutorials]$ ./file2.sh 35OK on the /home/njust directory. 36Now checking on the file, sentinel. 37OK on the filename 38Updating Current Date...
检查文件:-e可用于文件和目录。要确定指定对象为文件,必须用-f。示例如下:
1#!/bin/bash 2 3item_name=$HOME 4 5echo 6echo "The item being checked: $item_name" 7echo 8 9if [ -e $item_name ] 10then 11echo "The item, $item_name, does exist." 12echo "But is it a file?" 13echo 14 15if [ -f $item_name ] 16then 17 echo "Yes, $item_name is a file." 18else 19 echo "No, $item_name is not a file." 20fi 21else 22echo "The item, $item_name, does not exist." 23echo "Nothing to update" 24fi 25 26# 结果 27[njust@njust tutorials]$ ./file3.sh 28 29The item being checked: /home/njust 30 31The item, /home/njust, does exist. 32But is it a file? 33 34No, /home/njust is not a file.
对上述程序进行小修改,可以观察出结果的不同:
1#!/bin/bash 2 3item_name=$HOME/tutorials/sentinel # 注意此句!!! 4 5echo 6echo "The item being checked: $item_name" 7echo 8 9if [ -e $item_name ] 10then 11echo "The item, $item_name, does exist." 12echo "But is it a file?" 13echo 14 15if [ -f $item_name ] 16then 17 echo "Yes, $item_name is a file." 18else 19 echo "No, $item_name is not a file." 20fi 21else 22echo "The item, $item_name, does not exist." 23echo "Nothing to update" 24fi 25 26# 结果 27[njust@njust tutorials]$ ./file3.sh 28 29The item being checked: /home/njust/tutorials/sentinel 30 31The item, /home/njust/tutorials/sentinel, does exist. 32But is it a file? 33 34Yes, /home/njust/tutorials/sentinel is a file.
检查是否可读:在尝试从文件中读取数据之前,最好先测试一下文件是否可读。可以使用-r比较测试。示例如下:
1#!/bin/bash 2 3pwfile=/etc/shadow 4 5if [ -f $pwfile ] 6then 7if [ -r $pwfile ] 8then 9 tail $pwfile 10else 11 echo "Sorry,I am unable to read the $pwfile file." 12fi 13else 14"Sorry, the file $pwfile does not exist" 15fi 16 17# 结果 18njust@njust tutorials]$ ./file4.sh 19Sorry,I am unable to read the /etc/shadow file.
检查空文件:用-s比较来检查文件是否为空,尤其是在不想删除非空文件的时候。注意:当-s比较成功时,说明文件中有数据。具体示例如下所示:
1#!/bin/bash 2 3file_name=$HOME/tutorials/sentinel 4 5if [ -f $file_name ] 6then 7if [ -s $file_name ] 8then 9 echo "The $file_name file exists and has data in it." 10 echo "Will not remove this file." 11else 12 echo "The $file_name file exists, but is empty." 13 echo "Deleting empty file." 14 rm $file_name 15fi 16 17else 18echo "File,$file_name, does not exist." 19fi 20 21# 结果 22[njust@njust tutorials]$ ./file5.sh 23The /home/njust/tutorials/sentinel file exists and has data in it. 24Will not remove this file.
检查文件是否可写:-w比较会判断你对文件是否有写的权限。具体示例如下所示:
1#!/bin/bash 2 3item_name=$HOME/tutorials/sentinel 4 5echo 6echo "The item being checked: $item_name." 7echo 8 9if [ -e $item_name ] 10then 11echo "The item, $item_name, does exist." 12echo "But is it a file?" 13echo 14if [ -f $item_name ] 15then 16 echo "Yes, $item_name is a file." 17 echo "But is it writable?" 18 if [ -w $item_name ] 19 then 20 echo "Writing current time to $item_name." 21 date +%H%M >> $item_name 22 else 23 echo "Unable to write to $item_name." 24 fi 25else 26 echo "No, $item_name is not a file." 27fi 28else 29echo "The item,$item_name, does not exist." 30echo "Nothing to update." 31fi 32 33# 结果 34[njust@njust tutorials]$ ./file6.sh 35 36The item being checked: /home/njust/tutorials/sentinel. 37 38The item, /home/njust/tutorials/sentinel, does exist. 39But is it a file? 40 41Yes, /home/njust/tutorials/sentinel is a file. 42But is it writable? 43Writing current time to /home/njust/tutorials/sentinel.
检查文件是否可执行:-x比较是判断特定文件是否有执行权限的一个简单方法。如果你需要在shell脚本中运行大量脚本,它就能发挥作用。
1#!/bin/bash 2 3if [ -x file5.sh ] 4then 5echo "You can run the script: " 6./file5.sh 7else 8echo "Sorry, you are unable to execute the script" 9fi 10 11# 结果 12[njust@njust tutorials]$ ./file7.sh 13You can run the script: 14The /home/njust/tutorials/sentinel file exists and has data in it. 15Will not remove this file.
检查所属关系:-O可以测试你是否是文件的拥有者。具体示例如下所示:
1#!/bin/bash 2 3if [ -O /etc/passwd ] 4then 5echo "You are the owner of the /etc/passwd file." 6else 7echo "Sorry,you are not the owner of the /etc/passwd file." 8fi 9 10# 结果 11[njust@njust tutorials]$ ./file8.sh 12Sorry,you are not the owner of the /etc/passwd file.
检查默认属组关系:-G比较会检查文件的默认组。如果它匹配了用户的默认组,则测试成功。-G比较只会检查默认组而非用户所属的所有组。
1#!/bin/bash 2 3if [ -G $HOME/tutorials/sentinel ] 4then 5echo "You are in the same group as the file." 6else 7echo "The file is not owned by your group." 8fi 9 10# 结果 11[njust@njust tutorials]$ ./file9.sh 12You are in the same group as the file.
检查文件日期:主要用于对两个文件的创建日期进行比较。通常用于编写软件安装脚本时非常有用。-nt比较会判定一个文件是否比另一个文件新;如果文件较新,则它的文件创建日期更近。-ot比较会判断一个文件是否比另一文件旧。如果文件较旧,意味着它的创建日期更早。
1#!/bin/bash 2 3if [ file9.sh -nt file1.sh ] 4then 5echo "The file9 file is newer than file1." 6else 7echo "The file1 file is newer than file9." 8fi 9 10if [ file7.sh -ot file9.sh ] 11then 12echo "The file7 file is older than the file9 file." 13fi 14 15# 结果 16[njust@njust tutorials]$ ./file10.sh 17The file9 file is newer than file1. 18The file7 file is older than the file9 file.
注意:使用-nt或-ot比较文件之前,必须先确认文件是存在的。因为-nt或-ot都不会先检查文件是否存在!
1#!/bin/bash 2 3if [ file9.sh -nt file1.sh ] 4then 5echo "The file9 file is newer than file1." 6else 7echo "The file1 file is newer than file9." 8fi 9 10if [ file7.sh -ot file9.sh ] 11then 12echo "The file7 file is older than the file9 file." 13fi 14 15# 错误的结果,因为badfile1和badfile2文件根本就不存在! 16[njust@njust tutorials]$ ./error.sh 17The badfile2 file is newer than badfile1.
5.复合条件测试
if-then语句允许你使用布尔逻辑进行组合测试。有两种布尔运算符可以使用:(1).[ 条件1 ] && [ 条件2 ](2).[ 条件1 ] || [ 条件2 ]复合条件测试案例如下所示:
1#!/bin/bash 2 3if [ -d $HOME ] && [ -w $HOME/tutorials/sentinel ] 4then 5echo "The file exists and you can write to it" 6else 7echo "I cannot write to the file" 8fi 9 10# 结果 11[njust@njust tutorials]$ ./file11.sh 12The file exists and you can write to it
6.if-then的高级特性
bash shell提供了两种可在if-then语句中使用的高级特性:
(1).用于数学表达式的双括号;(2).用于高级字符串处理功能的双方括号;
6.1 使用双括号
双括号命令允许你在比较的过程中使用高级数学表达式。test命令只能在比较的过程中使用简单的算术操作。双括号提供了更多的数学符号,双括号命令的格式如下:
1(( 表达式 ))
其中,表达式可以是任意的数学赋值或比较表达式。双括号命令符号如下所示:
1符号 说明 2val++ 后置加加 3val-- 后置减减 4++val 前置加加 5--val 前置减减 6! 取反 7~ 按位取反 8** 幂运算 9<< 左移 10>> 右移 11& 按位与 12| 按位或 13&& 逻辑与 14|| 逻辑或
可以在if语句中使用双括号命令,也可以在脚本中的普通命令里使用来赋值。示例如下所示:
1#!/bin/bash 2 3val1=10 4if (( $val1 ** 2 > 90 )) 5then 6(( val2 = $val1 ** 2 )) 7echo "The square of $val1 is $val2" 8fi 9 10# 结果 11[njust@njust tutorials]$ ./file12.sh 12The square of 10 is 100
6.2 使用双方括号
双方括号命令提供了针对字符串比较的高级特性。双方括号的语法格式如下:
1[[ 表达式 ]]
注意:双方括号中的表达式使用了test命令中采用的标准字符串比较,但它额外还提供了test命令不具有的特性即模式匹配。同时,值得注意的是并不是所有的shell等支持方双括号。
1#!/bin/bash 2 3if [[ $USER == n* ]] 4then 5echo "Hello $USER" 6else 7echo "Sorry, I do not know you" 8fi 9 10# 结果 11[njust@njust tutorials]$ ./file13.sh 12Hello njust
7.case命令
使用case命令可以有效的减少使用if-then-else语句的出现次数,简化代码结构。case命令的语法结构如下所示:
1case 变量 in 2变量可能取值1 | 变量可能取值2) 命令1;; 3变量可能取值3) 命令2;; 4*) default 命令3;; 5esac
case命令的具体示例如下所示:
1#!/bin/bash 2 3case $USER in 4njust | bar) 5echo "Welcome, $USER" 6echo "Please enjoy your visit";; 7testing) 8echo "Special testing account";; 9jessica) 10echo "Do not forget to log off when you're done.";; 11*) 12echo "Sorry,you are not allowed here";; 13esac 14 15# 结果 16[njust@njust tutorials]$ ./case.sh 17Welcome, njust 18Please enjoy your visit
8.相关资料
[1] https://github.com/cdlwhm1217096231/Linux/tree/master/Shell%E8%84%9A%E6%9C%AC%E7%BC%96%E7%A8%8B