はじめに (対象読者・この記事でわかること)
この記事は、Linux/macOSのターミナルで「ディレクトリ配下のすべてのファイルを一気に表示したい」と思っている方を対象にしています。
特に、サーバー環境でfindやxargsが使えない、あるいはコマンドが制限されているケースで困っている方に最適です。
読み進めることで、Bashの組み込み機能(glob/配列/リダイレクト)だけで再帰的にファイルを結合・表示する方法が身につきます。
外部コプロセスを起動しないため、高速かつ依存関係ゼロで動作するスクリプトを書けるようになります。
前提知識
この記文を読み進める上で、以下の知識があるとスムーズです。
- Bashの基本的な文法(変数、ループ、リダイレクト)
- ファイルパスのグロブ展開(ワイルドカード)の概念
- 標準エラー出力(
2)と標準出力(1)の違い
なぜfind/xargsを使いたくないのか
findやxargsは非常に便利ですが、以下の理由で「使えない/使いたくない」場面があります。
- 最小限のコンテナ/組み込み環境
AlpineやDistroless、BusyBoxではfindutilsやxargsが入っていないことがあります。 - 大量ファイルでのボトルネック
findは再起動ごとにstatを大量に呼び出し、ファイル数が多いと明らかに遅くなります。 - 特殊文字対策の煩雑さ
ファイル名にスペースや改行が含まれると、find -print0+xargs -0の組み合わせが必須になり、コマンドが長くなりがちです。
Bash 4以降であれば、組み込みの**(グロブ)と配列でこれらの問題を回避できます。
Bash組み込みだけで再帰catする実装
ここでは、外部コマンドを一切使わず「カレント以下の全ファイルを順番にcatする」シェル関数を作ります。
エラーは標準エラーに、ファイル内容は標準出力に分離して、後続のパイプやリダイレクトで加工しやすくしています。
ステップ1: 再帰グロブを有効にする
Bash 4+では**がディレクトリを再帰的にマッチします。まずオプションを有効化します。
Bashshopt -s globstar # ** を有効化 shopt -s nullglob # マッチしない場合に空文字列になる(エラー回避)
ステップ2: 配列にファイル一覧を展開してcat
ファイル名を配列に格納して順次catします。
これにより、ファイル名にスペースや改行が含まれていても安全です。
Bashrec_cat() { local files=() file # 隠しファイルも含めて再帰的に取得 for file in **/* .*; do [[ -f $file ]] && files+=("$file") done # ファイルがなければ早期リターン ((${#files[@]})) || return 0 # 全ファイルを順にcat for file in "${files[@]}"; do # エラーはstderrに、中身はstdoutに cat -- "$file" 2>/dev/null || printf 'rec_cat: %s: %s\n' "$file" "$?" >&2 done }
一行で呼び出す場合は以下の通りです。
Bashshopt -s globstar nullglob; for f in **/* .*; do [[ -f $f ]] && cat -- "$f"; done
ステップ3: 必要に応じてソートやフィルタを追加
ファイル名順に処理したい場合はprintf '%s\n' "${files[@]}" | sort -zしてからループします。
拡張子で絞りたい場合は[[ $file == *.log ]]のように条件を追加するだけです。
Bash# 例: *.logファイルだけcat for file in **/*.log; do [[ -f $file ]] && cat -- "$file" done
ハマった点と解決策
-
Argument list too long
デフォルトの配列展開で"$files[@]"を一度にcatに渡すと、ファイル数が多いとエラーになります。
→ 1ファイルずつcatするループにすることで回避できます。 -
隠しディレクトリの扱い
**/*は隠しファイルを拾わないため、.*も併せてループします。
ただし.と..は除外するため、[[ -f $file ]]でチェックしています。 -
バイナリファイルが混入した場合
ターミナルが乱れることがあるので、catの代わりにfile -b --mime-type "$file"でテキストかチェックしてからcatする運用も推奨されます。
まとめ
本記事では、外部コマンドなしでディレクトリ配下の全ファイルを再帰的にcatする方法を解説しました。
- Bash 4以降の
globstarで再帰グロブを有効化 - 配列にファイルパスを展開して安全にループ
- 1ファイルずつcatすることで大量ファイルでも高速かつ安全
このテクニックを使えば、最小限の環境でも高速にファイル結合が可能です。
次回は「並列化と進捗表示」を追加して、より大規模なログ解析にも対応できるように改良したいと思います。
参考資料
- Bash Reference Manual – 4.3.2 The Shopt Builtin
https://www.gnu.org/software/bash/manual/bash.html#The-Shopt-Builtin - Bash Hackers Wiki – glob
https://wiki.bash-hackers.org/syntax/expansion/glob - POSIX Programmer’s Manual – cat
https://pubs.opengroup.org/onlinepubs/9699919799/utilities/cat.html
