Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/shell/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在bash中转义通配符/星号字符?_Bash_Shell_Escaping - Fatal编程技术网

如何在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解决方案!这很神秘,为什么?这是怎么回事?因为变量展开它不仅仅是变量展开,它也是特殊的字符展开(请参阅)或阅读下文以完全理解细微差别