Bashの二重引用符付き配列と引用符なしの配列の違いは何ですか?

Bashの二重引用符付き配列と引用符なしの配列の違いは何ですか?

シェルスクリプトでバグを追跡中に、このコードスニペットで次の動作が見つかりました。

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

明らかに...二重引用符は使用できません。この場合、単語の分離は問題にならないからです。しかし、これからもそうかもしれないので、投稿をしたいと思いました。

私の質問は2つの部分で構成されています。

  1. 上記の二重引用符の配列に加えて、単語の分割を防ぐための「ベストプラクティス」方法はありますか?
  2. 配列の一重引用符はどこから来たのですか? 編集:一重引用符はありません。一重引用符は、開けられないファイル名を表示するエラーです。

また、疑問に思われecho ${filelist[0]}ない追加の改行文字が含まれるのはなぜですかecho "${filelist[0]}"

ベストアンサー1

参照配列の拡張にはまったく問題はありません。

もちろん、結果を知って受け入れるならば、引用しなくても大丈夫です。引用符のない拡張子は、分割とワイルドカードの影響を受けます。そして、コードから${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
    
  • ループ内では$filevar値を使用する必要があります。

    for file in "${filelist[@]}"; do
      sha256sum "$file" | head -c 64
    done
    

    for file in "${!filelist[@]}"; doリストを使用しない限りソート。

  • リスト全体を処理するだけです。一つ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

おすすめ記事