4

如何从bash包含管道的数组运行命令行?

例如,我想ls | grep x通过以下方式运行:

$ declare -a pipeline
$ pipeline=(ls)
$ pipeline+=("|")
$ pipeline+=(grep x)
$ "${pipeline[@]}"

但我明白了:

ls: cannot access |: No such file or directory
ls: cannot access grep: No such file or directory
ls: cannot access x: No such file or directory
4

3 回答 3

4

简短形式:你不能(不写一些代码),它是一个特性,而不是一个错误。

如果您以安全的方式做事,那么您就是在保护您的数据不被解析为代码(语法)。但是,您在这里明确想要的是将数据视为代码,但只能以受控方式。

您可以做的是迭代元素,printf '%q ' "$element"如果它们不是管道,则使用它来获取安全引用的字符串,如果它们是,则不要替换它们。

在这样做之后,并且只有在这样做之后,您才能安全地评估输出字符串。

eval_args() {
  local outstr=''
  while (( $# )); do
    if [[ $1 = '|' ]]; then
      outstr+="| "
    else
      printf -v outstr '%s%q ' "$outstr" "$1"
    fi
    shift
  done
  eval "$outstr"
}
eval_args "${pipeline[@]}"

顺便说一句——不这样做会更安全。考虑一下您正在处理文件列表的情况,其中一个文件名为|; 攻击者可以使用此策略来注入代码。对前后数组使用单独的列表,或者只将管道的一侧设为数组并硬编码另一侧,是更好的做法。

于 2013-06-07T21:04:49.007 回答
1

关闭 - 只需添加eval

$ eval ${pipeline[@]}
于 2013-06-07T20:49:12.127 回答
0

这对我有用:

bash -c  "${pipeline[*]}"
于 2013-06-07T20:55:54.983 回答