如何在bash中转义通配符/星号字符?

时间:2020-03-06 14:26:03  来源:igfitidea点击:

例如。

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