Shell:常见错误总结(二)
Blog:博客园 个人
译自BashPitfalls
本文总结了编写Shell脚本中的常见错误。
承接上文。
[ "$foo" = bar && "$bar" = foo ]
不能在test
或者[]
中使用&&
命令。正确方法:
[ bar = "$foo" ] && [ foo = "$bar" ] # Right! (POSIX)
[[ $foo = bar && $bar = foo ]] # Also right! (Bash / Ksh)
[[ $foo > 7 ]]
虽然[[]]
可以做一些数值比较,但不推荐使用,正确方法:
# Bash / Ksh
((foo > 7)) # Right!
[[ foo -gt 7 ]] # Works, but is uncommon. Use ((…)) instead.
# POSIX
[ "$foo" -gt 7 ] # Also right!
[ "$((foo > 7))" -ne 0 ] # POSIX-compatible equivalent to ((, for more general math operations.
💡Tips:在
[[]]
中使用类似>
比较符,bash解释器会将其视为字符串比较。
如果任何算术上下文的输入(包括((
,let
,数组索引)或[[…]]
不能保证包含数字比较的测试表达式,因此必须始终在计算表达式之前验证您的输入:
POSIX
case $foo in
("" | *[!0123456789]*)
printf '$foo is not a sequence of decimal digits: "%s"\n' "$foo" >&2
exit 1
;;
*)
[ "$foo" -gt 7 ]
esac
💡Tips:由于
[/test
这类命令的算数运算符操作的是十进制整数,若二进制010则会被解释为数字10。
grep foo bar | while read -r; do ((count++)); done
该命令咋看还不错,但只是grep -c
很差的实现,而且对count
的更改不会传播到while
循环之外,因为管道中的每个命令都在单独的子shell中执行。
if [grep foo myfile]
许多初学者对if
语句有一种错觉,看到if
关键字后面紧跟[
或[[
这一非常常见的模式。这让人相信[
不知何故是if
语句语法的一部分,就像C语言的if
语句中使用的括号一样。
这种想法是错误的,[
是命令,而不是if
语句的语法标记。它等同于test
命令,不同之处在于最后一个参数必须是]
。例如:
# POSIX
if [ false ]; then echo "HELP"; fi
if test false; then echo "HELP"; fi
if
语法如下:
if COMMANDS; then
<COMMANDS>
elif <COMMANDS>; then # optional
<COMMANDS>
else
<COMMANDS> # optional
fi # required
如果您希望根据grep
命令的输出做出决定,则不希望将其括在圆括号、方括号、反号或任何其他语法中,只需在if
之后使用grep
作为命令,如下所示:
if grep -q fooregex myfile; then
…
fi
如果grep
与myfile
中的一行匹配,那么退出代码将为0(True),然后将执行then
部分。否则,如果没有匹配项,grep
将返回非零值,整个if
命令将为零。
if [bar="$foo"]; then …
[bar="$foo"] # Wrong!
[ bar="$foo" ] # Still wrong!
[bar = "$foo"] # Also wrong!
[[bar="$foo"]] # Wrong again!
[[ bar="$foo" ]] # Guess what? Wrong!
[[bar = "$foo"]] # Do I really need to say it…
以上为错误语法,正确如下:
if [ bar = "$foo" ]; then …
if [[ bar = "$foo" ]]; then …
💡Tips:每对参数之间必须有空格,以便Bash解释器知道每个参数的开始和结束位置。