單引號和雙引號是由“bash”還是由“echo”處理的?
當你做這樣的事情時:
echo 'Hello World'
或者像這樣:
x=12345 echo "x is: $x"
在第一個範例中,
echo
命令是接收'Hello World'
還是接收Hello World
?在第二個範例中,
echo
命令是接收"x is: $x"
還是接收x is: 12345
?所以基本上我的問題是:單引號和雙引號是由
bash
還是由處理的echo
?
引號、變數擴展、萬用字元以及bash 手冊中有關擴展的部分中提到的所有其他內容都由 bash 處理。
例如,當您執行 bash command 時
echo "x is: $x"
,bash 對其進行解析以發現它需要執行echo
帶有一個參數的命令,即x is: 12345
. 給定echo "x is" "$x"
, bashecho
使用兩個參數執行:x is
和12345
— 這就是為什麼保留引號內的兩個空格(它們是未修改的 echo 列印的參數的一部分),但引號外的兩個空格不是(對於 shell,兩個分隔參數的空格與單個參數一樣好,並且echo
始終在其間列印一個空格)。命令(
echo
或任何其他命令)無法知道哪個 shell 命令產生了參數x is: 12345
,或者實際上是否涉及 shell。以下是一些產生此參數的範例命令:echo "x is: 12345" echo 'x is: 12345' echo x\ is:\ 12345 echo "x is: $x" echo 'x is:'\ "$x" echo "$(echo "x ")is: $x" # Assume there is no other file whose name begins with x in the current directory touch "x is: $x"; echo x*
或者它可以
exec "echo", "x is: 12345"
在 Perl 或execlp("echo", "echo", "x is: 12345")
C 等中。這適用於每個命令。同樣的原則也適用於其他 shell,儘管它們每個都有稍微(或顯著)不同的擴展集。
另一方面,選項由命令處理。例如,
ls -l -t
在ls -l "-t"
bash(或任何類似的 shell)中,兩者都ls
以完全相同的方式執行,帶有兩個參數-l
和-t
. 這就是為什麼如果您想執行ls
以顯示有關名為-t
. 您可以使用 來做到這一點ls -l -- -t
,即--
作為參數傳遞。這是大多數命令遵循的約定:後面的任何內容都不會--
被解析為選項。再一次,這是命令的一個特性;對於 shell,前導破折號沒什麼特別的。可能會變得棘手的一件事是反斜杠。在 bash 和其他 shell 中,任何引號之外的反斜杠意味著下一個字元失去其特殊含義。例如,
echo \"x\ is:\ 12345\"
prints"x is: 12345"
,因為前面有反斜杠的每個字元都失去了它們的特殊含義(引號語法"
用於空格,單詞分隔符用於空格)。但有些命令也解釋反斜杠。當他們這樣做時,您需要確保反斜杠到達他們。例如,在 bash 中,該echo
命令預設按字面意思列印反斜杠,但如果您傳遞選項-e
或shopt xpg_echo
先執行,則echo
有其自己的轉義序列(這是針對 bash,echo
不同 shell 和不同系統中的命令對於是否特殊處理反斜杠有不同的規則)。例如,echo 'a\nb'
printsa\nb
whileecho -e 'a\nb'
printsa
-newline-b
因為\n
意味著“換行符”到echo -e
. 另一方面,echo a\nb
printssince被 shell 擴展,意思anb
是“引用下一個字元”。\n``\
此外,當涉及多個 shell 時要小心,例如使用 SSH。在 shell 中執行
ssh
時,本地 shell 會像往常一樣解析命令。SSH 客戶端用空格連接它的非選項參數,並將結果字元串發送到 SSH 伺服器。SSH 伺服器將此字元串傳遞給遠端 shell。這意味著在您在終端或 shell 腳本中鍵入的內容與在遠端機器上執行的內容之間存在兩輪完整的 shell 擴展。