2

我正在尝试从 bash 脚本运行命令。该命令本身有单引号,但我无法让它们工作,因为单引号内有需要扩展的变量。这是 bash 脚本:

#!/bin/bash

if [ "$2" == "PracSci" ];
then
    echo "Running tabulate.science.r"
    R CMD BATCH --no-save --no-restore --slave '--args $1 $2 $3' tabulate.science.r /dev/tty
else
    echo "Running tabulate.r"
    R CMD BATCH --no-save --no-restore --slave '--args $1 $2 $3' tabulate.r /dev/tty
fi

./script.sh 2 Vocab May12例如,当运行时,命令本身在没有变量值的情况下运行。

如何在仍然运行命令的同时扩展变量?

为了清楚起见,我要运行的命令是:( R CMD BATCH --no-save --no-restore --slave '--args $1 $2 $3' tabulate.r /dev/tty包括命令中的单引号)。

谢谢!

4

4 回答 4

5

简短的回答:使用双引号而不是单引号(正如@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 会将$1etc 替换为脚本的参数,但随后会对它们进行一些额外的解析:寻找用作参数分隔符的空格、用于进行文件名匹配的通配符等。我很确定你不想要的所有东西——尽管因为参数可能不包含任何特殊字符,所以这可能不会成为一个问题。大概。

我看到的最好的选择是简单地使用双引号:

R CMD BATCH --no-save --no-restore --slave "--args $1 $2 $3" tabulate.r /dev/tty

双引号抑制空格的特殊含义(如您所愿),允许$触发变量扩展(也如您所愿),但一旦变量已扩展(也可能是您想要的),则阻止任何进一步的解析。参数中的空格或其他有趣的字符可能仍然会在 R 脚本中造成麻烦,但这至少可以防止它们在 R 脚本启动之前造成麻烦。

于 2012-05-17T21:45:01.670 回答
2

使用双引号 - 还是我错过了重点?

于 2012-05-17T14:32:18.100 回答
0

您可以使用 "(双引号) 代替或关闭 ' 与 ' 即

#!/bin/bash

if [ "$2" == "PracSci" ];
then
    echo "Running tabulate.science.r"
    R CMD BATCH --no-save --no-restore --slave '--args '$1' '$2' '$3 tabulate.science.r /dev/tty
else
    echo "Running tabulate.r"
    R CMD BATCH --no-save --no-restore --slave '--args '$1' '$2' '$3 tabulate.r /dev/tty
fi

或者,如果您需要args ...再次在单引号中,则只需编写

#!/bin/bash

if [ "$2" == "PracSci" ];
then
    echo "Running tabulate.science.r"
    R CMD BATCH --no-save --no-restore --slave "'--args $1 $2 $3'" tabulate.science.r /dev/tty
else
    echo "Running tabulate.r"
    R CMD BATCH --no-save --no-restore --slave "'--args $1 $2 $3'" tabulate.r /dev/tty
fi
于 2012-05-17T14:32:24.210 回答
0

如果我理解正确,你想要 " '--args $1 $2 $3' "而不是 plain '--args $1 $2 $3'。由于顶级标记是双引号字符串,因此变量将被扩展,并且'将保留在标记中,以便 R 可以使用它们。

于 2012-05-17T14:33:48.627 回答