Bash
在 Bash 中雙引號和不雙引號之間有什麼區別?
在跟踪我的 shellscript 中的錯誤時,我在這段程式碼片段中發現了以下行為:
declare -a filelist readarray filelist < <(ls -A) readonly filelist for file in "${filelist[@]}"; do sha256sum ${filelist[$file]} | head -c 64 done
當數組
filelist
不在雙引號中時,命令成功。我一直在使用 ShellCheck 來嘗試改進我的編碼,它建議 -雙引號以防止萬用字元和分詞。
在這種情況下,我不擔心分詞,但在很多其他情況下,我會擔心,所以我試圖保持我的程式碼一致。但是,當我雙引號數組時,命令失敗。將程式碼簡化為單個元素會得到以下結果:
bash-5.0# sha256sum ${filelist[0]} | head -c 64 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 bash-5.0# sha256sum "${filelist[0]}" | head -c 64 sha256sum: can't open 'file1 ': No such file or directory
我顯然可以……不是雙引號,因為在這種情況下分詞不是問題。但我想發帖,因為將來可能會。
我的問題有兩個部分:
- 除瞭如上所述的雙引號數組之外,是否有“最佳實踐”方法來防止分詞?
- 數組中的單引號來自哪裡? 編輯:沒有單引號。單引號是顯示無法打開的文件名的錯誤。
另外,只是出於好奇,為什麼不
echo ${filelist[0]}
包含額外的換行符但包含echo "${filelist[0]}"
?
引用數組擴展絕對沒有問題。
而且,當然,只要您知道並接受後果,不引用它也沒有問題。任何未引用的擴展都會受到拆分和通配。並且,在您的程式碼中,
${filelist[…]}
會刪除 IFS 字元(如果字元串包含任何<space>
、<tab>
或,則進行拆分<newline>
)。這就是沒有引用的擴展所做的事情,刪除尾隨
<newline>
.造成此問題的原因是您在使用時
readarray
沒有從每個數組元素中刪除尾隨分隔符。這樣做會保留
<newline>
反映在錯誤消息上的尾隨。你可以使用的是:
readarray -t filelist < <(ls -A)
該
-t
選項將刪除每個文件名的所有尾隨換行符。-t 從讀取的每一行中刪除尾隨分隔符(預設換行符)。
但是您的程式碼還有一些其他問題。
- 無需聲明或清空數組
filelist
。它預設由 readarray 完成。在其他一些情況下需要這樣做。- 沒有必要解析 的輸出
ls
,事實上,這是個壞主意。獲取數組中文件列表的最簡單方法是:filelist=( ./* )
而且,為了讓它變得更好,最好避免使用目錄:
for file in ./*; do [[ -f $file ]] && filelist+=( "$file" ) done
- 在循環中,
$file
應該使用 var 的值:for file in "${filelist[@]}"; do sha256sum "$file" | head -c 64 done
除非您使用
for file in "${!filelist[@]}"; do
which 將列出數組的鍵。
- 只需一次呼叫 sha256sum 即可處理整個列表:
sha256sum "${filelist[@]}" | cut -c -64
改進後的腳本是:
filelist=() # declare filelist as an array and empty it. for file in ./*; do if [[ -f $file ]]; then filelist+=( "$file" ) fi done declare -r filelist # declare filelist as readonly. sha256sum "${filelist[@]}" | cut -c -64