如何在bash中转义通配符/星号字符?
例如。
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='BAR * BAR' echo "$FOO"
echo "$FOO"
设置$ FOO时引用还不够。我们还需要引用变量引用:
me$ FOO="BAR * BAR" me$ echo "$FOO" BAR * BAR
可能值得养成在命令行上使用printf
而不是echo
的习惯。
在此示例中,它并没有带来太多好处,但是对于更复杂的输出,它可能会更有用。
FOO="BAR * BAR" printf %s "$FOO"
短答案
就像其他人所说的那样,我们应始终引用变量以防止出现奇怪的行为。因此,使用echo" $ foo"代替echo $ foo。
长答案
我确实认为此示例值得进一步解释,因为正在进行的事情比它看上去的更多。
我可以看到我们困惑的地方,因为在运行第一个示例后,我们可能会以为自己外壳显然在做:
- 参数扩展
- 文件名扩展
因此,从第一个示例:
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
在扩展文件名之后,该命令应等效于:
me$ echo BAR \* BAR
并且,如果我们尝试直接在命令行中键入" echo BAR \ * BAR",则实际上将打印" BAR * BAR",因为转义阻止了文件名扩展。
那么为什么不使用$ foo呢?
这是因为发生了第三个扩展,即报价删除。从bash手动删除报价是:
After the preceding expansions, all unquoted occurrences of the characters ‘\’, ‘'’, and ‘"’ that did not result from one of the above expansions are removed.
因此,发生的情况是,当我们直接在命令行中键入命令时,转义字符不是先前扩展的结果,因此BASH在将其发送给echo命令之前将其删除,但是在第二个示例中," \ *"为之前的参数扩展的结果,因此不会将其删除。结果,echo接收到" \ *",这就是它的输出内容。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
请注意,第一个示例" *"之间的区别不包括在将被"引号删除"删除的字符中。
我希望这是有道理的。最后,在相同的结论只是使用引号。我只是想解释一下为什么转义不起作用,而转义在逻辑上仅在参数和文件名扩展起作用时才有效。
有关BASH扩展的完整说明,请参阅:
http://www.gnu.org/software/bash/manual/bashref.html#Shell-Expansions