如何在 bash 中转义通配符/星号?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/102049/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I escape the wildcard/asterisk character in bash?
提问by andyuk
For example:
例如:
me$ FOO="BAR * BAR"
me$ echo $FOO
BAR file1 file2 file3 file4 BAR
and using the \
escape character:
并使用\
转义字符:
me$ FOO="BAR \* BAR"
me$ echo $FOO
BAR \* BAR
I'm obviously doing something stupid.
我显然在做一些愚蠢的事情。
How do I get the output BAR * BAR
?
我如何获得输出BAR * BAR
?
回答by finnw
Quoting when setting $FOO
is not enough. You need to quote the variable reference as well:
设置$FOO
不够时引用。您还需要引用变量引用:
me$ FOO="BAR * BAR"
me$ echo "$FOO"
BAR * BAR
回答by mithu
SHORT ANSWER
简答
Like others have said - you should always quote the variables to prevent strange behaviour. So use echo "$foo"in instead of just echo $foo.
就像其他人所说的那样 - 您应该始终引用变量以防止出现奇怪的行为。所以使用echo "$foo"而不仅仅是echo $foo。
LONG ANSWER
长答案
I do think this example warrants further explanation because there is more going on than it might seem on the face of it.
我确实认为这个例子值得进一步解释,因为发生的事情比表面上看起来要多。
I can see where your confusion comes in because after you ran your first example you probably thought to yourself that the shell is obviously doing:
我可以看出您的困惑在哪里,因为在您运行第一个示例之后,您可能认为 shell 显然在做:
- Parameter expansion
- Filename expansion
- 参数扩展
- 文件名扩展
So from your first example:
所以从你的第一个例子:
me$ FOO="BAR * BAR"
me$ echo $FOO
After parameter expansion is equivalent to:
参数展开后等价于:
me$ echo BAR * BAR
And after filename expansion is equivalent to:
并且经过文件名扩展后相当于:
me$ echo BAR file1 file2 file3 file4 BAR
And if you just type echo BAR * BAR
into the command line you will see that they are equivalent.
如果你只是echo BAR * BAR
在命令行中输入,你会看到它们是等价的。
So you probably thought to yourself "if I escape the *, I can prevent the filename expansion"
所以你可能想过“如果我转义 *,我可以防止文件名扩展”
So from your second example:
所以从你的第二个例子:
me$ FOO="BAR \* BAR"
me$ echo $FOO
After parameter expansion should be equivalent to:
参数展开后应等价于:
me$ echo BAR \* BAR
And after filename expansion should be equivalent to:
并且在文件名扩展之后应该相当于:
me$ echo BAR \* BAR
And if you try typing "echo BAR \* BAR" directly into the command line it will indeed print "BAR * BAR" because the filename expansion is prevented by the escape.
如果您尝试直接在命令行中键入“echo BAR \* BAR”,它确实会打印“BAR * BAR”,因为转义阻止了文件名扩展。
So why did using $foo not work?
那么为什么使用 $foo 不起作用?
It's because there is a third expansion that takes place - Quote Removal. From the bash manual quote removal is:
这是因为发生了第三次扩展 - 报价删除。从 bash 手动引用删除是:
After the preceding expansions, all unquoted occurrences of the characters ‘\', ‘'', and ‘"' that did not result from one of the above expansions are removed.
在前面的扩展之后,所有不是由上述扩展之一产生的字符 '\'、''' 和 '"' 的所有未加引号的出现都将被删除。
So what happens is when you type the command directly into the command line, the escape character is not the result of a previous expansion so BASH removes it before sending it to the echo command, but in the 2nd example, the "\*" was the result of a previous Parameter expansion, so it is NOT removed. As a result, echo receives "\*" and that's what it prints.
因此,当您直接在命令行中键入命令时,转义字符不是先前扩展的结果,因此 BASH 在将其发送到 echo 命令之前将其删除,但在第二个示例中,“\*”是先前参数扩展的结果,因此不会被删除。结果,echo 收到“\*”,这就是它打印的内容。
Note the difference between the first example - "*" is not included in the characters that will be removed by Quote Removal.
请注意第一个示例之间的区别 - "*" 不包含在将被 Quote Removal 删除的字符中。
I hope this makes sense. In the end the conclusion in the same - just use quotes. I just thought I'd explain why escaping, which logically should work if only Parameter and Filename expansion are at play, didn't work.
我希望这是有道理的。最后的结论是一样的 - 只需使用引号。我只是想我会解释为什么转义,如果只有参数和文件名扩展在起作用,逻辑上应该起作用,但不起作用。
For a full explanation of BASH expansions, refer to:
有关 BASH 扩展的完整说明,请参阅:
http://www.gnu.org/software/bash/manual/bashref.html#Shell-Expansions
http://www.gnu.org/software/bash/manual/bashref.html#Shell-Expansions
回答by AlexandreH
I'll add a bit to this old thread.
我会在这个旧线程中添加一点。
Usually you would use
通常你会使用
$ echo "$FOO"
However, I've had problems even with this syntax. Consider the following script.
但是,即使使用这种语法,我也遇到了问题。考虑以下脚本。
#!/bin/bash
curl_opts="-s --noproxy * -O"
curl $curl_opts ""
The *
needs to be passed verbatim to curl
, but the same problems will arise. The above example won't work (it will expand to filenames in the current directory) and neither will \*
. You also can't quote $curl_opts
because it will be recognized as a single (invalid) option to curl
.
在*
需要传递逐字到curl
,但也会出现同样的问题。上面的示例将不起作用(它将扩展为当前目录中的文件名)并且\*
. 您也不能引用,$curl_opts
因为它将被识别为curl
.
curl: option -s --noproxy * -O: is unknown
curl: try 'curl --help' or 'curl --manual' for more information
Therefore I would recommend the use of the bash
variable $GLOBIGNORE
to prevent filename expansion altogether if applied to the global pattern, or use the set -f
built-in flag.
因此,如果应用于全局模式或使用内置标志,我建议使用该bash
变量$GLOBIGNORE
来完全防止文件名扩展set -f
。
#!/bin/bash
GLOBIGNORE="*"
curl_opts="-s --noproxy * -O"
curl $curl_opts "" ## no filename expansion
Applying to your original example:
适用于您的原始示例:
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
回答by tzot
FOO='BAR * BAR'
echo "$FOO"
回答by Dave Webb
It may be worth getting into the habit of using printf
rather then echo
on the command line.
养成在命令行上使用printf
而不是使用的习惯可能是值得的echo
。
In this example it doesn't give much benefit but it can be more useful with more complex output.
在这个例子中,它没有带来太多好处,但对于更复杂的输出它可能更有用。
FOO="BAR * BAR"
printf %s "$FOO"
回答by Rafa? Dowgird
echo "$FOO"