如果您已经关注 unix.stackexchange.com 一段时间了,那么您现在应该知道,echo $var
在 Bourne/POSIX shell(zsh 是例外)中的列表上下文(如)中不加引号的变量具有非常特殊的含义,并且除非你有很好的理由,否则不应该这样做。
在这里的许多问答中详细讨论了它(例如:为什么我的 shell 脚本会因空格或其他特殊字符而窒息?,何时需要双引号?,shell 变量的扩展以及 glob 和 split 对其的影响,引用vs 不带引号的字符串扩展)
自从 70 年代末 Bourne shell 首次发布以来就是这种情况,并且没有被 Korn shell 改变(David Korn 最大的遗憾之一(问题 #7))或者bash
大部分复制了 Korn shell,这就是POSIX/Unix 是如何指定的。
现在,我们仍然在这里看到许多答案,甚至偶尔会公开发布未引用变量的 shell 代码。你会认为人们现在已经学会了。
根据我的经验,主要有 3 类人会省略引用他们的变量:
初学者。这些可以被原谅,因为它是一种完全不直观的语法。我们在这个网站上的职责是教育他们。
健忘的人。
即使经过反复锤击也不相信的人,他们认为Bourne shell 的作者肯定没有打算让我们引用所有变量。
如果我们揭露与此类行为相关的风险,也许我们可以说服他们。
如果您忘记引用变量,那么最糟糕的事情是什么。真的有那么糟糕吗?
我们在这里谈论什么样的漏洞?
在什么情况下会出现问题?
我在 while 循环中尝试使用特定工具(esearch
来自 NCBI 电子实用程序套件)时遇到了非常奇怪的情况。这是我的输入文件,一个字符串列表,每行一个:
$ cat transcripts.list
NR_169596.1
NR_169595.1
NR_169594.1
Run Code Online (Sandbox Code Playgroud)
我想esearch
使用每个字符串作为参数来运行命令,所以我这样做:
$ while read -r line; do echo "Line: $line"; esearch -db nucleotide -query "$line"; done < transcripts.list
Line: NR_169596.1
<ENTREZ_DIRECT>
<Db>nucleotide</Db>
<WebEnv>MCID_61bb689d20b59b3e2e2d405d</WebEnv>
<QueryKey>1</QueryKey>
<Count>1</Count>
<Step>1</Step>
</ENTREZ_DIRECT>
Run Code Online (Sandbox Code Playgroud)
这是一个结果,而不是三个,正如您通过echo
运行的单个结果所看到的那样。然而,如果我使用不好的 循环实践,同样的事情也会发生for
:
$ for line in $(cat transcripts.list); do echo "Line: $line"; esearch -db nucleotide -query "$line"; done
Line: NR_169596.1
<ENTREZ_DIRECT>
<Db>nucleotide</Db>
<WebEnv>MCID_61bb68cabbe98560233344a7</WebEnv>
<QueryKey>1</QueryKey>
<Count>1</Count>
<Step>1</Step>
</ENTREZ_DIRECT>
Line: NR_169595.1
<ENTREZ_DIRECT>
<Db>nucleotide</Db>
<WebEnv>MCID_61bb68cad05f5825d75e3ace</WebEnv>
<QueryKey>1</QueryKey> …
Run Code Online (Sandbox Code Playgroud)