条件判断
if语句
if condition
then
statement(s)
fi
if condition; then
statement(s)
fi
if else
if condition
then
statement1
else
statement2
fi
if elif else
if condition1
then
statement1
elif condition2
then
statement2
elif condition3
then
statement3
……
else
statementn
fi
命令的退出状态
每一条 Shell命令,不管是 Bash 内置命令(例如 test、echo),还是外部的 Linux 命令(例如 cd、ls),还是自定义的 Shell 函数,当它退出(运行结束)时,都会返回一个比较小的整数值给调用(使用)它的程序,这就是命令的退出状态(exit statu)。
很多 Linux 命令其实就是一个C语言程序,熟悉C语言的读者都知道,main() 函数的最后都有一个
return 0
,如果程序想在中间退出,还可以使用exit 0
,这其实就是C语言程序的退出状态。当有其它程序调用这个程序时,就可以捕获这个退出状态。
Shell test命令
Shell test 命令的用法为:
test expression
当 test 判断 expression 成立时,退出状态为 0,否则为非 0 值。
test 命令也可以简写为[],它的用法为:
[ expression ]
注意[]和expression之间的空格,这两个空格是必须的,否则会导致语法错误。[]的写法更加简洁,比 test 使用频率高。
test选项
文件类型判断
选项 | 作用 |
---|---|
-b filename | 判断文件是否存在,并且是否为块设备文件 |
-c filename | 判断文件是否存在,并且是否为字符设备文件 |
-d filename | 判断文件是否存在,并且是否为目录文件 |
-e filename | 判断文件是否存在 |
-f filename | 判断文件是否存在,并且是否为普通文件 |
-L filename | 判断文件是否存在,并且是否为符号链接文件 |
-p filename | 判断文件是否存在,并且是否为管道文件 |
-s filename | 判断文件是否存在,并且是否为非空 |
-S filename 判断文件是否存在,并且是否为套接字文件
文件权限判断
选项 | 作用 |
---|---|
-r filename | 判断文件是否存在,并且是否拥有读权限 |
-w filename | 判断文件是否存在,并且是否拥有写权限 |
-x filename | 判断文件是否存在,并且是否拥有执行权限 |
-u filename | 判断文件是否存在,并且是否拥有SUID权限 |
-g filename | 判断文件是否存在,并且是否拥有SGID权限 |
-k filename | 判断文件是否存在,并且是否拥有SBIT权限 |
文件比较
选项 | 作用 |
---|---|
filename1 -nt filename2 | 判断 filename1 的修改时间是否比 filename2 的新 |
filename1 -ot filename2 | 判断 filename1 的修改时间是否比 filename2 的旧 |
filename1 -ef filename2 | 判断 filename1 是否和 filename2 的 inode 号一致,可以理解为两个文件是否为同一个文件。这个判断用于判断硬链接是很好的方法 |
数值比较
选项 | 作用 |
---|---|
num1 -eq num2 | 判断 num1 是否和 num2 相等。 |
num1 -ne num2 | 判断 num1 是否和 num2 不相等。 |
num1 -gt num2 | 判断 num1 是否大于 num2 。 |
num -lt num2 | 判断 num1 是否小于 num2。 |
num1 -ge num2 | 判断 num1 是否大于等于 num2。 |
num1 - le num2 | 判断 num1 是否小于等于 num2。 |
注意,test 只能用来比较整数,小数相关的比较还得依赖 bc 命令。
字符串相关
选项 | 作用 |
---|---|
-z str | 判断字符串 str 是否为空。 |
-n str | 判断字符串 str 是否为非空。 |
str1 = str2 str1 == str2 | =和==是等价的,都用来判断 str1 是否和 str2 相等 |
str1 !=str2 | 判断 str1 是否和 str2 不相等 |
str1 > str2 | 判断 str1 是否大于 str2。>是>的转义字符,这样写是为了防止>被误认为成重定向运算符。 |
str1 < str2 判断 str1 是否小于 str2。同样,<也是转义字符。
逻辑运算相关
选项 | 作用 |
---|---|
expression1 -a expression | 逻辑与,表达式 expression1 和 expression2 都成立,最终的结果才是成立的。 |
expression1 -o expression2 | 逻辑或,表达式 expression1 和 expression2 有一个成立,最终的结果就成立。 |
!expression | 逻辑非,对 expression 进行取反。 |
当你在 test 命令中使用变量时,我强烈建议将变量用双引号""包围起来,这样能避免变量为空值时导致的很多奇葩问题
test 命令比较奇葩,>、<、== 只能用来比较字符串,不能用来比较数字,比较数字需要使用 -eq、-gt 等选项;不管是比较字符串还是数字,test 都不支持 >= 和 <=。有经验的程序员需要慢慢习惯 test 命令的这些奇葩用法。
对于整型数字的比较,我建议大家使用 (())
[[]]
[[ ]] 的用法为:
[[ expression ]]
当 [[ ]] 判断 expression 成立时,退出状态为 0,否则为非 0 值。注意[[ ]]和expression之间的空格,这两个空格是必须的,否则会导致语法错误。
[[ ]] 是 Shell 内置关键字,不是命令,在使用时没有给函数传递参数的过程,所以 test 命令的某些注意事项在 [[ ]] 中就不存在了,具体包括:
不需要把变量名用双引号""包围起来,即使变量是空值,也不会出错。
不需要、也不能对 >、< 进行转义,转义后会出错
[[]]支持逻辑运算符
[[ -z $str1 || -z $str2 ]]
不能用-o -a选项
[[]]支持正则表达式
在 Shell [[ ]] 中,可以使用=~来检测字符串是否符合某个正则表达式,它的用法为:
[[ str =~ regex ]]
但是 [[ ]] 对数字的比较仍然不友好,所以我建议,以后大家使用 if 判断条件时,用 (()) 来处理整型数字,用 [[ ]] 来处理字符串或者文件。
shell case in
case expression in
pattern1)
statement1
;;
pattern2)
statement2
;;
pattern3)
statement3
;;
……
*)
statementn
esac
case、int 和 esac 都是 Shell 关键字,expression 表示表达式,pattern 表示匹配模式。
- expression 既可以是一个变量、一个数字、一个字符串,还可以是一个数学计算表达式,或者是命令的执行结果,只要能够得到 expression 的值就可以。
- pattern 可以是一个数字、一个字符串,甚至是一个简单的正则表达式。
case 会将 expression 的值与 pattern1、pattern2、pattern3 逐个进行匹配:
-
如果 expression 和某个模式(比如 pattern2)匹配成功,就会执行这模式(比如 pattern2)后面对应的所有语句(该语句可以有一条,也可以有多条),直到遇见双分号;;才停止;然后整个 case 语句就执行完了,程序会跳出整个 case 语句,执行 esac 后面的其它语句。
-
如果 expression 没有匹配到任何一个模式,那么就执行)后面的语句(表示其它所有值),直到遇见双分号;;或者esac才结束。*)相当于多个 if 分支语句中最后的 else 部分。
-
Shell case in 语句中的)用来“托底”,万一 expression 没有匹配到任何一个模式,)部分可以做一些“善后”工作,或者给用户一些提示。
-
可以没有*)部分。如果 expression 没有匹配到任何一个模式,那么就不执行任何操作。
case in 与正则表达式
格式 | 说明 |
---|---|
* | 表示任意字符串 |
[abc] | 表示 a、b、c 三个字符中的任意一个。比如,[15ZH] 表示 1、5、Z、H 四个字符中的任意一个。 |
[m-n] | 表示从 m 到 n 的任意一个字符。比如,[0-9] 表示任意一个数字,[0-9a-zA-Z] 表示字母或数字。 |
竖线 | 表示多重选择,类似逻辑运算中的或运算。比如,abc 竖线xyz 表示匹配字符串 "abc" 或者 "xyz"。 |
while
while 循环的用法如下:
while condition
do
statements
done
until
until condition
do
statements
done
for
for((exp1; exp2; exp3))
do
statements
done
for in
for variable in value_list
do
statements
done
select in
select variable in value_list
do
statements
done
break
break n
continue
continue n
函数
function name() {
statements
[return value]
}
Shell 函数的返回值只能是一个介于 0~255 之间的整数,其中只有 0 表示成功,其它值都表示失败。
重定向
- 输入方向就是数据从哪里流向程序。数据默认从键盘流向程序,如果改变了它的方向,数据就从其它地方流入,这就是输入重定向
- 输出方向就是数据从程序流向哪里。数据默认从程序流向显示器,如果改变了它的方向,数据就流向其它地方,这就是输出重定向
与输入输出有关的文件描述符
文件描述符 | 文件名 | 类型 | 硬件 |
---|---|---|---|
0 | stdin | 标准输入 | 键盘 |
1 | stdout | 标准输出 | 显示器 |
2 | stderr | 标准错误输出 | 显示器 |
输出重定向
类型 | 符号 | 作用 |
---|---|---|
标准输出重定向 | 命令>文件 | 以覆盖的方式,把命令的正确输出结果输出到指定的文件或设备中。 |
标准输出重定向 | 命令>>文件 | 以覆盖的方式,以追加的方式,把命令的正确输出结果输出到指定的文件或设备中。 |
标准错误输出重定向 | 命令 2> 文件 | 以覆盖的方式,把命令的错误信息输出到指定的文件或设备中。 |
标准错误输出重定向 | 命令 2>> 文件 | 以追加的方式,把命令的错误信息输出到指定的文件或设备中。 |
正确输出和错误信息同时保存 | 命令 > 文件2 > &1 | 以覆盖的方式,把正确输出和错误信息同时保存到同一个文件中。 |
正确输出和错误信息同时保存 | 命令 >> 文件 2> &1 | 以追加的方式,把正确输出和错误信息同时保存到同一个文件中。 |
正确输出和错误信息同时保存 | 命令 &> 文件 | 以覆盖的方式,把正确输出和错误信息同时保存到同一个文件中。 |
正确输出和错误信息同时保存 | 命令 &>> 文件 | 以追加的方式,把正确输出和错误信息同时保存到同一个文件中。 |
正确输出和错误信息同时保存 | 命令 >> 文件1 2>> 文件2 | 把正确的输出追加到文件1中,把错误信息追加到文件2中。 |
输入重定向
符号 | 说明 |
---|---|
命令 < 文件 | 将指定的文件作为命令的输入。 |
命令 << 分界符 | 从标准输入(键盘)中读取数据,直到遇见分界符才停止。 |
命令 < 文件1 > 文件2 | 将文件1作为命令的输入,并将命令的处理结果输出到文件2。 |
shell模块化
source
source filename
. filename
避免循环导入
模块文件 module.sh:
if [ -n "$__MODULE_SH__" ]; then
return
fi
__MODULE_SH__='module.sh'
echo "http://c.biancheng.net/shell/"
主文件 main.sh:
#!/bin/bash
source module.sh
source module.sh
echo "here executed"
运行 main.sh,输出结果为:
http://c.biancheng.net/shell/
here executed
网友评论