在bash shell脚本的命令中扩展单引号内的variables

我想从一个bash shell脚本中运行一个命令,在单引号和一个variables中包含单引号和其他一些命令。

例如repo forall -c '....$variable'

在这种格式下,$被转义并且variables不被扩展。

我尝试了以下变化,但他们被拒绝了:

 repo forall -c '...."$variable" ' repo forall -c " '....$variable' " " repo forall -c '....$variable' " repo forall -c "'" ....$variable "'" 

如果我用这个值代替variables,那么命令执行得很好。

请告诉我我哪里错了

在单引号里面,一切都保持字面上,毫无例外。

这意味着你必须closures报价,插入一些东西,然后再次重新input。

 'before'"$variable"'after' 'before'\''after' 'before'"'"'after' 

正如您可以validation的那样,上面的每一行都是一个单词。 string连接只是通过并置来完成的。 引号(单引号或双引号,取决于具体情况)用于禁用各种特殊字符的解释,如空格$; …有关引用的好教程,请参阅Mark Reed的回答。 也相关: 哪些字符需要在bash中转义?


请注意,您应该避免通过程序性地连接string和variables来构buildshell命令。 这与在大多数编程语言中使用eval类似,或者构buildSQL请求(SQL注入!)是一个糟糕的主意。

通常,可以在命令中包含占位符,并将命令与variables一起提供,以便被调用者可以安全地replace占位符,而不是调用者连接string,从而混合代码和数据。

例如,要在外部shell中使用参数运行shell命令:

 myvar=foo /bin/sh -c 'echo "argument 1 is: $1"' -- "$myvar" 

另一方面,以下是非常不安全的。 不要这样做

 myvar='foo"; rm -rf /mypreciousdata; echo "you were hacked' # exploit /bin/sh -c "echo \"Argument 1 is: $myvar\"" 

repo命令不能关心它得到什么样的引用。 如果您需要参数扩展,请使用双引号。 如果这意味着你需要反斜杠,那么大多数情况下都要用单引号,然后把它们打散出去,在需要扩展的地方进行双打。

 repo forall -c 'literal stuff goes here; '"stuff with $parameters here"' more literal stuff' 

解释如下,如果你有兴趣。

当你从shell运行一个命令时,那个命令作为参数接收的是一个以空字符结尾的string数组。 这些string可能包含绝对的任何非空字符。

但是当shell从命令行创build这个string数组时,它会专门解释一些字符; 这是为了使命令更容易(实际上是可能的)input而devise的。 例如,空格通常表示数组中string之间的边界; 出于这个原因,个别论据有时被称为“文字”。 但是一个论点可能还有空间。 你只需要一些方法来告诉shell是你想要的。

您可以在任何字符(包括空格或另一个反斜杠)前使用反斜杠来指示shell从字面上处理该字符。 但是,虽然你可以做这样的事情:

echo \"Thank\ you.\ \ That\'ll\ be\ \$4.96,\ please,\"\ said\ the\ cashier

它可能会让人厌烦 所以shell提供了一个替代方法:引号。 这些来自两个主要品种。

双引号称为“分组引号”。 它们防止通配符和别名被扩展,但主要是为了在一个单词中包含空格。 其他的东西,比如参数和命令扩展(用$表示的东西)仍然会发生。 当然,如果你想在双引号内使用双引号,你必须反斜杠:

echo "\"Thank you. That'll be \$4.96, please,\" said the cashier"

单引号更为严格。 它们之间的一切都是完全字面的,包括反斜杠。 绝对没有办法得到单引号内的文字单引号。

幸运的是,shell 中的引号不是单词分隔符 , 他们本身并没有终止一个字。 您可以在同一个单词中进出引号(或不同types的引号之间)以获得期望的结果:

echo '"Thank you. That'\''ll be $4.96, please," said the cashier'

所以这很容易 – 反斜杠的数量要less得多,尽pipe单引号,反引号,单引号,单引号开放序列需要一些习惯。

现代的shell已经添加了POSIX标准没有指定的另一种引用风格,其中前导单引号以$符号为前缀。 如此引用的string遵循ANSI C编程语言中string文字的类似惯例,因此有时称为“ANSIstring”和$''对“ANSI引号”。 在这样的string中,上面关于反斜杠的build议从字面上看不再适用。 相反,它们再次变得特别 – 不仅可以通过在其前面加一个反斜杠来包含一个单引号或反斜线,而且还会扩展ANSI C字符的转义符(如换行符为\n对于制表符为\t\xHH代表hex代码HH )。 否则,它们performance为单引号string:不发生参数或命令replace:

 echo $'"Thank you. That\'ll be $4.96, please," said the cashier' 

重要的是要注意的是,作为echo命令的参数接收的string在所有这些示例中都完全相同 。 在完成shellparsing命令行后,运行的命令无法告诉引用的内容。 即使它想。

编辑:(根据评论的问题:)

从那以后我一直在研究这个。 我很幸运,我有回购铺设。 不过,我还不清楚你是否需要用单引号括起你的命令。 我看着回购语法,我不认为你需要。 你可以在你的命令周围使用双引号,然后使用你需要的任何单引号和双引号,只要你转义双引号。

下面是对我有用的东西 –

QUOTE="'" hive -e "alter table TBL_NAME set location $QUOTE$TBL_HDFS_DIR_PATH$QUOTE"