Bash

在 Bash 中雙引號和不雙引號之間有什麼區別?

  • April 24, 2020

在跟踪我的 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

我顯然可以……不是雙引號,因為在這種情況下分詞不是問題。但我想發帖,因為將來可能會。

我的問題有兩個部分:

  1. 除瞭如上所述的雙引號數組之外,是否有“最佳實踐”方法來防止分詞?
  2. 數組中的單引號來自哪裡? 編輯:沒有單引號。單引號是顯示無法打開的文件名的錯誤。

另外,只是出於好奇,為什麼不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[@]}"; dowhich 將列出數組的

  • 只需一次呼叫 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

引用自:https://unix.stackexchange.com/questions/582041