如何防止命令行上的命令替換?
我發現當將文本作為輸入寫入另一個程序時,預期文本中雙引號中的任何命令替換都會由 shell 解釋和擴展
此處答案中的連結指出,單引號可用於防止參數擴展或命令替換。但是我發現在單引號中包含命令替換也無法阻止 shell 擴展命令替換
如何防止 shell 解釋旨在作為文本而不是要執行的命令的命令替換?
展示
$ echo "`wc -l *`"
嘗試計算目前目錄中所有文件的行數
$ echo "'`wc -l *`'"
結果相同,即計算目前目錄中所有文件的行數
更新從這個展示中我發現問題似乎是我引用了單引號。我認為將單引號和```(反引號)括在雙引號中可以保留(即抑制)單引號的字面含義,但不會保留引入命令替換的反引號(即反引號)的字面含義。
在我的案例中,需要引用另一個命令的輸入。這份文件說:
單引號內不能出現單引號
當單引號命令替換在(雙)引號字元串內時,如何防止單引號命令替換被擴展?除了使用反斜杠轉義之外,應該有一種方法可以做到這一點
實際情況
在一個程序中,我使用將任務描述拆分為單獨行的唯一方法是將描述括在雙引號中:
$ task add "first line doesn\'t say much Second line says a lot but part of this line does not appear in the resulting description 'truncate -s0 !(temp_file | temp_dir)' truncates all files to 0 bytes as shown by: '`wc -l *`'"
結果描述:
first line doesn\ -s0 !(temp_file | temp_dir)' truncates all files to 0 bytes as shown by: 0 file1 10 file2 0 directory1 0 directory2 502 file3 123 file4 162 file5 0 directory3
如你看到的
't say much Second line says a lot but part of this line does not appear in the resulting description 'truncate
描述中缺少,並且 shell 已解釋
'wc -l *'
為命令替換,因此包括目前目錄中所有文件的行數作為描述的一部分是什麼導致 shell 刪除了
task
between\
(backslash) and的部分參數-s
,以及如何防止 shell 解釋上述單引號命令替換(即'
wc -l *'
)?
在這裡(添加了換行符),
$ task add "first line doesn\'t say much Second line says a lot but part of this line does not appear in the resulting description 'truncate -s0 !(temp_file | temp_dir)' truncates all files to 0 bytes as shown by: '`wc -l *`'"
整個字元串是雙引號的,因此命令替換和其他擴展將在那裡執行。這發生在 shell 中,在
task
看到該字元串之前,您需要使用反斜杠或將該部分放在單引號中來防止它。例如
$ printf "%s\n" "...shown by: '\`wc -l *\`'" ...shown by: '`wc -l *`'
所以,
task add "...shown by: '\`wc -l *\`'"
會將字元串傳遞
...shown by: '
wc -l *'
給task
. 這取決於它做什麼。如果您不想使用反斜杠,可以將其放在單引號中:
# aaaaaaaaaaaaaaaaBBBBBBBBBBBaaa $ printf "%s\n" "...shown by: '"'`wc -l *`'"'" ...shown by: '`wc -l *`'
(
a
’ 標記雙引號部分, ’ 標記B
單引號部分。它們只是在 shell 命令行上連接起來。文字單引號在雙引號字元串內。)至於單引號和反斜杠,您不需要在雙引號內轉義單引號,實際上反斜杠將保留在那裡:
$ printf "%s\n" "foo'bar" foo'bar $ printf "%s\n" "foo\'bar" foo\'bar
從您顯示的內容來看,似乎
task
至少從參數中刪除了第一個單引號字元串(之後加上一個單詞,因為刪除的部分是't say much ... 'truncate
)外殼不會那樣做,這很好用:
$ printf "%s\n" "a 'quoted string' to test" a 'quoted string' to test
是什麼導致shell刪除了(反斜杠)和
task
之間的部分參數,\``-s
很可能不是外殼在這樣做。
以及如何防止外殼解釋上述單引號命令替換(即
'
wc -l *'
)?它不是單引號,它是雙引號,旁邊是帶引號的單引號。
使用單引號強引用:
printf '%s\n' '`wc -l *`'
如果您還想在傳遞給的參數中包含單引號,則
printf
需要為'
自己使用不同的引號,例如:printf '%s\n' '`wc -l *` and a '"'"' character'
或者:
printf '%s\n' '`wc -l *` and a '\'' character'
其他替代方法包括```在雙引號內使用反斜杠轉義:
printf '%s\n' "\`wc -l *\` and a ' character"
或者```是一些擴展的結果:
backtick='`' printf '%s\n' "${backtick}wc -l *${backtick} and a ' character"
另請注意:
cat << 'EOF' `wc -l *` and a ' character and a " character EOF
輸出任意文本而不必擔心引用(注意第一個引號
EOF
)。你也可以這樣做:
var=$(cat << 'EOF' echo '`wc -l *`' EOF )
使用
ksh93
或mksh
您可以優化到:var=$(<<'EOF' echo '`wc -l *`' EOF )
(也可以
zsh
在.cat``$var``echo '
wc -l *'
在
fish
外殼中,您可以'
嵌入'...'
其中\'
:printf '%s\n' '`wc -l *` and a \' character'
但無論如何```在那裡並不特別,所以:
printf '%s\n' "`wc -l *` and a ' character"
也可以。
在 rc、es 或中,您可以在其中
zsh -o rcquotes
插入一個with :'``'...'``''
printf '%s\n' '`wc -l *` and a '' character'
請參閱如何將特殊字元用作普通字元?更多細節。