如何在bash中转义通配符/星号字符?
例如:如何在bash中转义通配符/星号字符?,bash,shell,escaping,Bash,Shell,Escaping,例如: 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时引用是不够的。您还需要引用变量引用: FOO='BAR * BAR' echo "$FOO" me$ FOO="BAR * BAR" me$ echo "$FOO" BAR * B
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
时引用是不够的。您还需要引用变量引用:
FOO='BAR * BAR'
echo "$FOO"
me$ FOO="BAR * BAR"
me$ echo "$FOO"
BAR * BAR
养成在命令行上使用
printf
而不是echo
的习惯可能是值得的
在本例中,它并没有带来太多好处,但对于更复杂的输出,它可能更有用
FOO="BAR * BAR"
printf %s "$FOO"
简短回答
正如其他人所说,你应该总是引用变量来防止奇怪的行为。因此,在中使用echo“$foo”,而不仅仅是echo$foo 长答案 我确实认为这个例子值得进一步解释,因为它所发生的事情比表面上看起来的要多 我可以看出您的困惑之处,因为在运行第一个示例后,您可能会认为shell显然在做:
me$ FOO="BAR * BAR"
me$ echo $FOO
参数展开后相当于:
me$ echo BAR * BAR
me$ echo BAR file1 file2 file3 file4 BAR
me$ echo BAR \* BAR
me$ echo BAR \* BAR
文件名扩展后,等效于:
me$ echo BAR * BAR
me$ echo BAR file1 file2 file3 file4 BAR
me$ echo BAR \* BAR
me$ echo BAR \* BAR
如果您只是在命令行中键入echobar*BAR
,您将看到它们是等效的
所以你可能会想“如果我逃过了*,我可以阻止文件名的扩展”
从你的第二个例子来看:
me$ FOO="BAR \* BAR"
me$ echo $FOO
参数展开后应等于:
me$ echo BAR * BAR
me$ echo BAR file1 file2 file3 file4 BAR
me$ echo BAR \* BAR
me$ echo BAR \* BAR
文件名扩展后应相当于:
me$ echo BAR * BAR
me$ echo BAR file1 file2 file3 file4 BAR
me$ echo BAR \* BAR
me$ echo BAR \* BAR
如果您尝试直接在命令行中键入“echo BAR\*BAR”,它确实会打印“BAR*BAR”,因为转义阻止了文件名的扩展
那么为什么使用$foo不起作用呢
这是因为有第三个扩展正在发生-报价删除。从bash手册中删除报价是:
在前面的扩展之后,所有
字符的非引号引用
“\”、“”、和“”,但没有结果
从上面的扩展之一是
删除
因此,当您直接在命令行中键入命令时,转义字符不是上一次扩展的结果,因此BASH在将其发送到echo命令之前将其删除,但在第二个示例中,“\*”是上一次参数扩展的结果,因此不会删除。因此,echo接收\*“这就是它打印的内容
请注意,第一个示例-“*”之间的差异不包括在将通过删除引号删除的字符中
我希望这是有道理的。最后的结论是一样的——只要用引号就行了。我只是想解释一下为什么转义不起作用,如果只有参数和文件名扩展在起作用的话,转义在逻辑上应该起作用
有关BASH扩展的完整说明,请参阅:
我将在这个旧线程中添加一点 通常你会使用
$ echo "$FOO"
然而,即使使用这种语法,我也遇到了问题。考虑下面的脚本。
#!/bin/bash
curl_opts="-s --noproxy * -O"
curl $curl_opts "$1"
*
需要逐字传递给curl
,但同样的问题也会出现。上面的示例不起作用(它将扩展到当前目录中的文件名),而且\*
也不起作用。您也不能引用$curl\u opts
,因为它将被识别为curl
的单个(无效)选项
curl: option -s --noproxy * -O: is unknown
curl: try 'curl --help' or 'curl --manual' for more information
因此,如果应用于全局模式,我建议使用bash
变量$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
如果您不想为来自bash的奇怪扩展而烦恼,您可以这样做
me$ FOO="BAR \x2A BAR" # 2A is hex code for *
me$ echo -e $FOO
BAR * BAR
me$
在此解释为什么使用echo的-e选项会使生活更轻松:
文中相关引用:
SYNOPSIS
echo [SHORT-OPTION]... [STRING]...
echo LONG-OPTION
DESCRIPTION
Echo the STRING(s) to standard output.
-n do not output the trailing newline
-e enable interpretation of backslash escapes
-E disable interpretation of backslash escapes (default)
--help display this help and exit
--version
output version information and exit
If -e is in effect, the following sequences are recognized:
\\ backslash
...
\0NNN byte with octal value NNN (1 to 3 digits)
\xHH byte with hexadecimal value HH (1 to 2 digits)
对于十六进制代码,您可以查看man ascii页面(八进制第一行,十进制第二行,十六进制第三行):
这是可行的,但将第一行的单引号改为双引号并不是必需的。不,不是这样,但当您要包含特殊的shell字符且不需要任何替换时,使用单引号的习惯更可取。见鬼,为什么?printf是一个独立的进程(至少不是内置的bash),您演示的printf的使用没有echo的好处。printf是一个内置的bash,我在回答中说过“在这个例子中,它没有带来太多的好处,但它可以更有用,更复杂的输出。伟大的答案!现在我不觉得我问了这么愚蠢的问题。:-)对于特殊字符的转义有一些实用程序?“你应该总是引用变量以防止奇怪的行为”--当你想将它们用作字符串时,也可以使用上面@finnw up的答案直接回答这个问题,这个答案更能解释为什么,这有助于推断在我们自己的场景中如何使用。这是我们需要更多了解的答案。非常好的解释,谢谢!我的用例是
SELECT*FROM等。
,这是唯一有效的方法。感谢您介绍set-f解决方案!这很神秘,为什么?这是怎么回事?因为变量展开它不仅仅是变量展开,它也是特殊的字符展开(请参阅)或阅读下文以完全理解细微差别