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

如果grepmyfile中的一行匹配,那么退出代码将为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解释器知道每个参数的开始和结束位置。

posted @ 2022-03-28 10:58  不羁的罗恩  阅读(109)  评论(0编辑  收藏  举报