退出和状态码,操作符
1 exit 被用来结束一个脚本, 就像在C语言中一样. 它也返回一个值, 并且这个值会传递给脚本的父进程, 父进程会使用这个值做下一步的处理.
2 每个命令都会返回一个 退出状态码 (有时候也被称为 返回状态 ). 成功的命令返回0, 而不成功的命令返回非零值, 非零值通常都被解释成一个错误码. 行为良好的UNIX命令, 程序, 和工具都会返回0作为退出码来表示成功, 虽然偶尔也会有例外.
3 同样的, 脚本中的函数和脚本本身也会返回退出状态码. 在脚本或者是脚本函数中执行的最后的命令会决定退出状态码. 在脚本中, exit nnn命令将会把 nnn退出码传递给shell( nnn必须是十进制数, 范围必须是0 - 255).
4 当脚本以不带参数的exit命令来结束时, 脚本的退出状态码就由脚本中最后执行的命令来决定(就是exit之前的命令).不带参数的exit命令与 exit $?的效果是一样的, 甚至脚本的结尾不写exit, 也与前两者的效果相同.
5 $?保存了最后所执行的命令的退出状态码. 当函数返回之后, $?保存函数中最后所执行的命令的退出状态码. 这就是bash对函数"返回值"的处理方法. 当一个脚本退出, $?保存了脚本的退出状态码, 这个退出状态码也就是脚本中最后一个执行命令的退出状态码. 一般情况下, 0表示成功, 在范围1 - 255的整数表示错误.$?用于测试脚本中的命令结果的时候, 往往显得特别有用。!, 逻辑 "非"操作符, 将会反转命令或条件测试的结果, 并且这会影响退出状态码.
条件测试结构
1. if/then结构用来判断命令列表的退出状态码是否为0(因为在UNIX惯例, 0表示"成功"), 如果成功的话, 那么就执行接下来的一个或多个命令.
2. 有一个专有命令[ (左中括号, 特殊字符). 这个命令与test命令等价, 并且出于效率上的考虑,这是一个内建命令. 这个命令把它的参数作为比较表达式或者作为文件测试, 并且根据比较的结果来返回一个退出状态码(0 表示真, 1表示假).
3. 在版本2.02的Bash中, 引入了[[ ... ]]扩展测试命令, 因为这种表现形式可能对某些语言的程序员来说更容易熟悉一些. 注意[[是一个关键字, 并不是一个命令.Bash把[[ $a -lt $b ]]看作一个单独的元素, 并且返回一个退出状态码.
4. (( ... ))和let ...结构也能够返回退出状态码, 当它们所测试的算术表达式的结果为非零的时候, 将会返回退出状态码0. 这些算术扩展结构被用来做算术比较.
5. if命令能够测试任何命令, 并不仅仅是中括号中的条件.一个if/then结构可以包含嵌套的比较操作和条件判断操作.
6. 0为真,1为真,-1为真,空状态NULL为假,随便的一串字符为真.未初始化的变量为假;初始化了, 但是赋null值xyz= .null变量为假;if [ -n "$xyz" ]
7. "false"只不过是一个字符串而已,"false" 为真.if [ "$false" ]未初始化的变量"$false" 为假.
8. 如果if和then在条件判断的同一行上的话, 必须使用分号来结束if表达式.
if test condition-true结构与if [ condition-true ]完全相同. 就像我们前面所看到的, 左中括号,[ , 是调用test命令的标识. 而关闭条件判断用的的右中括号, ], 在if/test结构中并不是严格必需的, 但是在Bash的新版本中必须要求使用.test命令在Bash中是内建命令, 用来测试文件类型, 或者用来比较字符串. 因此, 在Bash脚本中, test命令并不会调用外部的/usr/bin/test中的test命令, 这是sh-utils工具包中的一部分. 同样的, [也并不会调用/usr/bin/[, 这是/usr/bin/test的符号链接.
test, /usr/bin/test, [ ], 和/usr/bin/[都是等价命令
9. 使用[[ ... ]]条件判断结构, 而不是[ ... ], 能够防止脚本中的许多逻辑错误. 比如,&&, ||, <, 和> 操作符能够正常存在于[[ ]]条件判断结构中, 但是如果出现在[ ]结构中的话, 会报错.
10. 在if后面也不一定非得是test命令或者是用于条件判断的中括号结构( [ ] 或 [[ ]] ). "if COMMAND"结构将会返回COMMAND的退出状态码.
11. (( ))结构扩展并计算一个算术表达式的值. 如果表达式的结果为0, 那么返回的退出状态码为1, 或者是"假". 而一个非零值的表达式所返回的退出状态码将为0, 或者是"true". 这种情况和先前所讨论的test命令和[ ]结构的行为正好相反.
12. 比较操作符
整数比较:
-eq等于,if [ "$a" -eq "$b" ]
-ne不等于,if [ "$a" -ne "$b" ]
-gt大于,if [ "$a" -gt "$b" ]
-ge大于等于,if [ "$a" -ge "$b" ]
-lt小于,if [ "$a" -lt "$b" ]
-le小于等于,if [ "$a" -le "$b" ]
<小于(在双括号中使用),(("$a" < "$b"))
<=小于等于(在双括号中使用),(("$a" <= "$b"))
>大于(在双括号中使用),(("$a" > "$b"))
>=大于等于(在双括号中使用),(("$a" >= "$b"))
字符串比较
=,等于,if [ "$a" = "$b" ]
==等于,if [ "$a" == "$b" ], 与=等价. ==比较操作符在双中括号对和单中括号对中的行为是不同的. [[ $a == z* ]] # 如果$a以"z"开头(模式匹配)那么结果将为真, [[ $a == "z*" ]] # 如果$a与z*相等(就是字面意思完全一样), 那么结果为真. [ $a == z* ] # 文件扩展匹配(file globbing)和单词分割有效, [ "$a" == "z*" ] # 如果$a与z*相等(就是字面意思完全一样), 那么结果为真.
!=不等号,if [ "$a" != "$b" ]这个操作符将在[[ ... ]]结构中使用模式匹配.
<小于, 按照ASCII字符进行排序,if [[ "$a" < "$b" ]], if [ "$a" \< "$b" ], 注意"<"使用在[ ]结构中的时候需要被转义.
>大于, 按照ASCII字符进行排序,if [[ "$a" > "$b" ]], if [ "$a" \> "$b" ], 注意">"使用在[ ]结构中的时候需要被转义.
-z字符串为"null", 意思就是字符串长度为零
-n字符串不为"null". 当-n使用在中括号中进行条件测试的时候, 必须要把字符串用双引号引用起来.
-a逻辑与,exp1 -a exp2 如果表达式exp1和exp2都为真的话, 那么结果为真.
-o逻辑或,exp1 -o exp2 如果表达式exp1和exp2中至少有一个为真的话, 那么结果为真.
这与Bash中的比较操作符&&和||非常相像, 但是这个两个操作符是用在双中括号结构中的. [[ condition1 && condition2 ]]
-o和-a操作符一般都是和test命令或者是单中括号结构一起使用的.1 if [ "$exp1" -a "$exp2" ]
在一个混合测试中, 即使使用引用的字符串变量也可能还不够.如果$string为空的话, [ -n "$string" -o "$a" = "$b" ]可能会在某些版本的Bash中产生错误. 安全的做法是附加一个额外的字符给可能的空变量, [ "x$string" != x -o "x$a" ="x$b" ] ("x"字符是可以相互抵消的).
位操作符.
<<左移一位(每次左移都相当于乘以2)
<<="左移-赋值"
let "var <<= 2" 这句的结果就是变量var左移2位(就是乘以4)
>>右移一位(每次右移都将除以2)
>>="右移-赋值" (与<<=正好相反)
&按位与
&="按位与-赋值"
|按位或
|="按位或-赋值"
~按位反
!按位非
^按位异或XOR
^="按位异或-赋值"
逻辑操作符
&&与(逻辑)
if [ $condition1 ] && [ $condition2 ] 与 if [ $condition1 -a $condition2 ] 相同, 如果condition1和condition2都为true, 那结果就为true.
if [[ $condition1 && $condition2 ]] 也可以. # 注意: &&不允许出现在[ ... ]结构中.&&也可以用在与列表中, 但是使用在连接命令中时, 需要依赖于具体的上下文.
||
或(逻辑)
if [ $condition1 ] || [ $condition2 ] 与 if [ $condition1 -o $condition2 ] 相同, 如果condition1或condition2中的一个为true, 那么结果就为true.
if [[ $condition1 || $condition2 ]] # 也可以. 注意||操作符是不能够出现在[ ... ]结构中的.
&&和||操作符也可以用在算术上下文中:echo $(( 1 && 2 )) $((3 && 0)) $((4 || 0)) $((0 || 0))
1 0 1 0
,
逗号操作符: 逗号操作符可以连接两个或多个算术运算. 所有的操作都会被运行(可能会有负作用), 但是只会返回最后操作的结果.