Bash脚本只传递一个参数,但我想要多个参数。

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\"" 传递到脚本中。 如何将这个“一个参数”变成“多个参数”,同时仍然尊重组合的单词(用引号括起来)?

1个回答

3

尝试:

eval set "$@"

或者(如果可能以shell选项开头则更安全):
eval set -- "$@"

之后你应该能够使用"$@"

与所有的eval一样,这种方法有很多危险。:-)

一个危险的例子:

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

编辑:这里有一个 protect shell 函数和一个使用它的示例。我不确定是否对所有情况都进行了保护,但它可以处理两种明显的情况:

#! /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]

如果需要引用其他字符,添加到保护很明显就行了。

除了使用“eval”之外,还有其他的方法吗? - justderb
总有另一种方法。但是其他“简单”的方法呢?目前没有明显的选择。不过,将“$@”通过过滤器进行替换以替换“危险”字符(至少是美元符号和反引号)可能值得一试。我已经将其编写为测试,稍后会进行编辑。 - torek
eval 会留下四个参数,分别是 'This'、'is'、'a' 和 'test target' —— 但双引号会被移除,因为 "testtarget" 被解释并组合在一起了。但 eval 基本上已经是最好的选择了。 - Jonathan Leffler
我最终只使用了 eval。谢谢! - justderb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接