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 之后没有额外的空白字符(尤其是空格或制表符)。
酷客网相关文章:
评论前必须登录!
注册