如何通过存储在单个变量中的引号传递命令行参数?

时间:2012-05-04 12:56:01

标签: linux bash shell

我想从shell脚本调用外部应用程序,但是这个shell脚本在单个变量中获取参数(来自其他脚本)。一切都没问题,直到我不必为单个参数使用双引号,而是用空格分隔的单词。

以下是我的问题的简化示例(sh_param只打印所有传递的参数):

#!/bin/sh

pass() {
    echo "Result with \$@"
    ./sh_param $@
    echo "Result with \"\$@\""
    ./sh_param "$@"
    echo "Result with \$*"
    ./sh_param $*
    echo "Result with \"\$*\""
    ./sh_param "$*"
}

pass '"single param" separate params'

和结果(sh_param只打印所有传递的参数):

Result with $@
Param: "single
Param: param"
Param: separate
Param: params
Result with "$@"
Param: "single param" separate params
Result with $*
Param: "single
Param: param"
Param: separate
Param: params
Result with "$*"
Param: "single param" separate params

我想要:

Param: single param
Param: separate
Param: params

5 个答案:

答案 0 :(得分:2)

脚本

pass() {
  echo 'Result with "$@"'
  sh_param "$@"
}

sh_param() {
  for i in "$@"
  do
    echo Param: $i
  done
}

pass "single param" separate param

结果

Result with "$@"
Param: single param
Param: separate
Param: param

答案 1 :(得分:1)

如果您遇到单个变量,则必须使用eval

$ show() { i=0; for param; do ((i++)); echo "$i>$param"; done; }

$ show '"single param" separate params'
1>"single param" separate params

$ eval show '"single param" separate params'
1>single param
2>separate
3>params

请注意,双引号会被shell吃掉。

答案 2 :(得分:1)

避免将整个事物作为单个参数传递(与squotes一样)。使shell脚本小心地保留传递的参数数量是很困难的,而不需要通过将它们展平为字符串并再次扩展它们来使其变得更难。

如果确实需要,可以遵循一些最佳做法。我不得不在一段时间内编写一个脚本作为su / sudo包装器:su接受一个参数传递给sh进行评估; sudo将任意数量的未经修改的参数传递给execv(e)。

你必须非常小心,让它可移植,而不是在晦涩的shell中遇到问题。整个脚本对于发布并不是很有用,但一般的要点是编写一些转义函数并执行引用以构建一个可以安全传递给eval的防弹,不可读 - 谨慎转义的字符串。

bash_escape() {
  # backtick indirection strictly necessary here: we use it to strip the
  # trailing newline from sed's output, which Solaris/BSD sed *always* output
  # (unlike GNU sed, which outputs "test": printf %s test | sed -e s/dummy//)
  out=`echo "$1" | sed -e s/\\'/\\''\\\\'\\'\\'/g`
  printf \'%s\' "$out"
}
append_bash_escape() {
  printf "%s " "$1"
  bash_escape "$2"
}
sed_escape() {
  out=`echo "$1" | sed -e 's/[\\/&]/\\\\&/g'`
  printf %s "$out"
}

这些有用的功能让你可以这样做,以便可移植地构建命令字符串:

COMMAND=
while [ $# -gt 0 ] ; do
  COMMAND=`append_bash_escape "$COMMAND" "$1"` ; shift
done

然后,您可以操作命令字符串,例如在其上运行bash_escape并使用sed_escape替换为字符串"su - root -c SUB_HERE",或者直接将其替换为"sudo -- SUB_HERE"之类的字符串{1}}。然后,您可以安全地eval,而不必担心元字符,参数分裂,未转义的全局等等。

偏执狂,并用你能想到的每一个讨厌的输入单元测试你的脚本,以确保你的论点分裂和保存真的是正确的!

答案 3 :(得分:0)

这可能有用,虽然在不知道sh_param如何处理其参数的情况下很难说清楚。

#!/bin/sh

pass() {
    echo "Result with \"\$@\""
    ./sh_param "$@"
}

pass "single param" separate params

答案 4 :(得分:0)

回答我自己的问题。非常感谢pzanoni。 xargs似乎正确地解析了你扔给它的任何东西:-) " $ @"," $ ",$ @和$ 很适合。所以我的代码现在看起来像:

#!/bin/sh

pass() {
    echo $* | xargs ./sh_param
}

pass '"single param" separate params'

结果就是我想要的:

Param: single param
Param: separate
Param: params