在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'
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章