Using-Structured-Commands
# 本章内容
if-then,if-then-else,if-then-elifstatement- Understanding the
testcommand - Testing compound conditions
- Using double brackets and parentheses Looking at case
# if-then statement
# if-then
if-then 语句在 shell 中是用来判断命令的 (0 表示命令执行成功,非 0 标识命令执行失败),而在常规的编程语言中 if 语句通常是用来判断条件的。但在 shell 中判断条件使用 test 。具体见 test command and [] (opens new window)
我的缩进风格采用了 google shell (opens new window) 的缩进风格,在需要缩进的地方都使用两个 space。
if-then 的格式:
if command
then
commands
fi
2
3
4
或者也可以使用:
if command ; then
commands
fi
2
3
如果 command 执行成功,exit code 为 0,那么就会执行 then 中的 commands .
# if-then else
if then 语句的缺点是如果 command 命令的退出码不为 0,那么就不会执行 commands 直接退出。使用 if then else 可以对 command 的退出码不为 0 时就会执行 else 中的 commands 。
if command
then
commands
else
commands
fi
2
3
4
5
6
if-then else 和 if-then 可以嵌套使用。
# if-then elif-then
if command1
then
commands
elif command2
then
more commands
...
fi
2
3
4
5
6
7
8
# if-then elif-then else
或者可以在 elif 中加入 else ,这样如果 command1 和 command2 返回的状态码都不为 0 时,会执行 commands3:
if command1
then
commands1
elif command2
then
commands2
else
commands3
fi
2
3
4
5
6
7
8
9
# test command and []
if 语句只能用来直接判断命令的执行是否成功,然后执行一些操作。 test 命令使得 if 语句有了判断条件语句的能力。
test 和 [] 能判断的条件有:
- Numeric comparisions
- String comparisions
- File comparisions
(接下来会一一介绍每种判断条件的使用方法)
如果 test 条件判断为 TRUE,那么 test 命令的条件状态码返回 0,否则条件状态码返回非零:
if test condition
then
commands
fi
2
3
4
(如果 condition 为空,则 test 返回条件码为非零 (FALSE)。)
使用举例:
#!/bin/bash
# testing if a variable has content
# my_variable is empty
if test $my_variable
then
echo "The my_variable variable has content and returns a True."
echo "The my_variable variable content is: $my_variable"
else
echo "The my_variable variable doesn't have content,"
echo "and returns a False."
fi
2
3
4
5
6
7
8
9
10
11
output:
The my_variable variable doesn't have content,
and returns a False.
2
Bash shell 中声明了 square bracket [] 来代替 test。
if [ condition ]
then
commands
fi
2
3
4
警告
左括号后和右括号前都必须有一个 sapce,否则会报错误。
# Numeric comparisons
使用 test 或者 [] 来进行整型数值条件的比较 (注意 n1, n2 可以是数字或者是存储数字的变量):
| Comparison | Description |
|---|---|
| n1 -eq n2 | Checks if n1 is equal to n2. |
| n1 -ge n2 | Checks if n1 is greater than or equal to n2. |
| n1 -gt n2 | Checks if n1 is greater than n2. |
| n1 -le n2 | Checks if n1 is less than or equal to n2. |
| n1 -lt n2 | Checks if n1 is less than n2. |
| n1 -ne n2 | Checks if n1 is not equal to n2. |
举例:
# This file is named script.sh
#!/bin/bash
var1=1
var2=2
if [ $var1 -ge $var2 ]
then
echo "var1 >= var 2"
else
echo "var1 < var 2"
fi
2
3
4
5
6
7
8
9
10
output:
$ ./script.sh
var1 < var 2
2
# String comparisions
使用 test 或者 [] 来进行字符串条件的比较 (要比较的两个字符串可以是字符串或者是存储字符串的变量):
| Comparison | Description |
|---|---|
| str1 = str2 | Checks if str1 is the same as string str2. |
| str1 != str2 | Checks if str1 is not the same as str2. |
| str1 < str2 | Checks if str1 is less than str2. |
| str1 > str2 | Checks if str1 is greater than str2. |
| -n str1 | Checks if str1 has a length greater than zero.(-n is "not zero") |
| -z str1 | Checks if str1 has a length of zero. |
注意事项:
- 使用
>和<进行比较时,需要使用\进行 escape. 否则 bash 会把它理解为重定向。 >和<是按照每个字符的 Unicode 进行比较的。sort进行比较时,小写字符比大写字符都小,这是根据字符的使用习惯。而 shell 的比较条件<和>使用的是每个字符对应的 Unicode 进行比较,所以大写字符比小写字母都要小。- 未定义的变量,对应的字符串长度也为 0。
#!/bin/bash
var1="He"
var2="he"
if [ $var1 \> $var2 ]
then
echo "var1 > var 2"
else
echo "var1 < var 2"
fi
2
3
4
5
6
7
8
9
# File comparisions
(最常使用在文件访问时)
用来检查 Linux 中文件的各种属性。
| 命令 | 解释 |
|---|---|
-d f | Checks if f exists and is a directory. |
-e f | Checks if f exists and is file or directory. |
-f f | Checks if f exists and is a file. |
-r f | Checks if f exists and is readable. |
-w f | Checks if f exists and is writable. |
-x f | Checks if f exists and is executable. |
-s f | Checks if f exists and is not empty. |
-O f | Checks if f exists and is owned by the current user. |
-G f | Checks if f exists and the default group of the file f is the same as the group of the current user. |
| f1 -nt f2 | Checks if f1 is newer than f2 . (-nt means "new than") |
| f1 -ot f2 | Checks if f1 is older than f2 .(-nt means "old than") |
提示
-d命令常使用在读写文件前,用来判断文件所在的目录是否存在。-r命令常使用在读文件前,用来判断文件是否是可读的。-w命令常使用在读文件写,用来判断文件是否是可写的。-s命令常使用在删除文件前,用来判断文件是否是空的。-nt和-ot常用来比较两个文件的新旧,但是比较前,应该使用-f命令确保两个文件都是存在的。
表格中的 f, f1, f2 可以是一个变量,也可以直接是一个字符串
举例:
#!/bin/bash
name="foo.md"
if [ -f $name ]
then
echo "$name is a file"
fi
2
3
4
5
6
7
output:
$ file foo.md
foo.md: empty
./script.sh
foo.md is a file
2
3
4
5
# Compound Testing
[ condition1 ] && [ condition2 ] // AND
[ condition1 ] || [ condition2 ] // OR
2
对于 OR 语句来说: The first condition is always verified, but the second condition is only verified if the first condition is false.
对于 AND 语句来说: The first condition is always verified, but the second condition is only verified if the first condition is true.
# Working with Advanced if-then Features
在 if-then 中还能使用三种高级特性:
- Single Parentheses
# Single Parentheses
Single Parenthese: 在 bash 执行 command 之前,会创建一个 subshell 来执行 command 命令。如果不加括号,就直接在运行脚本的那个 shell 中执行 command 命令。
使用方法:
if (command)
then
commands
fi
2
3
4
如果 command 的退出码为 0,就会执行 then 中的 commands
# Using double parentheses
double parentheses 命令提供了高级的字符串比较功能。(还增加了赋值功能)
在 if 中使用 test 命令可以使得我们可以进行三种类型的比较:数字比较,字符串比较,文件比较。双括号使得我们可以在 if 中使用更多的数学运算。更加符合编程语言比较语句的语法逻辑
(若双括号中的运算结果是 0,则退出码为非 0;若双括号中的运算结果为非 0,则退出码为 0,即正常退出)
$ ((0))
$ echo $?
1
$ ((1))
$ echo $?
0
2
3
4
5
6
在双括号比较语句和赋值语句,还可以在双括号中使用:
| Symbol | Description |
|---|---|
| val++ | Post-increment |
| val-- | Post-decrement |
| ++val | Pre-increment |
| --val | Pre-decrement |
| ! | Logical negation |
| ~ | Bitwise negation |
| ** | Exponentiation |
| << | Left bitwise shift |
| >> | Right bitwise shift |
| & | Bitwise Boolean AND |
| | | Bitwise Boolean OR |
| && | Logical AND |
| || | Logical OR |
不仅可以在 if 进行判断时使用双括号语句,还可以在正常命令中使用双括号将数学运算的结果赋值给变量:
$ cat script.sh
#!/bin/bash
# Testing a double parentheses command
#
val1=10
#
if (( $val1 ** 2> 90 ))
then
(( val2 = $val1 ** 2 )) # 也可以使用上一章中的: val2=$[$val1 ** 2]
echo "The square of $val1 is $val2,"
echo "which is greater than 90."
#
fi
$ ./script.sh
The square of 10 is 100,
which is greater than 90.
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
提示
在使用 test 或者 [] 对字符串进行比较时,还需要使用 backslash 来 escape > 和 < 符号。但是使用双括号时不需要 escape。
# Using double brackets
double brackets 命令提供了高级的字符串比较功能。 它和 test 中字符串比较方式相同,但是 double brackets 提供了一个 test 没有的高级功能 —— pattern matching
举例:
$ bash --version
GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ cat script.sh
#!/bin/bash
# Using double brackets for pattern matching
#
#
if [[ $BASH_VERSION == 5.* ]]
then echo "You are using the Bash Shell version 5 series."
fi
$ ./script.sh
You are using the Bash Shell version 5 series.
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
注意
使用 double bracket 来比较字符串时,判断两字符串相等使用的是 == . 在 test 命令中使用的时 = .
# Considering the case Command
语法:
case variable in
pattern1 | pattern2 ) commands1 ;;
pattern3 ) commands2 ;;
*) default commands ;;
esac
2
3
4
5
使用举例:
$ cat script.sh
#!/bin/bash
# Using a short case statement
#
case $USER in
rich | christine)
echo "Welcome $USER"
echo "Please enjoy your visit.";;
barbara | tim | tartarus)
echo "Hi there, $USER"
echo "We're glad you could join us.";;
testing)
echo "Please log out when done with test.";;
*)
echo "Sorry, you are not allowed here."
esac
$ ./script
Hi there, tartarus
We're glad you could join us.
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
提示
每个选项都可以是多个命令,只有最后一个命令需要使用 ;;