在Bash中的命令中单引号内的变量扩展

本文翻译自:Expansion of variable inside single quotes in a command in Bash

I want to run a command from a bash shell script which has single quotes and some other commands inside the single quotes and a variable. 我想从bash shell脚本运行一个命令,该脚本具有单引号,并且在单引号内还有一些其他命令和一个变量。

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

In this format, $ is escaped and the variable is not expanded. 以这种格式, $会转义,并且变量不会扩展。

I tried the following variations but they were rejected: 我尝试了以下变体,但被拒绝了:

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

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

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

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

If I substitute the value in place of the variable the command is executed just fine. 如果我用值代替变量,则命令执行得很好。

Please tell me where am I going wrong. 请告诉我我要去哪里错了。


#1楼

参考:https://stackoom.com/question/vtxF/在Bash中的命令中单引号内的变量扩展


#2楼

Inside single quotes everything is preserved literally, without exception. 在单引号内,所有内容均按原样保留,无一例外。

That means you have to close the quotes, insert something, and then re-enter again. 这意味着您必须关闭引号,插入一些内容,然后再次输入。

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

Word concatenation is simply done by juxtaposition. 单词串联仅通过并置即可完成。 As you can verify, each of the above lines is a single word to the shell. 如您所验证的,以上每一行对于shell来说都是一个单词。 Quotes (single or double quotes, depending on the situation) don't isolate words. 引号(单引号或双引号,视情况而定)不会隔离单词。 They are only used to disable interpretation of various special characters, like whitespace, $ , ; 它们仅用于各种特殊字符禁用解释,像空格, $; ... For a good tutorial on quoting see Mark Reed's answer. ...有关引用的良好教程,请参见马克·里德的答案。 Also relevant: Which characters need to be escaped in bash? 还相关: bash中哪些字符需要转义?

Do not concatenate strings interpreted by a shell 不要连接由shell解释的字符串

You should absolutely avoid building shell commands by concatenating variables. 您应该绝对避免通过连接变量来构建Shell命令。 This is a bad idea similar to concatenation of SQL fragments (SQL injection!). 这是一个与串联SQL片段(SQL注入!)类似的坏主意。

Usually it is possible to have placeholders in the command, and to supply the command together with variables so that the callee can receive them from the invocation arguments list. 通常,可以在命令中使用占位符,并将命令与变量一起提供,以便被调用方可以从调用参数列表中接收它们。

For example, the following is very unsafe. 例如,以下内容非常不安全。 DON'T DO THIS 不要这样做

script="echo \"Argument 1 is: $myvar\""
/bin/sh -c "$script"

If the contents of $myvar is untrusted, here is an exploit: 如果$myvar的内容不受信任,则可以利用以下漏洞:

myvar='foo"; echo "you were hacked'

Instead of the above invocation, use positional arguments. 代替上面的调用,请使用位置参数。 The following invocation is better -- it's not exploitable: 以下调用会更好-不可利用:

script='echo "arg 1 is: $1"'
/bin/sh -c "$script" -- "$myvar"

Note the use of single ticks in the assignment to script , which means that it's taken literally, without variable expansion or any other form of interpretation. 请注意,在分配给script的操作中使用了单个刻度,这意味着它是按字面意义使用的,没有变量扩展或任何其他形式的解释。


#3楼

The repo command can't care what kind of quotes it gets. repo命令不在乎它得到哪种报价。 If you need parameter expansion, use double quotes. 如果需要参数扩展,请使用双引号。 If that means you wind up having to backslash a lot of stuff, use single quotes for most of it, and then break out of them and go into doubles for the part where you need the expansion to happen. 如果那意味着您不得不反斜杠很多内容,请对大多数内容使用单引号,然后将其括起来,并在需要扩展的部分加倍。

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

Explanation follows, if you're interested. 如果您感兴趣,请按照以下说明进行操作。

When you run a command from the shell, what that command receives as arguments is an array of null-terminated strings. 从外壳运行命令时,该命令作为参数接收的是一个以null终止的字符串数组。 Those strings may contain absolutely any non-null character. 这些字符串可以绝对包含任何非空字符。

But when the shell is building that array of strings from a command line, it interprets some characters specially; 但是,当外壳程序通过命令行构建字符串数组时,它会特别解释某些字符。 this is designed to make commands easier (indeed, possible) to type. 这是为了使命令更容易(实际上是可能的)输入。 For instance, spaces normally indicate the boundary between strings in the array; 例如,空格通常表示数组中字符串之间的边界。 for that reason, the individual arguments are sometimes called "words". 因此,有时将各个参数称为“单词”。 But an argument may nonetheless have spaces in it; 但是,论点中可能还有空格。 you just need some way to tell the shell that's what you want. 您只需要一些方法告诉外壳程序就是您想要的。

You can use a backslash in front of any character (including space, or another backslash) to tell the shell to treat that character literally. 您可以在任何字符(包括空格或其他反斜杠)前面使用反斜杠,以指示外壳按字面意义对待该字符。 But while you can do something like this: 但是,尽管您可以执行以下操作:

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

...it can get tiresome. ...可能会变得很累。 So the shell offers an alternative: quotation marks. 因此,外壳提供了另一种选择:引号。 These come in two main varieties. 这些有两个主要品种。

Double-quotation marks are called "grouping quotes". 双引号称为“分组引号”。 They prevent wildcards and aliases from being expanded, but mostly they're for including spaces in a word. 它们防止通配符和别名被扩展,但是大多数情况下它们是为了在单词中包含空格。 Other things like parameter and command expansion (the sorts of thing signaled by a $ ) still happen. 诸如参数和命令扩展(由$表示的某种事情)之类的其他事情仍然发生。 And of course if you want a literal double-quote inside double-quotes, you have to backslash it: 当然,如果要在双引号中使用文字双引号,则必须反斜杠:

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

Single-quotation marks are more draconian. 单引号更加严格。 Everything between them is taken completely literally, including backslashes. 它们之间的所有内容都完全按字面意义使用,包括反斜杠。 There is absolutely no way to get a literal single quote inside single quotes. 绝对没有办法在单引号内获取文字单引号。

Fortunately, quotation marks in the shell are not word delimiters ; 幸运的是,外壳中的引号不是单词分隔符 by themselves, they don't terminate a word. 就他们自己而言,他们不会终止一个单词。 You can go in and out of quotes, including between different types of quotes, within the same word to get the desired result: 您可以在同一个单词内输入和输出引号,包括不同类型的引号之间的引号,以得到所需的结果:

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

So that's easier - a lot fewer backslashes, although the close-single-quote, backslashed-literal-single-quote, open-single-quote sequence takes some getting used to. 这样更容易-反斜杠要少得多,尽管右斜杠单引号,单斜杠单反引号,开路单引号的顺序需要一些时间来习惯。

Modern shells have added another quoting style not specified by the POSIX standard, in which the leading single quotation mark is prefixed with a dollar sign. 现代shell添加了POSIX标准未指定的另一种引用样式,其中前导单引号带有一个美元符号。 Strings so quoted follow similar conventions to string literals in the ANSI C programming language, and are therefore sometimes called "ANSI strings" and the $' ... ' pair "ANSI quotes". 这样引用的字符串遵循与ANSI C编程语言中的字符串文字相似的约定,因此有时被称为“ ANSI字符串”和$' ... '对的“ ANSI引号”。 Within such strings, the above advice about backslashes being taken literally no longer applies. 在这样的字符串中,上述关于反斜杠的建议实际上不再适用。 Instead, they become special again - not only can you include a literal single quotation mark or backslash by prepending a backslash to it, but the shell also expands the ANSI C character escapes (like \\n for a newline, \\t for tab, and \\xHH for the character with hexadecimal code HH ). 取而代之的是,它们再次变得特别-您不仅可以在其前面加上反斜杠来包含文字单引号或反斜杠,而且Shell还会扩展ANSI C字符转义符(例如\\n表示换行符, \\t表示制表符, \\xHH表示具有十六进制代码HH的字符。 Otherwise, however, they behave as single-quoted strings: no parameter or command substitution takes place: 但是,否则,它们将充当单引号字符串:不会发生参数或命令替换:

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

The important thing to note is that the single string received as the argument to the echo command is exactly the same in all of these examples. 需要注意的重要一点是,在所有这些示例中,作为echo命令的参数接收的单个字符串是完全相同的 After the shell is done parsing a command line, there is no way for the command being run to tell what was quoted how. Shell完成命令行解析后,就无法运行命令来告诉引用的内容。 Even if it wanted to. 即使它想要。


#4楼

EDIT: (As per the comments in question:) 编辑:(根据有问题的评论:)

I've been looking into this since then. 从那时起,我一直在研究这个问题。 I was lucky enough that I had repo laying around. 我很幸运能够回购信息。 Still it's not clear to me whether you need to enclose your commands between single quotes by force. 我仍然不清楚您是否需要强制将命令括在单引号之间。 I looked into the repo syntax and I don't think you need to. 我调查了repo语法,但我认为您不需要这样做。 You could used double quotes around your command, and then use whatever single and double quotes you need inside provided you escape double ones. 您可以在命令周围使用双引号,然后在内部使用所需的任何单引号和双引号,只要您避免使用双引号即可。


#5楼

Below is what worked for me - 以下是对我有用的-

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

#6楼

这对您有用吗?

eval repo forall -c '....$variable'
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值