我想从 bash shell脚本运行命令,该脚本在单引号和变量中包含单引号和一些其他命令。
e.g。 repo forall -c '....$variable'
在此格式中,$
被转义,变量未展开。
我尝试了以下变体,但遭到拒绝:
repo forall -c '...."$variable" '
repo forall -c " '....$variable' "
" repo forall -c '....$variable' "
repo forall -c "'" ....$variable "'"
如果我用值代替变量,则命令执行得很好。
请告诉我哪里出错了。
答案 0 :(得分:490)
在单引号内,所有内容都是字面上保留的,无一例外。
这意味着您必须关闭引号,插入内容,然后重新输入。
'before'"$variable"'after'
'before'"'"'after'
'before'\''after'
您可以验证,上面的每一行都是shell的单个单词。字符串连接简单地通过并置来完成。引号(单引号或双引号,取决于具体情况)用于禁用各种特殊字符的解释,如空格,$
,;
...有关引用的好教程请参阅Mark Reed的答案。相关:Which characters need to be escaped in bash?
绝对应该通过连接变量来避免构建shell命令。这是一个糟糕的想法,类似于SQL片段的连接(SQL注入!)。
通常可以在命令中包含占位符,并将命令与变量一起提供,以便被调用者可以从调用参数列表中接收它们。
例如,以下内容非常不安全。不要这样做
script="echo \"Argument 1 is: $myvar\""
/bin/sh -c "$script"
如果$myvar
的内容不受信任,则可以使用以下内容:
myvar='foo"; echo "you were hacked'
使用位置参数代替上述调用。以下调用更好 - 它不可利用:
script='echo "arg 1 is: $1"'
/bin/sh -c "$script" -- "$myvar"
请注意在script
的赋值中使用单个刻度,这意味着它是字面上的,没有可变扩展或任何其他形式的解释。
答案 1 :(得分:81)
repo
命令无法关注它获得的引用类型。如果需要参数扩展,请使用双引号。如果这意味着你不得不反复使用大量的东西,那么对大多数东西使用单引号,然后突破它们并进入双打,以便你需要进行扩展。
repo forall -c 'literal stuff goes here; '"stuff with $parameters here"' more literal stuff'
如果您有兴趣,请按照以下说明进行操作。
当您从shell运行命令时,该命令作为参数接收的是一个以null结尾的字符串数组。这些字符串可能包含绝对任何非空字符。
但是当shell从命令行构建那个字符串数组时,它会特别解释一些字符;这旨在使命令更容易(实际上,可能)键入。例如,空格通常表示数组中字符串之间的边界;因此,个别论据有时被称为"单词"。但是,一个论点可能会有空格;你需要一些方法来告诉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 中的引号不是单词分隔符;他们自己不会终止一个字。您可以在同一个单词中输入和输出引号,包括不同类型的引号,以获得所需的结果:
echo '"Thank you. That'\''ll be $4.96, please," said the cashier'
这样更容易 - 反斜杠的数量要少得多,尽管单引号,反单词 - 单引号,开引单引号序列需要一些时间来适应。
现代shell添加了另一种POSIX标准未指定的引用样式,其中前导单引号以美元符号为前缀。引用的字符串遵循与ANSI C编程语言中的字符串文字类似的约定,因此有时称为" ANSI字符串"以及$'
... '
对" ANSI引号"。在这些字符串中,上面关于反斜杠的建议实际上不再适用。相反,它们再次变得特殊 - 不仅可以通过在其前面添加反斜杠来包含文字单引号或反斜杠,而且shell还会扩展ANSI C字符转义(如\n
换行,{{1对于制表符,\t
表示具有十六进制代码\xHH
的字符。否则,它们表现为单引号字符串:不进行参数或命令替换:
HH
需要注意的重要一点是,作为echo $'"Thank you. That\'ll be $4.96, please," said the cashier'
命令的参数接收的单个字符串在所有这些示例中都是完全相同的。在shell完成解析命令行之后,没有办法运行命令来告诉引用的内容。即使它想要。
答案 2 :(得分:2)
编辑:(根据相关评论:)
从那以后我一直在研究这个问题。我很幸运,我有回购。我还不清楚你是否需要强制将命令括在单引号之间。我查看了repo语法,我认为你不需要。你可以在你的命令周围使用双引号,然后使用你需要的任何单引号和双引号,只要你逃脱双重引号。
答案 3 :(得分:0)
以下是对我有用的东西 -
QUOTE="'"
hive -e "alter table TBL_NAME set location $QUOTE$TBL_HDFS_DIR_PATH$QUOTE"
答案 4 :(得分:0)
变量可以包含单引号。
myvar=\'....$variable\'
repo forall -c $myvar
答案 5 :(得分:0)
只需使用printf
代替
repo forall -c '....$variable'
使用printf将变量标记替换为扩展变量。
例如:
template='.... %s'
repo forall -c $(printf "${template}" "${variable}")
答案 6 :(得分:-2)
这对你有用吗?
eval repo forall -c '....$variable'