[TOC]
if 分支结构
if 语句的语法:
if commands; then
commands
[elif commands; then
commands...]
[else
commands]
fi
示例代码:
x=5
if [ $x = 5 ]; then
echo "x equals 5."
else
echo "x does not equal 5."
fi
退出状态
当命令执行完毕后,命令(包括我们编写的脚本和 shell 函数)会给系统发送一个值,叫做退出状态。 这个值是一个 0 到 255 之间的整数,说明命令执行成功或是失败。按照惯例,一个零值说明成功,其它所有值说明失败。 Shell 提供了一个参数($?),我们可以用它检查退出状态。
echo $?
- true 命令总是执行成功,而 false 命令总是执行失败
测试
经常与 if 一块使用的命令是 test。这个 test 命令执行各种各样的检查与比较。它有两种等价模式:
test expression
比较流行的格式是:
[ expression ]
这里的 expression 是一个表达式,其执行结果是 true 或者是 false。当表达式为真时,这个 test 命令返回一个零退出状态,当表达式为假时,test 命令退出状态为 1。
文件表达式
测试文件表达式 | 如果为真 |
---|---|
file1 -ef file2 | file1 和 file2 拥有相同的索引号(通过硬链接两个文件名指向相同的文件)。 |
file1 -nt file2 | file1 新于 file2。 |
file1 -ot file2 | file1 早于 file2。 |
-b file | file 存在并且是一个块(设备)文件。 |
-c file | file 存在并且是一个字符(设备)文件。 |
-d file | file 存在并且是一个目录。 |
-e file | file 存在。 |
-f file | file 存在并且是一个普通文件。 |
-g file | file 存在并且设置了组 ID。 |
-G file | file 存在并且由有效组 ID 拥有。 |
-k file | file 存在并且设置了它的 “sticky bit”。 |
-L file | file 存在并且是一个符号链接。 |
-O file | file 存在并且由有效用户 ID 拥有。 |
-p file | file 存在并且是一个命名管道。 |
-r file | file 存在并且可读(有效用户有可读权限)。 |
-s file | file 存在且其长度大于零。 |
-S file | file 存在且是一个网络 socket。 |
-t fd | fd 是一个定向到终端/从终端定向的文件描述符 。 这可以被用来决定是否重定向了标准输入/输出错误。 |
-u file | file 存在并且设置了 setuid 位。 |
-w file | file 存在并且可写(有效用户拥有可写权限)。 |
-x file | file 存在并且可执行(有效用户有执行/搜索权限)。 |
示例代码:
#!/bin/bash
# test-file: Evaluate the status of a file
FILE=~/.bashrc
if [ -e "$FILE" ]; then
if [ -f "$FILE" ]; then
echo "$FILE is a regular file."
fi
if [ -d "$FILE" ]; then
echo "$FILE is a directory."
fi
if [ -r "$FILE" ]; then
echo "$FILE is readable."
fi
if [ -w "$FILE" ]; then
echo "$FILE is writable."
fi
if [ -x "$FILE" ]; then
echo "$FILE is executable/searchable."
fi
else
echo "$FILE does not exist"
exit 1
fi
exit
注意:
- 在表达式中参数 FILE 的参数展开 是一个空值,就会导致一个错误(操作符将会被解释为非空的字符串而不是操作符)。
- 注意脚本末尾的 exit 命令。 这个 exit 命令接受一个单独的,可选的参数,其成为脚本的退出状态。
test_file () {
# test-file: Evaluate the status of a file
FILE=~/.bashrc
if [ -e "$FILE" ]; then
if [ -f "$FILE" ]; then
echo "$FILE is a regular file."
fi
if [ -d "$FILE" ]; then
echo "$FILE is a directory."
fi
if [ -r "$FILE" ]; then
echo "$FILE is readable."
fi
if [ -w "$FILE" ]; then
echo "$FILE is writable."
fi
if [ -x "$FILE" ]; then
echo "$FILE is executable/searchable."
fi
else
echo "$FILE does not exist"
# 在函数中,用 return 语句来代替 exit 命令, 以得到期望的行为。
return 1
fi
}
字符串表达式
测试字符串表达式 | 如果为真... |
---|---|
string | string 不为 null。 |
-n string | 字符串 string 的长度大于零。 |
-z string | 字符串 string 的长度为零。 |
string1 = string2 | string1 和 string2 相同。单或双等号都可以,不过双等号更受欢迎。 |
string1 == string2 | 同上 |
string1 != string2 | string1 和 string2 不相同。 |
string1 > string2 | sting1 排列在 string2 之后。 |
string1 < string2 | string1 排列在 string2 之前。 |
⚠️ 当与 test 一块使用的时候, < 和 > 表达式操作符必须用引号引起来(或者是用反斜杠转义)。
整形表达式
测试整数表达式 | 如果为真... |
---|---|
integer1 -eq integer2 | integer1 等于 integer2. |
integer1 -ne integer2 | integer1 不等于 integer2. |
integer1 -le integer2 | integer1 小于或等于 integer2. |
integer1 -lt integer2 | integer1 小于 integer2. |
integer1 -ge integer2 | integer1 大于或等于 integer2. |
integer1 -gt integer2 | integer1 大于 integer2. |
示例代码:
#!/bin/bash
# test-integer: evaluate the value of an integer.
INT=-5
if [ -z "$INT" ]; then
echo "INT is empty." >&2
exit 1
fi
if [ $INT -eq 0 ]; then
echo "INT is zero."
else
if [ $INT -lt 0 ]; then
echo "INT is negative."
else
echo "INT is positive."
fi
if [ $((INT % 2)) -eq 0 ]; then
echo "INT is even."
else
echo "INT is odd."
fi
fi
更现代的测试版本
目前的 bash 版本包括一个复合命令,作为加强的 test 命令替代物。它使用以下语法:
[[ expression ]]
这个 [[ ]] 命令非常相似于 test 命令(它支持所有的表达式),但是增加了一个重要的新的字符串表达式:
string1 =~ regex
如果 string1 匹配扩展的正则表达式 regex,其返回值为真。
[[ ]]
添加的另一个功能是==
操作符支持类型匹配,正如路径名展开所做的那样。
(()) - 为整数设计
除了[[ ]]
复合命令之外,bash 也提供了 (( ))
复合命名,其有利于操作整数。它支持一套完整的算术计算。
(( ))
被用来执行算术真测试。如果算术计算的结果是非零值,则一个算术真测试值为真。
结合表达式
逻辑操作符 | 测试 | [[ ]] and (( )) |
---|---|---|
AND | -a | && |
OR | -o | || |
NOT | ! | ! |
控制操作符 - 分支的另一种方法
bash 支持两种可以执行分支任务的控制操作符。这个 &&(AND)
和 ||(OR)
操作符作用如同复合命令 [[ ]]
中的逻辑操作符。这是语法:
# 先执行 command1,并且只有 command1 执行成功后,才会执行 command2。
command1 && command2
和
# 先执行 command1,并且只有 command1 执行失败后, 才会执行 command2
command1 || command2
示例代码:
mkdir temp && cd temp
while/util 循环
while 命令的语法是:
while commands; do commands; done
和 if 一样, while 计算一系列命令的退出状态。只要退出状态为零,它就执行循环内的命令。
示例代码:
#!/bin/bash
# while-count: display a series of numbers
count=1
while [ $count -le 5 ]; do
echo $count
count=$((count + 1))
done
echo "Finished."
跳出循环
bash 提供了两个内部命令,它们可以用来在循环内部控制程序流程。
- break 命令立即终止一个循环, 且程序继续执行循环之后的语句。
- continue 命令导致程序跳过循环中剩余的语句,且程序继续执行 下一次循环。
case 分支
Bash 的多选复合命令称为 case。它的语法规则如下所示:
case word in
[pattern [| pattern]...) commands ;;]...
esac
示例代码:
#!/bin/bash
# case-menu: a menu driven system information program
clear
echo "
Please Select:
1. Display System Information
2. Display Disk Space
3. Display Home Space Utilization
0. Quit
"
read -p "Enter selection [0-3] > "
case $REPLY in
0) echo "Program terminated."
exit
;;
1) echo "Hostname: $HOSTNAME"
uptime
;;
2) df -h
;;
3) if [[ $(id -u) -eq 0 ]]; then
echo "Home Space Utilization (All Users)"
du -sh /home/*
else
echo "Home Space Utilization ($USER)"
du -sh $HOME
fi
;;
*) echo "Invalid entry" >&2
exit 1
;;
esac
case 模式 | 描述 |
---|---|
a) | 若单词为 “a”,则匹配 |
[[:alpha:]]) | 若单词是一个字母字符,则匹配 |
???) | 若单词只有 3 个字符,则匹配 |
.txt) | 若单词以 “.txt” 字符结尾,则匹配 |
) | 匹配任意单词。把这个模式做为 case 命令的最后一个模式,是一个很好的做法, 可以捕捉到任意一个与先前模式不匹配的数值;也就是说,捕捉到任何可能的无效值。 |
位置参数
可以用位置参数来访问命令行中的内容。
[me@linuxbox ~]$ posit-param a b c d
$0 = /home/me/bin/posit-param # 即使不带命令行参数,位置参数 $0 总会包含命令行中出现的第一个单词,也就是已执行程序的路径名。
$1 = a # 第一个参数是 a
$2 = b
$3 = c
$4 = d
$5 =
$6 =
$7 =
$8 =
$9 =
- 注意: 实际上通过参数展开方式你可以访问的参数个数多于 9 个。只要指定一个大于 9 的数字,用花括号把该数字括起来就可以。 例如 {55}, ${211},
确定参数个数
shell 还提供了一个名为 $#,可以得到命令行参数个数的变量。
shift - 访问多个参数的利器
for 循环
语法一:
for variable [in words]; do
commands
done
语法二:最新版本的 bash 已经添加了第二种格式的 for 命令语法,该语法相似于 C 语言中的 for 语法格式:
for (( expression1; expression2; expression3 )); do
commands
done
示例代码:
report_home_space () {
local format="%8s%10s%10s\n"
local i dir_list total_files total_dirs total_size user_name
if [[ $(id -u) -eq 0 ]]; then
dir_list=/home/*
user_name="All Users"
else
dir_list=$HOME
user_name=$USER
fi
echo "<H2>Home Space Utilization ($user_name)</H2>"
for i in $dir_list; do
total_files=$(find $i -type f | wc -l)
total_dirs=$(find $i -type d | wc -l)
total_size=$(du -sh $i | cut -f 1)
echo "<H3>$i</H3>"
echo "<PRE>"
printf "$format" "Dirs" "Files" "Size"
printf "$format" "----" "-----" "----"
printf "$format" $total_dirs $total_files $total_size
echo "</PRE>"
done
return
}
网友评论