简短的回答:使用双引号而不是单引号(正如@Pavel 建议的那样)。如果有疑问,请使用set -x
它来了解 shell 如何解析您的命令。
长答案:引号不会传递给命令;相反,它们在将参数传递给命令之前由 shell 解析(并删除)。他们所做的是改变shell解析引号内的内容的方式(通常通过抑制某些字符的特殊含义),这意味着您需要选择适当的引号以允许您想要解析的特殊字符,并抑制那些您希望将其视为普通字符。例如,考虑以下命令:
R CMD BATCH --no-save --no-restore --slave '--args 2 Vocab May12' tabulate.r /dev/tty
shell 将忽略命令的单引号部分中所有字符的特殊含义。唯一具有特殊含义的字符是空格,通常用作参数之间的分隔符;在这种情况下,单引号使 shell 将它们视为单个参数的一部分。这些其他命令:
R CMD BATCH --no-save --no-restore --slave "--args 2 Vocab May12" tabulate.r /dev/tty
R CMD BATCH --no-save --no-restore --slave --args' '2' 'Vocab' 'May12 tabulate.r /dev/tty
R CMD BATCH --no-save --no-restore --slave --args\ 2\ Vocab\ May12 tabulate.r /dev/tty
...都做同样的事情,因为它们都(以一种或另一种方式)让 shell 将空格视为参数的一部分,而不是参数之间的分隔符。
现在,让我们看看对您不起作用的命令:
R CMD BATCH --no-save --no-restore --slave '--args $1 $2 $3' tabulate.r /dev/tty
问题是,虽然单引号抑制了空格的特殊含义(如您所愿),但它们也抑制了$
s 的特殊含义(您不想要)。所以你需要一些更有选择性的东西。一种选择是引用/转义空格,但不引用$1
等:
R CMD BATCH --no-save --no-restore --slave --args' '$1' '$2' '$3 tabulate.r /dev/tty
R CMD BATCH --no-save --no-restore --slave --args\ $1\ $2\ $3 tabulate.r /dev/tty
(请注意,这两个命令的作用完全相同。)这些命令大部分都可以工作,但有一点潜在的麻烦:shell 会将$1
etc 替换为脚本的参数,但随后会对它们进行一些额外的解析:寻找用作参数分隔符的空格、用于进行文件名匹配的通配符等。我很确定你不想要的所有东西——尽管因为参数可能不包含任何特殊字符,所以这可能不会成为一个问题。大概。
我看到的最好的选择是简单地使用双引号:
R CMD BATCH --no-save --no-restore --slave "--args $1 $2 $3" tabulate.r /dev/tty
双引号抑制空格的特殊含义(如您所愿),允许$
触发变量扩展(也如您所愿),但一旦变量已扩展(也可能是您想要的),则阻止任何进一步的解析。参数中的空格或其他有趣的字符可能仍然会在 R 脚本中造成麻烦,但这至少可以防止它们在 R 脚本启动之前造成麻烦。