分支循环是编程语言重要结构,它使得计算机源源不断地给搬砖。Shell 中也有对应语法支持。

在分支循环结构中,判断条件十分重要,在 Shell 中可以用 test 命令来判断条件。

1. test 命令

test 在 Shell 用于测试判断,如其名字所示,它可以进行一些测试,如:

  • 两个字符串是否相等
  • 给定路径是否存在
  • 路径是否有各种权限
  • ……

语法如下:

test condition
test $a -eq 5

判断为逻辑真,返回 0,判断值为假返回值 1。返回值不能用 e=$(test $a -eq 5) 来获取,这样运算后 e 是空。而要用 $? 的方式来获取。$? 用于获取上一条命令的返回值。

test 1 -eq 2
echo $? # output 1, which means false
test 1 -eq 1
echo $? # output 0, which means true

test 的返回值可以作为条件判断(如 if else)的条件:

if test "${a}" -eq 5; then echo $a; fi

test 命令也可以用单中括号([])来代替,只是使用单中括号时候,需要注意在中括号和条件之间必须有空格( )。

if [ -e ex ]; then echo "exist ex"; else echo "not exist ex"; fi
if test -e ex; then echo "exist ex"; else echo "not exist ex"; fi

1.1 路径判断

Linux 中文件不一定有扩展名,文件和文件夹的名字没有区别。

函数意义
-e路径存在(文件或文件夹)则返回 true,否则 false,e 是 exist 的意思
-d路径存在且是文件夹则返回 true,否则 false,d 是 directory 的意思
-f路径存在且是文件则返回 true,否则 false,f 是 file 的意思
-n路径存在且大小不为零则返回 true,否则 false,n 是 nonzero 的意思
-z路径存在且大小为零则返回 true,否则 false,z 是 zero 的意思
-L/-h路径存在且是链接则返回 true,否则 false,L 是 link 的意思
-r路径存在且有 read 权限则返回 true,否则 false,r 是 read 的意思
-w路径存在且有 write 权限则返回 true,否则 false,w 是 write 的意思
-x路径存在且有 execute 权限则返回 true,否则 false,x 是 execute 的意思
if [ -e $a ]; then echo "exist $a"; fi
if [ -d $a ]; then echo "exist directory $a"; fi
if [ -f $a ]; then echo "exist file $a"; fi
if [ -n $a ]; then echo "$a is not None"; fi
if [ -z $a ]; then echo "$a is  None"; fi
if [ -L $a ]; then echo "exist link $a"; fi
if [ -r $a ]; then echo "$a has read access"; fi
if [ -w $a ]; then echo "$a has write access"; fi
if [ -x $a ]; then echo "$a has execute access"; fi

1.2 文件比较

test 命令也可以用于两个文件的比较。

函数意义
patha -nt pathbpatha 修改时间比 pathb 新则返回 true,否则 false,nt 是 newer than 的意思
patha -ot pathbpatha 修改时间比 pathb 旧则返回 true,否则 false,ot 是 older than 的意思
patha -ef pathbpathapathb 有相同 device 和 inode number 则返回 true,否则 false
if test $a -nt $b; then echo "$a is newer than $b"; fi
if test $a -ot $b; then echo "$a is older than $b"; fi

1.3 整数比较

下面针对的是整数判断,如果不是整数,则会报错。

函数意义
-eq两整数相等则返回 true,否则 false,eq 是 equal 的意思,若输入不是俩整数,则报错
-gt两整数前者大于后者则返回 true,否则 false,gt 是 greater than 的意思,若输入不是俩整数,则报错
\>含义同 -gt,为了和重定向符号区分,则需要转义
-ltlt 是 less than 的意思
\<-lt
-gege 是 greater eqaul 的意思,注意没有 \>= 这种写法
-lele 是 less eqaul 的意思,注意没有 \<= 这种写法
if test $a -eq $b; then echo "$a eqals $b"; fi

1.4 字符串不相等判断

=!= 针对字符串。字符串完全相同则是相等,有一点不同则是不等。

函数意义
=两字符串相同则返回 true,否则 false,判断字符串的等号左右都是有空格的
!=两字符串不同则返回 true,否则 false
if test $a = $b; then echo "$a eqals $b"; fi

2. 分支结构

就是条件判断,在不同条件下执行不同的操作。常见有 if elsedo whilecase esac 这几种。

2.1 if else 结构

if condition; then xxx; fi
if condition; then xxx; else yyy; fi
if condition_1; then xxx; elif condition_2;then yyy; else zzz; fi

2.2 case esac 结构

如果有多个选项,可以用一堆 if elif else,也可以用 case esac 的结构。这个和 c 语言中的 switch case 是一样的。不过这个 esac 是个什么鬼?看看 if 结尾的 fi 就能大悟了。🐶

语法如下:

case $x in
1) echo "select 1";;
2) echo "select 2";;
3) echo "select 3";;
*) echo "select nothing";;
esac

最后的星号 * 表示啥也没有选到,默认值。最后两个分号(;;)是跳出当前 case esac 的意思,和其它语言中的 break 很相似。不过 shell script 本身就是有 breakcontinue 关键字的,和 c 语言中的关键字是一样的。

3. 循环结构

常见的循环结构有 forwhileuntil 三种:

for x in xxxx;
do
xyz_operation
done
while condition:
do
xyz
done
until condition
do
xyz
done

如果要一直执行,则可以使用 while true 死循环一直执行。

continue 是跳出当前循环,继续下一次循环的意思。break 是跳出整个循环。

当然 continuebreak 都可以在后面接一个数字 n,表示是跳出当前第 n 层循环的意思。

4. 条件逻辑运算

4.1 分支中的条件运算

Shell 中表达式的结果可以进行与或非逻辑连接:

函数含义
-a/&&逻辑与
-o/||逻辑或
!逻辑非
if [ x -eq 5 ] && [ y -eq 6]; then echo "help"; fi
if test x -eq 5 && test y -eq 6; then echo "help"; fi
if ![ x -eq 5 ]; then echo "help"; fi

4.2 条件级连运算

对于命令也可以进行逻辑运算。

command_1 && command_2

这里还有一个好处,如果 command_1 已经返回逻辑假,则 command_2 就可以不执行了。

if [ ! -d ${path1} ]; then
mdkir -p ${path1}
fi

上面的写法就可以简写:

[ ! -d ${path1} ] && mkdir -p ${path1}

同样,对于或运算而言,如果第一个条件满足,后面的就不会执行了。这样的写法可以使代码更加简洁。

5. 小结

本文先介绍了 Shell 中的 test 命令,用于判断各种情况,然后介绍了 Shell 中的分支循环语法,以及条件级连运算。