0. はじめに
職業柄仕事で良くコードを書くのですが、ここ1年くらいGenAIの進化が凄まじく、手でコードを書くことが無くなってきました。
最近自分はClaude Codeにコードを書いてもらうことが多いですが、エディタやCLI上でClaude君が頑張っているのを眺めていると、よく以下の様なコマンドを実行しているのを目にすることが多いと思います。
※自分はMacなので、Unix系に限る
command 2>&1
command 2>/dev/null
Claude君には、rmのような破壊的なコマンドは、必ず自分の承認を挟むようにしていました。
ただ、「2>&1」や「2>/dev/null」は破壊的なコマンドでは無いことは知りつつ、何をやっているコマンドなのかを理解しないまま放置しているなと、ふと思ったので調査して記事にしてみる。
1. コマンドを分解して考える
まず、「2>&1」や「2>/dev/null」を分解してみるとこうなる。
2>&1
・2(ファイルディスクリプタ番号)
・>(リダイレクト)
・&1(ファイルディスクリプタ番号1の複製)
2>/dev/null
・2(ファイルディスクリプタ番号)
・>(リダイレクト)
・/dev/null(コマンド出力のゴミ箱 ※実態はファイルで、出力先に指定すると出力が消える)
分解すると「ファイルディスクリプタ」、「リダイレクト」、「/dev/null」に分けられる。
さらにこの3つについて調べてみる。
1.1 ファイルディスクリプタとは
結論から言うとファイルディスクリプタとは、
プロセスがアクセスするファイルを識別する整数値である
ちょっと最初は理解できなかったが、Linuxの重要な思想である「Everything is a file」という言葉を聞くと少し理解しやすい。
「Everything is a file」というのは、Linux上に出てくるすべてのリソースをファイルとして扱うということで、通常のファイルだけでなく、デバイスやプロセス、ネットワーク、インターフェースと全てをファイルとして扱うということ。
※以下参照
https://chotdekiru.com/learn/courses/linux-basics/filesystem-everything-is-file
そこで、「2>&1」や「2>/dev/null」とどういう関係があるかというと、ファイルディスクリプタには3つの予約された番号がある。
それが以下の3つ。
・0 標準入力(stdin)
・1 標準出力(stdout)
・2 標準エラー出力(stdout)
※ターミナルで考えると分かりやすい
sample@hogehoge ~ % ls test.txt no_exist.txt #標準入力
ls: no_exist.txt: No such file or directory #標準エラー出力
test.txt #標準出力
ここまででファイルディスクリプタ番号の0,1,2がターミナル上の入出力のことを表しているんだな〜程度まで理解できれば良さそう
1.2 リダイレクトとは
結論から言うとLinuxにおけるリダイレクトとは、標準入力や標準出力の向き先を変更するコマンドである
※これは結構使うコマンドなのでなんとなく皆んな知っていると思う
コマンドで試してみると分かりやすい
sample@hogehoge ~ % echo test # 普通の出力
test
sample@hogehoge ~ % echo test > output.txt #出力値をoutput.txtに送る(新規作成)
sample@hogehoge ~ % cat output.txt #ファイルの中身を表示
test
sample@hogehoge ~ % echo test2 >> output.txt #出力値をoutput.txtに送る(上書き)
sample@hogehoge ~ % cat output.txt #ファイルの中身を表示
test
test2
リダイレクトについては上記以外も色々と使い方があるが、深掘りすぎると調査と、書くのが面倒なので、ここまでにする。
ひとまず矢印の方向に値を向かわせるイメージでいれば良いと思う。
1.3 /dev/nullとは
結論から言うと「/dev/null」とは、書き込まれた情報を全て無視するファイルである
自分は最初は勝手にコマンドだと思っていたのですが、良く考えたらファイルだと気づきました。。
※以下の通り、実際に存在するファイル
sample@hogehoge ~ % ls -la /dev/null
crw-rw-rw- 1 root wheel 0x3000002 6月 13 17:05 /dev/null
このファイルの役割としては、前述の通りで、書き込まれた出力を無視することです。
実際に使ってみると、以下の様に、「/dev/null」ファイルに値を書き込むとターミナル上で出力が消えます。
sample@hogehoge ~ % echo test
test
sample@hogehoge ~ % echo test > /dev/null
sample@hogehoge ~ %
これは通常のファイルへの書き込みでも同じ動作ですが、通常のファイルとの一番の違いとしては、「/dev/null」ファイルにデータが書き込まれるわけではなく、データが破棄されるため、容量を取らないことです。
そのため、よく「データのブラックホール」とも称されます。
2. 各コマンドのやっていることをまとめる
ここまでの知識を使って、最初の疑問である「2>&1」や「2>/dev/null」が何をしているのかをまとめてみる。
2.1 「command 2>&1」のやっていること
分解した結果から考えると以下の通りである。
command 2>&1
-
2:標準エラー出力(stderr)のファイルディスクリプタ -
>&1:ファイルディスクリプタ1(標準出力 / stdout)にリダイレクト
つまり、「標準エラー出力をファイルディスクリプタ1が指している先(ターミナル)に向ける」という意味
sample@hogehoge ~ % ls test.txt no_exist.txt 2>&1
test.txt
ls: no_exist.txt: No such file or directory
ただここで「そんなのデフォルトと同じ挙動じゃないか???」と思ったので、Claudeに聞いてみら以下の様な回答が帰ってきました。

要するに、ただ確実にエラーを検知するために表示させていただけと言う結論に至りました。。
2.2 「command 2>/dev/null」のやっていること
分解した結果から考えると以下の通りである。
command 2>/dev/null
-
2:標準エラー出力(stderr)のファイルディスクリプタ -
>/dev/null:/dev/null(データを破棄するファイル)にリダイレクト
つまり、「標準エラー出力をデータのブラックホール(/dev/null)に向ける」という意味
結果的に、標準エラー出力だけが消え、標準出力のみターミナルに表示される。
sample@hogehoge ~ % ls test.txt no_exist.txt 2>/dev/null
test.txt
# ls: no_exist.txt: No such file or directory が消えている
実用的な活用例
# 存在するファイルだけを表示したい(エラーメッセージは不要)
find / -name "important_file.txt" 2>/dev/null
# 存在しないディレクトリへのアクセスエラーなどが表示されず、
# 見つかったファイルのパスだけが画面に出力される
2.3 「command > /dev/null 2>&1」のやっていること
最後に、この2つを組み合わせたパターンについても触れておく。
command > /dev/null 2>&1
-
> /dev/null:標準出力(fd 1)をデータのブラックホール(/dev/null)に向ける -
2>&1:標準エラー出力(fd 2)をfd 1の先(/dev/null)に向ける
つまり、「標準出力と標準エラー出力の両方をブラックホールに向ける」という意味
結果的に、すべての出力がターミナルから消える。
sample@hogehoge ~ % ls test.txt no_exist.txt > /dev/null 2>&1
sample@hogehoge ~ % # 何も表示されない
実用的な活用例
# バックグラウンドで実行するコマンドの出力を完全に無視したい
# (cron jobやスクリプト内でよく使われる)
command > /dev/null 2>&1 &
# 何か処理をしているが、成功・失敗問わず出力は不要な場合
./cleanup_script.sh > /dev/null 2>&1

