Bash
為什麼帶引號的變數中的選項會失敗,但不帶引號時會起作用?
我讀到我應該在 bash 中引用變數,例如“ $ foo" instead of $ 富。但是,在編寫腳本時,我發現了一個不帶引號但不帶引號的情況:
wget_options='--mirror --no-host-directories' local_root="$1" # ./testdir recieved from command line remote_root="$2" # ftp://XXX recieved from command line relative_path="$3" # /XXX received from command line
這個有效:
wget $wget_options --directory_prefix="$local_root" "$remote_root$relative_path"
這個沒有(注意 $wget_options 周圍的雙引號):
wget "$wget_options" --directory_prefix="$local_root" "$remote_root$relative_path"
- 這是什麼原因?
- 第一行是好版本嗎?還是我應該懷疑某處存在導致這種行為的隱藏錯誤?
- 一般來說,我在哪裡可以找到好的文件來了解 bash 及其引用的工作原理?在編寫這個腳本的過程中,我覺得我開始在反複試驗的基礎上工作,而不是理解規則。
基本上,您應該雙引號變數擴展以保護它們免於分詞(和文件名生成)。但是,在您的範例中,
wget_options='--mirror --no-host-directories' wget $wget_options --directory_prefix="$local_root" "$remote_root$relative_path"
分詞正是您想要的。
使用
"$wget_options"
(引用),wget
不知道如何處理單個參數--mirror --no-host-directories
並抱怨wget: unknown option -- mirror --no-host-directories
要
wget
查看這兩個選項--mirror
並--no-host-directories
作為單獨的選項,必須進行分詞。有更強大的方法可以做到這一點。如果您正在使用
bash
或任何其他使用數組的 shellbash
,請參閱glenn jackman’s answer。Gilles 的回答還描述了一種更簡單的外殼的替代解決方案,例如標準/bin/sh
. 兩者本質上都將每個選項儲存為數組中的單獨元素。具有良好答案的相關問題:為什麼我的 shell 腳本會因空格或其他特殊字元而窒息?
雙引號變數擴展是一個很好的經驗法則。那樣做。然後請注意極少數情況下您不應該這樣做。這些將通過診斷消息呈現給您,例如上述錯誤消息。
在某些情況下,您不需要引用變數擴展。但是無論如何繼續使用雙引號會更容易,因為它沒有太大區別。一種這樣的情況是
variable=$other_variable
另一個是
case $variable in ...) ... ;; esac
最健壯的編碼方式是使用數組:
wget_options=( --mirror --no-host-directories --directory_prefix="$1" ) wget "${wget_options[@]}" "$2/$3"