如何从包含管道的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
答案 0 :(得分:4)
简短形式:你不能(不写一些代码),这是一个功能,而不是一个bug。
如果您以安全的方式做事,那么您将保护您的数据不被解析为代码(语法)。但是,您在此明确要求的是将数据视为代码,但仅以受控方式处理。
你可以做的是迭代元素,如果它们不是管道,使用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[@]}"
顺便说一下,不要这样做更安全。考虑一下您正在处理文件列表的情况,其中一个名为|
;攻击者可以使用此策略来注入代码。对前后数组使用单独的列表,或者只为管道的一侧创建一个数组并对另一个进行硬编码,这是更好的做法。
答案 1 :(得分:1)
关闭 - 只需添加eval
:
$ eval ${pipeline[@]}
答案 2 :(得分:0)
这对我有用:
bash -c "${pipeline[*]}"