为了让eval能够处理其中一个参数中包含空格的命令,我到目前为止只发现了这个:
eval 'sed 's/foo/foo'" "'bar/g' filename'
在一个假设的程序中,用户输入命令,然后输入命令和参数给eval,这不是一个非常优雅或强大的解决方案。有没有其他方法可以运行eval命令,以便my_command的界面可以更加用户友好?以下是程序现在如何接受参数的示例。
my_command 'sed 's/foo/foo'" "'bar/g' filename'
我希望界面能够像这样工作:
my_command sed 's/foo/foo bar/g' filename
编辑:
我会尝试提出另一个问题:
如何让bash从字面上读取命令行的输入?我想要保留确切的输入,所以如果有引号我想保留它们。我可以通过使用egrep从文件中读取然后清理输入来完成我想要做的事情,如下所示:
egrep '/.*/' filename |
sed 's/\(.*\)['"'"']\(.*\) \(.*\)['"'"']\(.*\)/\1'"\'"'\2" "\3'"\'"'\4/g'
包含此行的“filename”
sed 's/foo/foo bar/g' file
这给了我想要的输出:
sed 's/foo/foo" "bar/g' file
这里的问题是我不能echo "$@"
因为bash解释了引号。我想要文字输入,而不必从文件中读取。
答案 0 :(得分:4)
对于您的首选用例,您只需编写(在my_command
内):
"$@"
执行给定的命令。
您的eval
行是奇怪的:
eval 'sed 's/foo/foo'" "'bar/g' filename'
由于单引号不嵌套的方式,它等同于:
eval 'sed s/foo/foo" "bar/g filename'
可能的解决方案:
egrep '/.*/' filename | sh
将filename
中的内容直接提供给shell进行解释。给定file
包含:
Some text containing foo; and bar.
More foo bar?
More text; more foo and bar; more foo bar beyond the possibility of unfooing.
输出结果为:
Some text containing foo bar; and bar.
More foo bar bar?
More text; more foo bar and bar; more foo bar bar beyond the possibility of unfoo baring.
请注意,复杂的sed
脚本不够复杂。给定filename
包含:
sed 's/foo/foo bar/g' file
sed 's/foo bar/foo bar baz/g' file
来自:
的输出egrep '/.*/' filename |
sed 's/\(.*\)['"'"']\(.*\) \(.*\)['"'"']\(.*\)/\1'"\'"'\2" "\3'"\'"'\4/g'
是:
sed 's/foo/foo" "bar/g' file
sed 's/foo bar/foo bar" "baz/g' file
尚未解决eval
的所有问题。
我花了很多时间,不停地在很长一段时间内处理这些问题(四分之一世纪毫不夸张),这并非微不足道。您可以在How to iterate over arguments in bash script中以扩展名找到一个讨论。在某个地方,我有另一个答案,通过对这些东西的旋转,但我不能立即找到它('立即'意味着一小时左右的分心搜索,其中分心是一组重复的问题,等等)。它可能已被删除,或者我可能已经找错了地方。
答案 1 :(得分:1)
你的设计存在缺陷。创建一个不允许他们直接输入命令的用户界面。给出选项,或让他们只输入参数。
在后端,您需要在调用sed
或其他所需工具之前对参数进行清理检查。您不必使用eval
答案 2 :(得分:0)
它实际上可以按照您的意愿工作。使用"$@"
- 这将完全按照命令行给出的所有参数传递。
如果my_command.sh包含:
sed "$@"
然后my_command.sh 's/foo/foo bar/g' filename
将完全符合您的预期。
答案 3 :(得分:0)
以下内容通过引用数组的每个元素在参数中保留空格:
function token_quote {
local quoted=()
for token; do
quoted+=( "$(printf '%q' "$token")" )
done
printf '%s\n' "${quoted[*]}"
}
用法示例:
$ token_quote token 'single token' token
token single\ token token
上面,请注意single token
的空格引用为\
。
$ set $(token_quote token 'single token' token)
$ eval printf '%s\\n' "$@"
token
single token
token
$
这表明令牌确实分开存放。
提供一些不受信任的用户输入:
% input="Trying to hack you; date"
构造一个命令进行评估:
% cmd=(echo "User gave:" "$input")
用正确的报价貌似对它进行评估:
% eval "$(echo "${cmd[@]}")"
User gave: Trying to hack you
Thu Sep 27 20:41:31 +07 2018
请注意,您被黑了。 date
被执行,而不是照字面意思打印。
用token_quote()
代替:
% eval "$(token_quote "${cmd[@]}")"
User gave: Trying to hack you; date
%
eval
不是邪恶的-只是被误解了:)