8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

为什么 shell 会忽略通过变量传递给它的参数中的引号字符?

Alex Fedulov 1月前

7 0

这些按照广告宣传的那样工作:grep -ir 'hello world' .grep -ir hello\ world .这些不行:argumentString1=\'-ir 'hello world'\'argumentString2=\'-ir hello\\ world\'grep $argumentSt...

这些产品的效果正如广告所宣传的:

grep -ir 'hello world' .
grep -ir hello\ world .

这些不:

argumentString1="-ir 'hello world'"
argumentString2="-ir hello\\ world"
grep $argumentString1 .
grep $argumentString2 .

尽管 'hello world' 在第二个示例中被引号括起来,但 grep 将 'hello (and hello\ ) 解释为一个参数,将 world' (and world ) 解释为另一个参数,这意味着,在这种情况下, 'hello 将是搜索模式,并且 world' 将是搜索路径。

同样,只有当参数从变量中扩展时,才会发生这种情况 argumentString 。在第一个示例中,grep 正确地将 'hello world' (和 hello\ world ) 解释为单个参数。

有人能解释一下这是为什么吗? 有没有一种适当的方法来扩展字符串变量,以保留每个字符的语法,以便 shell 命令可以正确解释它?

帖子版权声明 1、本帖标题:为什么 shell 会忽略通过变量传递给它的参数中的引号字符?
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由Alex Fedulov在本站《maven》版块原创发布, 转载请注明出处!
最新回复 (0)
  • 我应该注意这与 grep 本身没有任何关系;这更多的是一个 bash 问题(使用任何其他命令都有相同的效果)

  • zolo 1月前 0 只看Ta
    引用 3

    为什么

    当字符串被扩展时,它会被拆分成单词,但不会重新评估以查找特殊字符,例如引号或美元符号等...自 1978 年左右的 Bourne shell 以来,这是 shell '一直' 的行为方式。

    使固定

    在中 bash ,使用数组来保存参数:

    argumentArray=(-ir 'hello world')
    grep "${argumentArray[@]}" .
    

    或者,如果勇敢/鲁莽,使用 eval

    argumentString="-ir 'hello world'"
    eval "grep $argumentString ."
    

    另一方面,谨慎往往是勇气的重要组成部分,而与人合作时, eval 谨慎比勇敢更重要。如果您不能完全控制 eval 'd 字符串(如果命令字符串中有任何用户输入未经严格验证),那么您将面临潜在的严重问题。

    请注意,Bash 的扩展顺序在 Shell 扩展 。请特别注意第 3.5.3 节 Shell 参数扩展、第 3.5.7 节单词拆分和第 3.5.9 节引号删除。

  • 或者,“那就别这么做”。mywiki.wooledge.org/BashFAQ/050

  • 如果我们要展示如何使用 eval,不妨展示如何正确使用它。我认为正确使用 eval 总是需要向其传递一个字符串——否则,您将用空格连接所有参数,这会以令人惊讶的方式变得混乱。比较一下 eval printf '%s\n' \'hello world\' 与 eval 'printf \'%s\n\' \'hello world\'',这是一个典型的例子,说明为什么向 eval 传递多个参数会导致混乱。

  • 为什么 grep \'${argumentArray[@]}\' . 中的引号不会导致数组作为单个参数传递?我原本希望它改为 grep ${argumentArray[@]} . ,但实际上似乎两者都有效?

  • @natevw:原因大致与 \'$@\' 生成的是参数列表而不是单个字符串相同(\'$*\' 生成的是单个字符串,\'${array[*]}\' 也是如此)。为什么 \'$@\' 会这样?因为自古以来就是这样(或者至少自 1978 年左右的第 7 版 Unix 开始,引入了 Bourne shell)。

  • @JonathanLeffler 我想要一个针对此答案的规范常见问题解答,不仅限于引用。我应该发布一个新问题吗?

  • 当您将引号字符放入变量时,它们就变成了普通的文字(请参阅 http://mywiki.wooledge.org/BashFAQ/050 ;感谢 @tripleee 指出此链接)

    相反,尝试使用数组来传递参数:

    argumentString=(-ir 'hello world')
    grep "${argumentString[@]}" .
    
  • 引用 10

    在查看此问题和相关问题时,我很惊讶没有人提出使用显式子 shell。对于 bash 和其他现代 shell,您可以显式执行命令行。在 bash 中,它需要 -c 选项。

    argumentString="-ir 'hello world'"
    bash -c "grep $argumentString ."
    

    完全按照原始提问者的要求工作。此技术有两个限制:

    1. 您只能在命令或参数字符串中使用单引号。
    2. 只有导出的环境变量才可用于命令

    此外,该技术可以处理重定向和管道,其他 shellism 也可以正常工作。您还可以使用 bash 内部命令以及在命令行上运行的任何其他命令,因为您实际上是在要求子 shell bash 将其直接解释为命令行。这是一个更复杂的例子,一个有点不必要的复杂 ls -l 变体。

    cmd="prefix=`pwd` && ls | xargs -n 1 echo \'In $prefix:\'"
    bash -c "$cmd"
    

    我曾用这种方式和参数数组构建过命令处理器。通常,这种方式容易编写和调试,而且回显正在执行的命令也很简单。另一方面,当你确实有抽象的参数数组时,参数数组会很好地工作,而不是只想要一个简单的命令变体。

  • 命令中可以使用单引号和双引号。就像在命令行中输入一样。cmd='x=\' a \''\''$PATH'\''\' b \''; echo \'<$cmd>\'; bash -c \'$cmd; echo \\'\$x\\'\'

  • 引用 12

    \'Subshel​​l\',作为一个术语,是指由 fork() 创建的 shell,没有 exec() - 您可以从管道、命令替换、进程扩展和许多其他构造中隐式创建它们。相比之下,当您运行 bash -c '...' 时,这只是一个碰巧是 shell 的常规子进程。

返回
作者最近主题: