题
例如。
me$ FOO="BAR * BAR"
me$ echo $FOO
BAR file1 file2 file3 file4 BAR
并使用“\”转义字符:
me$ FOO="BAR \* BAR"
me$ echo $FOO
BAR \* BAR
我显然在做一些愚蠢的事情。
如何获得输出“BAR * BAR”?
解决方案
设置$ FOO时引用是不够的。您还需要引用变量引用:
me$ FOO="BAR * BAR"
me$ echo "$FOO"
BAR * BAR
其他提示
简短回答
就像其他人所说的那样 - 你应该总是引用变量来防止奇怪的行为。因此,请使用 echo“$ foo”而不是 echo $ foo 。
LONG ANSWER
我确实认为这个例子需要进一步解释,因为它的表面上看起来比它看起来更多。
我可以看到你的困惑在哪里,因为在你运行你的第一个例子后,你可能会认为shell显然正在做:
- 参数扩展
- 文件名扩展 醇>
所以从你的第一个例子开始:
me$ FOO="BAR * BAR"
me$ echo $FOO
参数扩展等同于:
me$ echo BAR * BAR
文件名扩展后相当于:
me$ echo BAR file1 file2 file3 file4 BAR
如果您只需在命令行中输入 echo BAR * BAR
,您就会发现它们是等效的。
所以你可能会想到自己“如果我逃避*,我可以阻止文件名扩展”
从第二个例子开始:
me$ FOO="BAR \* BAR"
me$ echo $FOO
参数扩展后应相当于:
me$ echo BAR \* BAR
文件名扩展后应相当于:
<*>如果你尝试输入“echo BAR \ * BAR”,直接进入命令行它将确实打印“BAR * BAR”。因为转义会阻止文件名扩展。
那么为什么使用$ foo不起作用?
这是因为发生了第三次扩张 - 报价清除。从bash手册中删除引用是:
在前面的扩展之后,所有 不带引号的字符出现 &#8216; \&#8217;,&#8216;'&#8217;和&#8216;&quot;&#8217;没结果 从上面的一个扩展是 除去。
所以当你直接在命令行输入命令时,转义字符不是先前扩展的结果,所以BASH在将它发送到echo命令之前将其删除,但在第二个例子中,“ \ *&QUOT;是先前参数扩展的结果,因此不会将其删除。结果,echo接收“\ *”。这就是打印的内容。
注意第一个例子 - “*”之间的区别。不包括在报价删除中删除的字符中。
我希望这是有道理的。最后得出的结论 - 只是使用引号。我只是想我会解释为什么转义,如果只有参数和文件名扩展在起作用,它在逻辑上应该可以工作,不起作用。
有关BASH扩展的完整说明,请参阅:
我会在这个老线程中加一点。
通常你会使用
$ echo "$FOO"
但是,即使使用这种语法,我也遇到了问题。请考虑以下脚本。
#!/bin/bash
curl_opts="-s --noproxy * -O"
curl $curl_opts "$1"
*
需要逐字传递给 curl
,但会出现同样的问题。上面的例子不起作用(它将扩展到当前目录中的文件名), \ *
也不会。您也无法引用 $ curl_opts
,因为它将被识别为 curl
的单个(无效)选项。
curl: option -s --noproxy * -O: is unknown
curl: try 'curl --help' or 'curl --manual' for more information
因此,如果应用于全局模式,或者使用 set -f,我建议使用
内置标志。 bash
变量 $ GLOBIGNORE
来完全阻止文件名扩展
#!/bin/bash
GLOBIGNORE="*"
curl_opts="-s --noproxy * -O"
curl $curl_opts "$1" ## no filename expansion
应用原始示例:
me$ FOO="BAR * BAR"
me$ echo $FOO
BAR file1 file2 file3 file4 BAR
me$ set -f
me$ echo $FOO
BAR * BAR
me$ set +f
me$ GLOBIGNORE=*
me$ echo $FOO
BAR * BAR
FOO='BAR * BAR'
echo "$FOO"
echo "$FOO"
在命令行中使用 printf
而不是 echo
的习惯可能是值得的。
在这个例子中,它并没有带来太多好处,但对于更复杂的输出它可能更有用。
FOO="BAR * BAR"
printf %s "$FOO"