如何将命令存储在变量中并在管道中使用它? [英] How do I store a command in a variable and use it in a pipeline?

查看:126
本文介绍了如何将命令存储在变量中并在管道中使用它?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  pipeline ... |如果我在管道中使用这个命令,它工作得很好; grep -P'^ [^ \s] * \s3\s'

但是,如果我想将grep设置为如下变量:

  var =grep -P'^ [^ \s] * \ s3 \'''

如果我把变量放在pipeline中;

  pipeline ... | $ var 

没有任何反应,就像没有任何匹配一样。



任何帮助我做错了什么?

解决方案

em>

pre> #分别将命令名称和参数
#存储在*数组* *的元素中。
cmd =(grep -P'^ [^ \s] * \s3\s')

#使用整个数组作为要执行的命令 - 确保
#双引号$ {cmd [@]}。
在'|之后3之前回显' $ {cmd [@]}

相反,如果您的命令更多而不是简单命令,例如,涉及管道,多个命令,循环......,定义功能 为正确的做法:

$ $ p $ #定义封装命令的函数...
myGrep(){grep -P' ^ [^ \s] * \s3\s'; }

#...并使用它:
在'|之后3之前回显' myGrep






t work:

  var =grep -P'^ [^ \s] * \s3\\ \\''

会使正则表达式中的单引号变成一个文字, / em> $ var 的值。



当你使用 $ var - 未加引号 - 作为命令,会发生以下情况:


  • Bash执行分词,这意味着它将 $ var 的值由空格(特殊变量<$ c $中定义的字符)拆分为单词(单独的标记) c> $ IFS ,默认情况下它包含空格,制表符和换行符)。 Bash也对结果作品执行 globbing (路径名扩展),这在这里不是问题,但可能会产生意想不到的后果。 你的原始参数已嵌入 em> whitespace,单词拆分会将它们拆分成多个单词,并且原始参数分区会丢失。


    • (另外:$ var - 即双引号变量引用 - 不是解决方案,因为整个字符串被视为命令 name 。)



  • 具体来说,结果是:


    • grep

    • -P '^ [^ \ s] * \ s3 \ s' - 包括 em>周围的单引号


  • 然后将单词解释为命令及其参数的名称,并调用为


    • 假设传递给 grep 的模式参数以



  • 单引号, p>使用 eval$ var - 由于安全原因而不推荐使用 - 您无法说服Bash查看嵌入的
    单引用为应该被删除的语法元素(一个适当的称为引用删除的过程)。



    使用数组绕过所有这些问题都通过将参数存储在单独的元素中,并让Bash强健地将它们组装成一个带有$ {cmd [@]}的命令


    If i use this command in pipeline, it's working very well;

    pipeline ... | grep -P '^[^\s]*\s3\s'
    

    But if I want to set grep into variable like:

    var="grep -P '^[^\s]*\s3\s'"
    

    And if I put variable in pipeline;

    pipeline ... | $var
    

    nothing happens, like there isn't any matches.

    Any help what am I doing wrong?

    解决方案

    The robust way to store a simple command in a variable in Bash is to use an array:

    # Store the command names and arguments individually
    # in the elements of an *array*.
    cmd=( grep -P '^[^\s]*\s3\s' )
    
    # Use the entire array as the command to execute - be sure to
    # double-quote ${cmd[@]}.
    echo 'before 3 after' | "${cmd[@]}"
    

    If, by contrast, your command is more than a simple command and, for instance, involves pipes, multiple commands, loops, ..., defining a function is the right approach:

    # Define a function encapsulating the command...
    myGrep() { grep -P '^[^\s]*\s3\s'; }
    
    # ... and use it:
    echo 'before 3 after' | myGrep
    


    Why what you tried didn't work:

    var="grep -P '^[^\s]*\s3\s'"
    

    causes the single quotes around the regex to become a literal, embedded part of $var's value.

    When you then use $var - unquoted - as a command, the following happens:

    • Bash performs word-splitting, which means that it breaks the value of $var into words (separate tokens) by whitespace (the chars. defined in special variable $IFS, which contains a space, a tab, and a newline character by default).

      • Bash also performs globbing (pathname expansion) on the resulting works, which is not a problem here, but can have unintended consequences in general.
      • Also, if any of your original arguments had embedded whitespace, word splitting would split them into multiple words, and your original argument partitioning is lost.
        • (As an aside: "$var" - i.e., double-quoting the variable reference - is not a solution, because then the entire string is treated as the command name.)
    • Specifically, the resulting words are:

      • grep
      • -P
      • '^[^\s]*\s3\s' - including the surrounding single quotes
    • The words are then interpreted as the name of the command and its arguments, and invoked as such.

      • Given that the pattern argument passed to grep starts with a literal single quote, matching won't work as intended.

    Short of using eval "$var" - which is NOT recommended for security reasons - you cannot persuade Bash to see the embedded single quotes as syntactical elements that should be removed (a process appropriate called quote removal).

    Using an array bypasses all these problems by storing arguments in individual elements and letting Bash robustly assemble them into a command with "${cmd[@]}".

    这篇关于如何将命令存储在变量中并在管道中使用它?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    相关文章
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆