Bashを使用したシェルスクリプトの実行において、ログの取得はデバッグや運用監視のために欠かせない作業です。
プログラムの実行結果である「標準出力」と、エラーメッセージである「標準エラー出力」を個別に扱うのは手間がかかる場合があります。
これら二つの出力ストリームを一つのファイルにまとめて保存することで、時系列に沿った正確な動作記録を効率的に残すことが可能になります。
本記事では、Bashで標準出力と標準エラー出力をスマートに統合してファイルに書き出す方法について詳しく解説します。
標準出力と標準エラー出力の基本概念
LinuxやUnixのシステムでは、コマンドの出力先を識別するために「ファイルディスクリプタ」という番号が割り当てられています。
標準出力(stdout)は「1」という番号で管理されており、通常のコマンド実行結果が表示されるストリームです。
一方で、標準エラー出力(stderr)は「2」という番号で管理され、エラーメッセージや警告が送出されるストリームです。
これらを適切に制御することが、シェルスクリプトにおける高度なログ管理の第一歩となります。
「&>」演算子を使用した最もシンプルな統合方法
Bashにおいて、標準出力と標準エラー出力をまとめてファイルに保存する最も簡潔な方法は、「&>」演算子を使用することです。
この記法を用いることで、コマンドから出力されるすべての情報を一つのファイルにリダイレクトできます。
従来の複雑な記述を短縮できるため、可読性の高いスクリプトを作成する際に非常に便利です。
# 標準出力と標準エラー出力を log.txt に保存する
ls -l /non_existent_dir /tmp > log.txt 2>&1
# 上記を Bash 特有の記法でスマートに記述する
ls -l /non_existent_dir /tmp &> output.log
上記の例では、存在しないディレクトリへのアクセスエラーと、正常なディレクトリのリスト表示の両方が output.log に書き込まれます。
ls: cannot access '/non_existent_dir': No such file or directory
/tmp:
total 0
...
追記モードでの保存方法
既存のファイルを上書きせずにログを末尾に追加していきたい場合は、「&>>」演算子を使用します。
バッチ処理や定期実行タスクにおいて、過去のログを保持しつつ新しい結果を記録したいシーンで多用されます。
# 実行結果を既存のログファイルに追記する
./my_script.sh &>> backup.log
伝統的な「2>&1」によるリダイレクトの仕組み
Bash以外のシェル(shなど)との互換性を重視する場合、「2>&1」という記法が現在でも広く使われています。
このコマンドの意味は、「ファイルディスクリプタ2(標準エラー)を、ファイルディスクリプタ1(標準出力)の現在の出力先に合流させる」というものです。
記述の順番が重要であり、必ず > file の後に 2>&1 を記述しなければなりません。
# 正しい記述順序
command > output.log 2>&1
# 誤った記述順序(エラーがファイルに保存されない)
command 2>&1 > output.log
誤った順序で記述すると、エラー出力がファイルではなく元の標準出力(画面)に向いてしまうため注意が必要です。
画面で見ながらファイルにも保存する「tee」コマンドの活用
ログをファイルに保存しつつ、リアルタイムでターミナル上でも出力を確認したい場合があります。
そのような場面では、「tee」コマンドとパイプラインを組み合わせる手法が非常に有効です。
この方法でも、標準出力と標準エラー出力を結合してから tee に渡す必要があります。
# 出力を統合して画面表示しつつファイルにも保存する
./my_script.sh 2>&1 | tee result.log
tee コマンドに -a オプションを付与すれば、追記モードでの保存も可能です。
# 画面に表示しながら追記保存する
./my_script.sh 2>&1 | tee -a result.log
リダイレクト演算子の比較一覧
状況に応じて最適な方法を選択できるよう、主要なリダイレクト演算子の違いを表にまとめました。
| 演算子 | 役割 | 特徴 |
|---|---|---|
> file 2>&1 | 統合・上書き | 高い互換性を持つ標準的な手法 |
&> file | 統合・上書き | Bash独自のスマートな短縮記法 |
>> file 2>&1 | 統合・追記 | ログを蓄積する際に使用 |
&>> file | 統合_追記 | Bash独自の追記用短縮記法 |
| tee file | 統合・表示・保存 | リアルタイム確認が必要な場合に最適 |
特定のセクションだけをまとめて出力する方法
スクリプト全体ではなく、特定のコマンド群の出力をまとめて一つのファイルに保存したい場合もあります。
その際は、「{ }(波括弧)」によるグループ化を利用すると効率的です。
複数のコマンドを一つのブロックとして扱い、そのブロック全体に対してリダイレクトを適用できます。
{
echo "--- 処理開始 ---"
ls /tmp
cp source.txt destination.txt
echo "--- 処理終了 ---"
} &> process.log
このように記述することで、個々のコマンドにリダイレクトを書く手間が省け、スクリプトの構造がスッキリします。
まとめ
Bashで標準出力と標準エラー出力をまとめて保存する方法には、いくつかのバリエーションがあります。
Bash環境であれば「&>」を使用するのが最もスマートで直感的な記述方法です。
一方で、移植性を考慮するスクリプトでは「2>&1」を使用し、画面確認を並行したい場合は「tee」を活用しましょう。
用途に合わせてこれらの手法を使い分けることで、トラブルシューティングが容易な信頼性の高いシェルスクリプトを構築できるようになります。
