Bash Shell避免here-document怪异行为

here-document 在使用时可能会出现一些怪异的行为。你想用 上文 介绍的方法来保存一份简单的捐赠人列表,因此创建了一个名为 donors 的文件,如下所示:

$ cat donors
#
# 简单地查找慷慨的捐赠人
#
grep $1 <<EOF
# 捐赠人及其捐赠额
pete $100
joe  $200
sam  $ 25
bill $ 9
EOF
$

但是运行时出现了奇怪的输出:

$ ./donors bill
pete bill00
bill $  9
$ ./donors pete
pete pete00
$

解决方案

通过转义结尾标记中的任意或所有字符,关闭 here-document 内部的 shell 特性:

grep $1 <<'EOF'
pete $100
joe  $200
sam  $ 25
bill $ 9
EOF

讨论

尽管其中存在非常微妙的区别,但也可以将 <<EOF 替换成 <<\EOF<<'EOF',甚至是 <<E\OF,都没问题。尽管这并不是最优雅的语法,但足以告诉 bash 你希望区别处理 here-document 中的内容。

正常情况下(除非使用了转义语法),bash 手册页中是这样说的:“……here-document 的每一行都要执行参数扩展、命令替换以及算术扩展”。

因此,最初的 donors 脚本中所发生的事情是捐赠额被当作 shell 变量了。例如,100 被视为 shell 变量1,随后跟着两个 0。这就是为什么我们在搜索“pete”时,得到的是 pete00;搜索“bill”时,得到的是 bill00。

如果我们转义了 EOF 的部分或全部字符,那么 bash 就知道不用执行扩展,这样就符合我们的预期行为了。

$ ./donors pete
pete $100

当然了,你可能确实想要 bash 对 here-document 内部执行扩展操作,这种做法在某些情况下自有用处,不过眼前这个例子并非如此。我们发现,除非你真的要扩展数据,否则坚持转义终止符(就像 <<'EOF'<<\EOF)是一种不错的做法,这样能够避免产生出乎意料的结果。

在结尾处的 EOF 标记中出现的拖尾空白字符(哪怕只是一个空格)会导致无法将其识别为结束标记。bash 会吞掉脚本的剩余部分,将其也视为输入并继续查找 EOF。所以,一定要确保 EOF 之后没有额外的空白字符(尤其是空格或制表符)。

酷客网相关文章:

赞(0)

评论 抢沙发

评论前必须登录!