bash脚本中单引号的问题

时间:2012-05-17 14:27:19

标签: bash

我正在尝试从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 个答案:

答案 0 :(得分:4)

简短回答:使用双引号而不是单引号(如@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

问题在于,虽然单引号抑制了空格的特殊含义(如你所愿),但它们也抑制了$的特殊含义(你不想要) 。所以你需要更具选择性的东西。一种选择是引用/转义空格,但不要引用$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等,但是然后它对它们进行一些额外的解析:寻找用作参数分隔符的空格,用于进行文件名匹配的通配符等等。所有我确定你不想要的东西 - 尽管因为参数可能不会包含任何特殊字符这可能都不是问题。可能。

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

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

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

答案 1 :(得分:1)

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

答案 2 :(得分:1)

您可以使用“(双引号)代替”或“使用”即“

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

答案 3 :(得分:0)

如果我理解正确,您需要" '--args $1 $2 $3' "而非普通'--args $1 $2 $3'。由于顶级令牌是双引号字符串,因此变量将被扩展,'将保留在令牌中以及R可以使用它们。