如何在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是不够的。 您还需要引用variables引用:

 me$ FOO="BAR * BAR" me$ echo "$FOO" BAR * BAR 

简短的回答

像其他人所说 – 你应该总是引用variables来防止奇怪的行为。 所以使用回声“$ foo”而不是只是echo $ foo

很长的答案

我认为这个例子值得进一步的解释,因为这个例子的表面上看起来更多。

我可以看到你的困惑来自哪里,因为在你运行你的第一个例子之后,你可能会认为shell很明显在做:

  1. 参数扩展
  2. 文件名扩展

所以从你的第一个例子:

 me$ FOO="BAR * BAR" me$ echo $FOO 

参数展开后相当于:

 me$ echo BAR * BAR 

文件名扩展后相当于:

 me$ echo BAR file1 file2 file3 file4 BAR 

如果你只是在命令行中inputecho BAR * BAR ,你会发现它们是相同的。

所以你可能以为自己“如果我逃避*,我可以防止文件名扩展”

所以从你的第二个例子:

 me$ FOO="BAR \* BAR" me$ echo $FOO 

参数展开后应该等同于:

 me$ echo BAR \* BAR 

文件名扩展后应该等同于:

 me$ echo BAR \* BAR 

如果您尝试直接在命令行中input“echo BAR \ * BAR”,它确实会打印“BAR * BAR”,因为文件名扩展被转义阻止。

那为什么用$ foo不行?

这是因为有第三个扩展发生 – 报价清除。 从bash手工报价删除是:

在前面的扩展之后,去除了不是由上述扩展之一产生的所有未加引号的字符'\','''和'''。

因此,当你直接在命令行中input命令时,会发生什么情况:转义字符不是先前扩展的结果,因此BASH在将它发送到echo命令之前将其删除,但在第二个示例中,“\ *”为之前参数扩展的结果,所以不会被删除。 结果,echo收到“\ *”,这就是它打印的内容。

注意第一个例子之间的区别 – “*”不包括在将被删除报价删除的字符中。

我希望这是有道理的。 最后的结论是一样的 – 只是用引号。 我只是想我会解释为什么转义,如果只有参数和文件名扩展在起作用,逻辑上应该工作,没有工作。

有关BASH扩展的完整说明,请参阅:

http://www.gnu.org/software/bash/manual/bashref.html#Shell-Expansions

我会添加一点这个旧的线程。

通常你会使用

 $ echo "$FOO" 

不过,即使使用这种语法,我也遇到了问题。 考虑下面的脚本。

 #!/bin/bash curl_opts="-s --noproxy * -O" curl $curl_opts "$1" 

*需要逐字传递,否则会出现同样的问题。 上面的例子将不起作用(它将扩展到当前目录中的文件名),也不会\* 。 您也不能引用$curl_opts因为它会被识别为单个(无效)选项来curl

 curl: option -s --noproxy * -O: is unknown curl: try 'curl --help' or 'curl --manual' for more information 

因此,我build议使用bashvariables$GLOBIGNORE来防止文件扩展,如果应用于全局模式,或使用set -f内置标志。

 #!/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"