结构化命令(structured command)就是类似于 if-else 的条件执行语句。
if-then 语句
if-then 的格式如下:
if command
then
commands
fi
在其他编程语言中,if 后面跟着一个 True 或 False 的逻辑表达式,但在 bash 中,先执行 if 后面的命令,如果该命令的退出状态码为 0(意味着成功执行),则执行 then 后面的语句。
有的脚本喜欢写成下面这样,看上去更像其他编程语言中的 if-then 语句:
if command; then
commands
fi
下面是一个示例:
$ cat test9
#!/bin/bash
user=pi
if grep $user /etc/passwd
then
echo "User $user exists"
echo "This is the user's file"
ls -a /home/$user/.b*
fi
$ /bin/bash test9
pi:x:1000:27:,,,:/home/pi:/bin/bash
cockpit-ws:x:114:121::/nonexisting:/usr/sbin/nologin
User pi exists
This is the user's file
/home/pi/.bash_history /home/pi/.bash_logout /home/pi/.bashrc
if语句使用 grep
命令在 /etc/passwd 文件中查找某个用户名当前是否在系统上使用,如果有用户使用了那个登录名,脚本会显示一些文本信息并列出用户 HOME 目录的 bash 文件。
if-then-else 语句
if-then-else 语句的格式如下:
if command
then
commands
else
commands
fi
我们可以在上一个脚本中加入 else 部分:
$ cat test9
#!/bin/bash
user=Todd
if grep $user /etc/passwd
then
echo "User $user exists"
echo "This is the user's file"
ls -a /home/$user/.b*
else
echo "User $user does not exist."
fi
$ /bin/bash test9
User Todd does not exist.
嵌套 if
if-then 可以嵌套在一起,当然这样看起来会很乱,这时可以用 elif 语句:
if command1
then
commands
elif command2
then
commands
elif command3
then
commands
...
else
commands
fi
最后的 else 不是必需的,可以省略。这里我懒得放例子了。
test 命令
if 只能测试退出状态码,如果需要进行数值比较,则需要利用 test 命令。test 的格式很简单:
test condition
如果 test 后面的条件为真,那么就会返回0,反之返回非零的退出状态码。比如:
$ test
$ echo $?
1
$ test ""
$ echo $?
1
$ test "0"
$ echo $?
0
如果 test 后面为空或空字符,那么退出状态码为 1;如果为非空字符,那么退出状态码为 0.
在 if-then 中,如果不想写 test,可以在 condition 两边用方括号 [ ]
括起来,注意括号与 condition 之间要有空格。如:
[ ]
$ echo $?
1
$ [ "" ]
$ echo $?
1
$ [ "0" ]
$ echo $?
0
test 可以判断三类条件:
- 数值比较
- 字符串比较
- 文件比较
数值比较
比较 |
描述 |
---|---|
|
检查 |
|
检查 |
|
检查 |
|
检查 |
|
检查 |
|
检查 |
示例:
$ [ 1 -eq 1 ] ; echo $?
0
$ [ 1 -gt 2 ] ; echo $?
1
$ [ 1 -lt 2 ] ; echo $?
0
$ [ 1 -ne 2 ] ; echo $?
0
$ [ 1 -eq 1.1 ] ; echo $?
bash: [: 1.1: integer expression expected
2
注意 n1
和 n2
必须是整数,否则就会像最后一行那样出错。
字符串比较
比较 |
描述 |
---|---|
|
检查 |
|
检查 |
|
检查 |
|
检查 |
|
检查 |
|
检查 |
这里要注意的是比较大小:
- 大于号和小于号必须转义,否则 shell 会把它们当作重定向符号,把字符串值当作文件名;
- 大于和小于顺序和 sort 命令采取的不同,这里认为大写字母是小于小写字母的。
示例:
$ [ "Hello" \> "hello" ] ; echo $?
1
$ [ "Hello" \< "hello" ] ; echo $?
0
文件比较
比较 |
描述 |
---|---|
|
检查 |
|
检查 |
|
检查 |
|
检查 |
|
检查 |
|
检查 |
|
检查 |
|
检查 |
|
检查 |
|
检查 |
|
检查 |
这里我也懒得举例子了,以后用到再来看吧。
复合条件测试
我们可以用布尔运算符将两个条件组合在一起:
[ condition1 ] && [ condition2 ]
[ condition1 ] || [ condition2 ]
示例:
$ [ -d $HOME ] && [ -w $HOME/testing ] ; echo $?
1
$ [ -d $HOME ] || [ -w $HOME/testing ] ; echo $?
0
if-then 高级特性
使用双括号
test 和 []
都只能使用简单的算术操作,双括号则提供了更多操作。除了 test 使用的标准数学运算符外,还有如下这些:
符号 |
描述 |
---|---|
|
后增 |
|
后减 |
|
先增 |
|
先减 |
|
逻辑求反 |
|
位求反 |
|
幂运算 |
|
左位移 |
|
右位移 |
|
位布尔和 |
|
位布尔或 |
|
逻辑和 |
|
逻辑或 |
而且双括号中的大于号无需转义。
$ cat test10
#!/bin/bash
val1=10
if (( $val1 ** 2 > 90))
then
(( val2 = $val1 **2))
echo "The square of $val1 is $val2"
fi
$ /bin/bash test10
The square of 10 is 100
case 命令
如果要匹配多个值,可以用 case,格式如下:
case variable in
pattern1 | pattern2) commands1;;
pattern3) commands2;;
*) default commands;;
esac
可以用 |
来匹配多个值,*
会捕获所有与已知模式不匹配的值。当执行完匹配的命令后,就会跳出 case。
$ cat test11
case $USER in
pi | root)
echo "Welcome, $USER";;
testing)
echo "Special testing account";;
Todd)
echo "Hi, $USER";;
*)
echo "Sorry, you are not allowed here";;
esac
$ /bin/bash test11
Welcome, pi