使用空格引用参数以便以后执行

时间:2013-03-12 12:16:38

标签: bash shell parameters quote

我有这个(测试)脚本:

#!/bin/bash

my_cmd_bad_ ( ) {
    cmd="$@"
    $cmd
}

my_cmd_good_ ( ) {
    "$@"
}

my_cmd_bad_  ls -l "file with space"
my_cmd_good_ ls -l "file with space"

输出是(文件不存在,这个问题的要点):

» ~/test.sh
ls: cannot access file: No such file or directory
ls: cannot access with: No such file or directory
ls: cannot access space: No such file or directory
ls: cannot access file with space: No such file or directory

我很惊讶第一个版本没有按预期工作:参数没有引用,而不是处理一个文件,它处理三个。为什么呢?

如何保存我想要执行的命令,正确引用?我需要稍后执行它,我不再有"$@"

对此测试脚本的简单修改将不胜感激。

4 个答案:

答案 0 :(得分:2)

查看类似问题:How to pass command line parameters with quotes stored in single variable?

使用这些实用程序函数将命令保存到字符串以便以后执行:

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"
}

your_cmd_fixed_ ( ) {
  cmd="$@"
  while [ $# -gt 0 ] ; do
    cmd=`append_bash_escape "$cmd" "$1"` ; shift
  done
  $cmd
}

答案 1 :(得分:1)

您将三个以空格分隔的字符串“ls”,“ - l”和“带空格的文件”组合成一个以空格分隔的字符串cmd。无法知道最初引用了哪些空格(在“带空格的文件中”)以及在分配给cmd期间引入了哪些空格。

通常,尝试将命令行构建为单个字符串并不是一个好主意。使用函数或隔离实际命令并将参数保留在$@

重写命令如下:

my_cmd_bad_ () {
    cmd=$1; shift
    $cmd "$@"
}

答案 2 :(得分:1)

您可以引用任何单个参数并在以后对其进行评估:

my_cmd_bad_ ( ) {
  j=0
  for i in "$@"; do
    cmd["$j"]=\"$"$i"\"
    j=$(( $j + 1 ))
   done;
  eval ${cmd[*]}
}

答案 3 :(得分:0)

请参阅http://mywiki.wooledge.org/BashFAQ/050

请注意,您的第二个版本在大多数情况下都是首选。唯一的例外是如果你需要做一些特殊的事情。例如,您不能将赋值或重定向或复合命令捆绑到参数列表中。

处理引用问题的正确方法需要非标准功能。涉及模板的半现实示例:

function myWrapper {
    typeset x IFS=$' \t\n'
    { eval "$(</dev/fd/0)"; } <<-EOF
    for x in $(printf '%q ' "$@"); do
        echo "\$x"
    done
EOF
}

myWrapper 'foo bar' $'baz\nbork'

确保您完全了解这里发生了什么,并且您确实有充分的理由这样做。它要求确保副作用不会影响参数。这个具体的例子并没有展示一个非常好的用例,因为所有内容都是硬编码的,因此你可以提前正确地转义,并扩展所引用的参数。