シェルでの安全なイテレーション: 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[@]}"を常にクォートすることが重要です。

ユースケース

複数のファイルを処理、アイテムのリストを読み取り、またはディレクトリの内容をイテレーションするすべてのシェルスクリプト。バックアップスクリプト、バッチ処理ツール、ファイル管理自動化のすべてで安全なイテレーションパターンが有益です。

試してみる — Shell Script Linter

フルツールを開く