4

我有这个简单的脚本来打印它收到的内容然后退出:

IFS="|${IFS}";
echo "$# parameters";
echo Using '$*';
for p in $*;
do
    echo "[$p]";
done;
echo Using '"$*"';
for p in "$*";
do
    echo "[$p]";
done;
echo Using '$@';
for p in $@;
do
    echo "[$p]";
done;
echo Using '"$@"';
for p in "$@";
do
    echo "[$p]";
done

如果我执行:./echoparams This is a "test target"它将打印出:

4 parameters
Using $*
[This]
[is]
[a]
[Test]
[target]
Using "$*"
[This|is|a|Test target]
Using $@
[This]
[is]
[a]
[Test]
[target]
Using "$@"
[This]
[is]
[a]
[Test target]

问题:

我有一个外部程序(我无法修改)将它传递到我的脚本中,但是当它执行时它会打印出这个:

1 parameters
Using $*
[This]
[is]
[a]
["test]
[target"]
Using "$*"
[This is a "test target"]
Using $@
[This]
[is]
[a]
["test]
[target"]
Using "$@"
[This is a "test target"]

我有一种预感,它实际上正在传递"This is a \"test target\""到脚本中。 我怎样才能把这个“一个参数”变成“多个参数”,但仍然尊重组合词(用引号括起来)?

4

1 回答 1

3

尝试:

eval set "$@"

或(如果它可能以 shell 选项开头,则更安全):

eval set -- "$@"

之后,您应该可以使用"$@".

和所有eval的s一样,这有各种各样的危险。:-)

危险示例:

$ set '`ls`'
$ eval set -- "$@"
$ echo $#
28
$ echo "$1"
COPYRIGHT

编辑:这是一个protectshell函数和一个使用它的例子。我不确定我是否保护了一切,但它有两个明显的情况:

#! /usr/bin/env bash

protect()
{
    local quoted

    quoted="${1//$/\\\$}"
    quoted="${quoted//\`/\\\`}"
    # use printf instead of echo in case $1 is (eg) -n
    printf %s "$quoted"
}

foo=expanded

set -- '-e -n $foo `ls` "bar baz"'
eval set -- "$@"
echo "without protect, \$# is $#:"
for arg do echo "[$arg]"; done

set -- '-e -n $foo `ls` "bar baz"'
eval set -- $(protect "$@")
echo "with protect, \$# is $#"
for arg do echo "[$arg]"; done

当我运行它时:

without protect, $# is 46:
[-e]
[-n]
[expanded]
[OUT]
[a.py]
[ast_ex.py]
  ---snipped remaining ls output for space reasons---
[bar baz]
with protect, $# is 5
[-e]
[-n]
[$foo]
[`ls`]
[bar baz]

如果其他字符需要引用,很明显如何将它们添加到protect.

于 2013-08-28T18:00:56.030 回答