Arrays 使用管道运行bash数组
如何从包含管道的Arrays 使用管道运行bash数组,arrays,bash,pipeline,Arrays,Bash,Pipeline,如何从包含管道的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
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
关闭-只需添加
eval
:
$ eval ${pipeline[@]}
这对我很有用:
bash -c "${pipeline[*]}"
简而言之:你不能(不写一些代码),这是一个特性,不是一个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[@]}"
顺便说一下,不这样做安全多了。考虑这样一种情况,您正在处理一个文件列表,其中一个文件名为
|
;攻击者可以使用此策略注入代码。为前后数组使用单独的列表,或者只将管道的一侧作为数组并对另一侧进行硬编码,这是更好的做法。但这非常脆弱且容易出错,因为空格、引号和星号等可以在多个阶段进行处理。这不是shell脚本的全部内容吗?;-)@CarlNorum不,shell脚本不是关于免费的安全漏洞。不管怎么说,如果你做得对的话就不会了。我想那张眨眼的脸就到此为止吧。OP的问题没有任何这些问题。你也可以写一个答案。@CarlNorum我正在写一个。构建和测试健壮的东西需要时间。尝试一些更有趣的东西。例如:pipeline=(“cat”文件名加空格“|”tr'[a-z]'[a-z]')
;您给出的表单将文件名
、带
和空格
视为cat
@CharlesDuffy的三个不同参数,您的观点是正确的。话虽如此,OP似乎希望从命令行运行一些东西,并控制输入。不确定名称中带有空格的文件是否在UNIX上常见。总的来说,我认为您的eval_args
函数可能是一个不错的选择,我将+1它。即使包含文本字符串$(rm-rf/)
的文件名不常见,但您仍然不希望在出现这种情况时对其进行求值。数据丢失事件和安全漏洞希望是不常见的事件,但您不要因此而忽视其前驱体发生的可能性。+1,但建议不要编写这样的代码,这一点再强调也不过分。