簡體   English   中英

Bash命令中單引號內變量的擴展

[英]Expansion of variables inside single quotes in a command in Bash

我想從一個bash 腳本運行一個命令,該腳本在單引號和一個變量中包含單引號和其他一些命令。

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

在這種格式中, $被轉義並且變量沒有被擴展。

我嘗試了以下變體,但被拒絕了:

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

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

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

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

如果我用值代替變量,則命令執行得很好。

請告訴我我哪里出錯了。

在單引號內,所有內容都按字面保留,無一例外。

這意味着您必須關閉引號,插入一些內容,然后再次重新輸入。

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

單詞連接只是通過並列完成的。 正如您可以驗證的那樣,上面的每一行都是 shell 的一個單詞。 引號(單引號或雙引號,視情況而定)不會隔離單詞。 它們僅用於各種特殊字符禁用解釋,像空格, $; ...有關引用的好教程,請參閱 Mark Reed 的回答。 同樣相關: 哪些字符需要在 bash 中轉義?

不要連接由 shell 解釋的字符串

您絕對應該避免通過連接變量來構建 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的賦值中使用單個刻度,這意味着它是按字面意思進行的,沒有變量擴展或任何其他形式的解釋。

repo命令不關心它得到什么樣的引號。 如果需要參數擴展,請使用雙引號。 如果這意味着你最終不得不對很多東西進行反斜杠,那么對大部分內容使用單引號,然后將它們分開並在需要擴展的部分進入雙引號。

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

解釋如下,如果你有興趣。

當您從 shell 運行命令時,該命令作為參數接收的是一個以空字符結尾的字符串數組。 這些字符串可能包含絕對任何非空字符。

但是當 shell 從命令行構建字符串數組時,它會特別解釋一些字符; 這是為了使命令更容易(實際上,可能)輸入。 例如,空格通常表示數組中字符串之間的邊界; 因此,個別論點有時被稱為“詞”。 但是一個論證中可能仍然有空格; 您只需要某種方式來告訴 shell 這就是您想要的。

您可以在任何字符(包括空格或另一個反斜杠)前使用反斜杠來告訴 shell 按字面意思處理該字符。 但是,雖然您可以執行以下操作:

reply=\”That\'ll\ be\ \$4.96,\ please,\"\ said\ the\ cashier

......它可能會讓人厭煩。 所以 shell 提供了一個替代方案:引號。 這些有兩個主要品種。

雙引號稱為“分組引號”。 它們防止擴展通配符和別名,但主要用於在單詞中包含空格。 諸如參數和命令擴展之類的其他事情(由$表示的那種事情)仍然會發生。 當然,如果您想在雙引號內使用文字雙引號,則必須將其反斜杠:

reply="\"That'll be \$4.96, please,\" said the cashier"

單引號更加嚴厲。 它們之間的所有內容都完全按字面意思理解,包括反斜杠。 絕對沒有辦法在單引號中獲得文字單引號。

幸運的是,shell中的引號不是單詞分隔符 就其本身而言,它們不會終止一個詞。 您可以在同一個單詞內進入和退出引號,包括在不同類型的引號之間,以獲得所需的結果:

reply='"That'\''ll be $4.96, please," said the cashier'

所以這更容易 - 更少的反斜杠,盡管關閉單引號,反斜杠文字單引號,開單引號序列需要一些時間來適應。

現代 shell 添加了另一種 POSIX 標准未指定的引用樣式,其中前導單引號以美元符號為前綴。 如此引用的字符串遵循與 C 編程語言的 ANSI 標准版本中的字符串文字類似的約定,因此有時稱為“ANSI 字符串”和$' ... '對“ANSI 引號”。 在這些字符串中,上述關於從字面上采用反斜杠的建議不再適用。 相反,它們再次變得特別——您不僅可以通過在其前面添加反斜杠來包含文字單引號或反斜杠,而且 shell 還擴展了 ANSI C 字符轉義(如\\n表示換行符, \\t表示制表符,以及\\xHH表示具有十六進制代碼HH的字符)。 然而,否則,它們表現為單引號字符串:不發生參數或命令替換:

reply=$'"That\'ll be $4.96, please," said the cashier'

需要注意的重要一點是,在所有這些示例中,存儲在reply變量中的單個字符串完全相同 同樣,外殼做解析命令行后,就沒有辦法為正在運行的命令,告訴每一個參數字符串中究竟是如何實際鍵入-或即使它是類型化的,而不是創建程序莫名其妙。

以下是對我有用的內容-

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

編輯:(根據相關評論:)

從那以后我一直在研究這個。 我很幸運,我有回購協議。 我仍然不清楚您是否需要強制將命令括在單引號之間。 我查看了 repo 語法,我認為您不需要。 你可以在你的命令周圍使用雙引號,然后使用你需要的任何單引號和雙引號,前提是你可以轉義雙引號。

只需使用 printf

代替

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

使用 printf 將變量標記替換為擴展變量。

例如:

template='.... %s'

repo forall -c $(printf "${template}" "${variable}")

變量可以包含單引號。

myvar=\'....$variable\'

repo forall -c $myvar

這對你有用嗎?

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM