保护包含eval空格的参数

时间:2013-12-28 23:48:09

标签: linux bash shell unix eval

为了让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解释了引号。我想要文字输入,而不必从文件中读取。

4 个答案:

答案 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不是邪恶的-只是被误解了:)