如何在变量中存储命令并在管道中使用它?

时间:2016-04-23 16:42:47

标签: bash variables grep pipeline

如果我在管道中使用此命令,它可以正常工作;

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

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

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

如果我将变量放入管道中;

pipeline ... | $var
没有任何反应,就像没有任何匹配一样。

任何帮助我做错了什么?

2 个答案:

答案 0 :(得分:3)

你做错了是试图在变量中存储命令。为简单起见,鲁棒性等命令存储在别名(如果没有参数)或函数(如果参数)中,而不是变量中。在这种情况下:

$ alias foo='grep X'
$ echo "aXb" | foo
aXb

我建议你阅读Chris Johnson ASAP的Shell Scripting Recipes一书来获取shell编程的基础知识,然后是Arnold Robbins的Effective Awk Programming,第4版,当你准备开始编写脚本来操作文本时。

答案 1 :(得分:3)

在Bash中的变量中存储 简单命令的强大方法是使用数组

# 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[@]}"

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

# Define a function encapsulating the command...
myGrep() { grep -P '^[^\s]*\s3\s'; }

# ... and use it:
echo 'before 3 after' | myGrep

为什么您尝试的不起作用

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

导致正则表达式周围的单引号成为$var值的文字,嵌入部分。

当您使用$var - unquoted - 作为命令时,会发生以下情况:

  • Bash执行分词,这意味着它通过空格(在特殊变量$var中定义的字符)将$IFS的值分解为单词(单独的标记),其中包含默认情况下,空格,制表符和换行符。)

    • Bash还对生成的作品执行 globbing (路径名扩展),这在这里不是问题,但一般会产生意想不到的后果。
    • 此外,如果您的任何原始参数具有嵌入空格,则分词会将它们拆分为多个字,并且您的原始参数分区将丢失。
      • (暂且不说:"$var" - 即,双引号变量引用 - 不是一个解决方案,因为那时整个< / em> string被视为命令 name 。)
  • 具体来说,结果是:

    • grep
    • -P
    • '^[^\s]*\s3\s' - 包括周围的单引号
  • 然后将这些单词解释为命令及其参数的名称,并按原样调用。

    • 鉴于传递给grep的模式参数以 literal 单引号开头,匹配不会按预期工作。

没有使用eval "$var" - 不建议出于安全原因 - 你无法说服Bash将嵌入式单引号视为语法元素应该是删除(适当的流程称为报价删除)。

使用数组通过将参数存储在单个元素中并让Bash以"${cmd[@]}"强大地将它们组合成命令来绕过所有这些问题。