【Linux】リダイレクトとパイプの使い方|>・>>・2>&1の順序・/dev/null・tee

【Linux】リダイレクトとパイプの使い方|>・>>・2>&1の順序・/dev/null・tee Linux

コマンドの結果をファイルに保存する>(リダイレクト)と、コマンドの出力を次のコマンドへ渡す|(パイプ)は、Linuxの操作の土台です。さらに、エラーメッセージだけを分けて記録する2>や、すべてをまとめる2>&1を理解すると、ログの記録やcronの設定で迷わなくなります。

つまずきやすいのは、>が「上書き」で、既存の内容が消えること、そして2>&1は書く位置(順序)で結果が変わることです。とくに後者は、知らないと「エラーがファイルに入らない」と悩む定番の罠です。この記事では、実機のLinux(WSLのDebian)で標準出力とエラーを実際に分けたり混ぜたりしながら、リダイレクトとパイプを整理します。

先に結論

  • >上書き保存>>追記です。
  • 出力には2種類あります:標準出力(1)標準エラー(2)
  • エラーだけ保存するのは2>、両方まとめるのは> file 2>&1です。
  • 2>&1> fileの「後」に書きます。先に書くと合流しません。
  • 要らない出力は/dev/nullに捨てます(2>/dev/nullでエラーを非表示)。
  • |(パイプ)には標準出力だけが流れます。teeで画面とファイル両方に出せます。

パイプ先の定番コマンドはgrep(絞り込み)awk(列抽出・集計)、ほかの基本はよく使うLinuxコマンドまとめもあわせて参考になります。

スポンサーリンク

リダイレクトの基本(> と >>)

コマンドの結果を画面ではなくファイルに書き出すのがリダイレクトです。>は上書き、>>は追記という違いがあります。

> は上書き・>> は追記
# > : ファイルに保存(既存の内容は消えて上書き)
echo "one" > f.txt
echo "two" > f.txt
cat f.txt        # two(one は消えた!)

# >> : ファイルの末尾に追記(既存の内容は残る)
echo "one" > g.txt
echo "two" >> g.txt
cat g.txt        # one と two の両方が残る
>は既存の中身を消す

実機で確認したところ、echo "one" > f.txtのあとにecho "two" > f.txtとすると、ファイルの中身はtwoだけになり、最初のoneは消えました。>はファイルを毎回作り直す「上書き」です。一方、>>で書いたファイルにはonetwoの両方が残りました。ログのように書き足していきたいときに>を使ってしまうと、実行のたびに過去の記録が消えます。「積み上げたいなら>>、作り直してよいなら>」と使い分けてください。既存の大事なファイル名を>の右に書いてしまう事故にも注意が必要です。

標準出力と標準エラー(1と2)

コマンドの出力には、実は2つの経路があります。通常の結果が流れる標準出力(stdout・番号1)と、エラーメッセージが流れる標準エラー(stderr・番号2)です。>だけでは標準出力しか保存されません。

エラーは別の経路
# 存在するファイルと存在しないファイルを ls すると…
ls f.txt nofile.txt > result.txt
# 画面: ls: cannot access 'nofile.txt': No such file or directory(エラーは画面に残る)
# result.txt: f.txt(正常な結果だけ保存される)

# 2> でエラーだけをファイルへ
ls f.txt nofile.txt > result.txt 2> error.txt
# result.txt: 正常な出力 / error.txt: エラーメッセージ

実機でも、正常出力とエラーを両方出すコマンドに> out.txt 2> err.txtを付けると、out.txtには正常な出力(OUT)だけ、err.txtにはエラー(ERR)だけが分かれて保存されました。>は正確には1>(標準出力のリダイレクト)の省略形で、エラーを保存したいなら2>と明示する必要があります。「ファイルに保存したはずのエラーが画面に出てくる」のは、この2経路が理由です。

【最重要】2>&1 と順序の罠

正常な出力もエラーも1つのファイルにまとめたいときは2>&1を使います。「2(エラー)を1(標準出力)と同じ場所へ」という意味です。ここで絶対に押さえたいのが、書く順序です。

2>&1 の正しい順序
# OK: > file の「後」に 2>&1 → 両方ファイルに入る
command > all.txt 2>&1

# NG: 2>&1 を「先」に書く → エラーはファイルに入らず画面に出る
command 2>&1 > all.txt

# cron やスクリプトのログ記録の定番形
./backup.sh >> backup.log 2>&1
2>&1は「> fileの後ろ」が正解

実機で確認したところ、command > both.txt 2>&1ではOUTとERRの両方がファイルに入りました。ところが順序を逆にしたcommand 2>&1 > wrong.txtでは、ファイルにはOUTしか入らず、ERRは画面に表示されました。リダイレクトは左から順に処理されるためです。2>&1を先に書くと「その時点での標準出力=画面」にエラーが向けられ、その後で標準出力だけがファイルに切り替わるので、エラーは画面に残ってしまいます。「まず> fileで出力先を決めて、その後2>&1でエラーを合流させる」という順序で覚えてください。cronのログ設定で「エラーが記録されない」というトラブルは、ほぼこの順序ミスが原因です。

/dev/null に捨てる

出力が要らないときは、何を書き込んでも消える特別なファイル/dev/nullにリダイレクトします。エラーメッセージを非表示にしたり、結果を完全に捨てたりできます。

/dev/null で出力を捨てる
# エラーメッセージだけを非表示にする(正常な出力は見える)
command 2>/dev/null

# 正常な出力を捨てて、エラーだけを見る
command >/dev/null

# 何も表示しない(両方捨てる)
command >/dev/null 2>&1

実機でも、2>/dev/nullを付けるとエラー(ERR)が消えて正常出力(OUT)だけが表示され、逆に>/dev/nullではOUTが消えてエラーだけが残りました。findのように「権限エラーが大量に出るコマンド」で2>/dev/nullを付けて結果だけを見やすくする、cronで通知を止めるために>/dev/null 2>&1にする、といった使い方が定番です。ただしエラーを捨てると問題に気づけなくなるため、本番のスクリプトではログに残すほうが安全です。

パイプ(|)とtee

|(パイプ)は、コマンドの出力を次のコマンドの入力へ渡します。ここで知っておきたいのは、パイプに流れるのは標準出力だけ(エラーは流れない)ということです。画面とファイルの両方に出したいときはteeを使います。

パイプと tee
# パイプ: 出力を次のコマンドへ(grep で絞り込みなど)
ps aux | grep nginx
cat access.log | awk '{print $1}' | sort | uniq -c

# パイプにはエラーは流れない(エラーも含めて渡すなら 2>&1 |)
command 2>&1 | grep "error"

# tee: 画面に表示しつつファイルにも保存
./build.sh | tee build.log

# tee -a で追記
./build.sh | tee -a build.log
パイプはstdoutのみ・両取りはtee

実機で確認したところ、エラーを出すコマンドをパイプでgrepにつなぐと、grepに届いたのは標準出力の行だけで、エラーはパイプを通りませんでした。エラーも含めて次のコマンドへ渡したいときは、command 2>&1 | grep ...のようにパイプの前で2>&1を付けます(この位置なら正しく合流します)。また、echo hello | tee t.txtでは、画面に表示されると同時にファイルt.txtにもhelloが保存されました。ビルドやデプロイのログを「目で追いつつ記録も残す」場面でteeは重宝します。追記したいときはtee -aです。

主な書き方一覧

リダイレクトとパイプの主な書き方をまとめます。

書き方 働き
> file 標準出力を上書き保存
>> file 標準出力を追記
2> file エラーだけを保存
> file 2>&1 両方をfileへ(順序に注意)
2>/dev/null エラーを捨てる(非表示)
cmd1 | cmd2 出力を次のコマンドへ(stdoutのみ)
| tee file 画面とファイルの両方へ

よくある失敗

>でログが毎回消える

>は上書きです。積み上げるログには>>を使います。

2>&1を先に書いてエラーが記録されない

順序は> file 2>&1です。2>&1 > fileではエラーが画面に残ります。

エラーがファイルに入らない

>は標準出力だけです。エラーは2>2>&1で扱います。

パイプ先にエラーが届かない

パイプはstdoutのみです。エラーも渡すなら2>&1 |とします。

エラーを全部捨てて問題に気づけない

2>/dev/nullの常用は危険です。本番ではログに残します。

よくある質問

Q>と>>の違いは何ですか?
A>はファイルを上書き(既存の内容は消える)、>>は末尾への追記(既存の内容は残る)です。実機でも、>で2回書き込むと最初の内容が消え、>>では両方残ることを確認しています。ログのように積み上げたいときは>>を使ってください。
Q2>&1とはどういう意味ですか?
A「標準エラー(2)を、標準出力(1)と同じ場所に向ける」という意味です。command > file 2>&1と書くと、正常な出力もエラーも1つのファイルにまとめて保存できます。cronやスクリプトのログ記録の定番の書き方です。
Q2>&1を書いたのにエラーがファイルに入りません。
A書く順序が原因です。リダイレクトは左から処理されるため、command 2>&1 > fileのように先に書くと、エラーは「その時点の標準出力=画面」に向いてしまいます。command > file 2>&1のように、> fileの後ろに2>&1を書いてください。
Qエラーメッセージだけを非表示にするには?
Acommand 2>/dev/nullとします。標準エラーが/dev/null(書き込むと消える特別なファイル)に捨てられ、正常な出力だけが表示されます。ただしエラーを捨てると問題に気づけなくなるため、本番のスクリプトではファイルに記録するほうが安全です。
Q画面に表示しながらファイルにも保存するには?
Acommand | tee ファイル名を使います。パイプで受け取った内容を、画面とファイルの両方に出力します。追記したい場合はtee -aです。ビルドログを目で追いながら記録に残す、といった場面で便利です。

まとめ

  • >上書き>>追記。ログには>>を使います。
  • 出力は標準出力(1)とエラー(2)の2経路。エラーは2>で扱います。
  • 両方まとめるのは> file 2>&1(この順序)。逆だと合流しません。
  • 不要な出力は/dev/nullへ。ただしエラーの捨てすぎに注意。
  • パイプ|stdoutのみ。両取りはtee、エラーも渡すなら2>&1 |

リダイレクトとパイプは、Linuxのあらゆる操作の基礎になる仕組みです。「>は上書き」「2>&1は後ろに書く」の2点さえ体で覚えれば、cronのログ設定もエラーの切り分けも自信を持って書けるようになります。grepawkとパイプでつなぎ、Linuxらしいコマンドの組み立てを楽しんでください。