シェルでの安全なイテレーション: forループのワードスプリッティング回避
bashでのファイルとデータの安全なイテレーションパターンを解説。ワードスプリッティングとグロブ展開によるforループの一般的な落とし穴を回避します。
Quoting
詳細な説明
シェルスクリプトでの安全なイテレーションパターン
forループはシェルスクリプトで最も誤用されている構文の一つです。コマンド置換やクォートされていない変数と組み合わせると、スペースや特殊文字を含むファイル名で微妙なバグが発生します。
アンチパターン
# 悪い例: スペースを含むファイル名で壊れる
for f in $(ls /path/to/dir); do
process "$f"
done
ファイル名が "my file.txt" の場合、このループは "my" と "file.txt" を別々のアイテムとして処理します。
安全な代替方法
グロブパターン(単純なケースで推奨):
for f in /path/to/dir/*; do
[ -e "$f" ] || continue # 空のディレクトリをハンドル
process "$f"
done
findとwhile-read(再帰的検索):
while IFS= read -r -d '' file; do
process "$file"
done < <(find /path -name "*.txt" -print0)
-print0と-d ''の組み合わせにより、改行を含むファイル名も含めすべての可能なファイル名を処理できます。
行のイテレーション
# 悪い例: 行内のスペースでワードスプリッティング
for line in $(cat file.txt); do
echo "$line"
done
# 良い例: 1行ずつ読み取り
while IFS= read -r line; do
echo "$line"
done < file.txt
配列のイテレーション
files=("file one.txt" "file two.txt" "file three.txt")
# 良い例: クォートされた展開でイテレーション
for f in "${files[@]}"; do
echo "$f"
done
要素の境界を保持するために、"${array[@]}"を常にクォートすることが重要です。
ユースケース
複数のファイルを処理、アイテムのリストを読み取り、またはディレクトリの内容をイテレーションするすべてのシェルスクリプト。バックアップスクリプト、バッチ処理ツール、ファイル管理自動化のすべてで安全なイテレーションパターンが有益です。