パイプとリダイレクト入門 - データの流れを理解する

パイプとリダイレクト入門 - データの流れを理解する

この記事でできるようになること

  • `>` と `>>` で出力をファイルに保存・追記できる
  • `|` でコマンドをつないで結果を加工できる
  • `2>` と `2>&1` でエラー出力を分けたりまとめたりできる

前提知識(先に読むと理解しやすい記事)

この記事で学べること

  • 「データの流れ」 という考え方が分かります。
  • |(パイプ)と > >>(リダイレクト)の違いが分かります。
  • 「標準出力」「標準エラー出力」を使い分けられます。
  • grepsort を組み合わせて 小さなコマンドを連結 できるようになります。

結論(先に覚えるべき型)

  • 画面に出る結果を ファイルに保存 したいときは >>> を使います。
  • 結果を 次のコマンドに渡す ときは | を使います。
  • エラーだけ を別扱いにしたいときは 2> を使います。

先に知っておくこと:この記事で唯一注意が必要なのは > です。> は保存先のファイルを先に空にします。中身のあるファイルに > を使うと、その内容は消えます。

失敗するとどうなるか:消えた内容はゴミ箱に行きません。元には戻せません。

安全に試す方法:練習では ~/practice のような新しいディレクトリファイルをまとめて整理する入れ物。Windows や macOS の「フォルダ」と同じもの。を作り、そこで新しい名前のファイルに書き出してください。追記したいだけなら、最初から >> を使えば中身は消えません。本サイトの仮想ターミナル入力したコマンドを解釈してコンピュータに実行させる対話プログラム。は学習用なので、あなたのパソコンは壊れません。安心して試してください。

1. まずはここから:データはどこから来てどこへ行く?

結論: Linux コマンドは標準入力・標準出力・標準エラーの 3 つの口を持ち、行き先を付け替えられる。

リナ: 先輩、ls を実行すると画面にファイル名が出ますよね。あれってどこから出てるんですか?
ライニー先輩: いい質問だね。Linuxのコマンドは 「入力 → 処理 → 出力」 の3つの口を持っているんだ。図にするとこんな感じ。
ライニー先輩: 入力(標準入力 / stdin)→ コマンド → 出力(標準出力 / stdout)+ エラー(標準エラー出力 / stderr)
リナ: 入力と出力で口が分かれてるんですね。
ライニー先輩: そう。そして大事なのは、この口は付け替えできる ということ。画面に出してるものを、ファイルに切り替えたり、別のコマンドに渡したり。それが今日のテーマだよ。

言葉の整理:標準入力・標準出力・標準エラー出力は、英語では stdin・stdout・stderr と書きます。読み方は「エスティーディーイン」などですが、記事や本では英語表記のまま出てくることが多いです。どちらも同じものを指します。

3 つの口の名前

名前 略称 番号 デフォルトの行き先
標準入力 stdin 0 キーボード
標準出力 stdout 1 画面
標準エラー stderr 2 画面

2. リダイレクト:出力をファイルに保存する

結論: > は出力をファイルに上書き保存し、>> は追記する。大事なファイルには >> を使う。

2-1. > で上書き保存

$ ls > files.txt
リナ: 何も画面に出ません...失敗ですか?
ライニー先輩: 大丈夫。>画面ではなくファイルに行き先を切り替えた から、画面には出ないんだ。中身を見てごらん。
ライニー先輩: 中身を見るのは cat コマンド。ファイルの中身を画面に出すコマンドだよ。
$ cat files.txt
Documents
Downloads
files.txt
Pictures

2-2. >> で追記

$ echo "1行目" > log.txt
$ echo "2行目" >> log.txt
$ cat log.txt
1行目
2行目

>既存の中身を消して上書き する。大事なファイルに > を使うと内容が消える。追記したいときは必ず >> を使うこと。

中身が A のファイルに B を書き込んだ結果の比較図。cmd > file では A が B に置き換わり、cmd >> file では A の下に B が並ぶ

図1: 左が書き込む前のファイル、右が書き込んだ後の同じファイル。上下は別々のケースだ。> は元の A が消えて B だけになり、>> は A の後ろに B が並ぶ。

2-3. < で入力をファイルから取る(応用)

wc は数を数えるコマンドです。-l を付けると行数を数えます。

$ wc -l < log.txt
2
リナ: wc -l log.txt と何が違うんですか?
ライニー先輩: 結果はほぼ同じだけど、ファイル名がコマンドに渡らない のが違い。< は「キーボードの代わりにファイルを差し込む」イメージ。最初は >>> だけ覚えればOK。

3. パイプ:コマンドをつなぐ

結論: | は左のコマンドの出力を右の入力に渡す。小さなコマンドを連結して目的を達成する。

3-1. 基本形

|(縦棒、パイプ)は 「左のコマンドの出力を、右のコマンドの入力にする」 記号。

$ ls | wc -l
12
リナ: ls の結果を wc -l に渡してファイル数を数えてるんですね!
ライニー先輩: その通り。これがパイプの威力。1 つのコマンドで全部やる必要はなくて、小さなコマンドを連結して目的を達成する のがLinuxの流儀だよ。

cmd1 の stdout がパイプ記号を通って cmd2 の stdin につながる流れ図

図2: | は左のコマンドの出力(stdout)を、右のコマンドの入力(stdin)に差し込む。画面には出ず、そのまま次のコマンドへ渡る。エラー(stderr)はこの管を通らず、画面にそのまま出る。

3-2. よく使う組み合わせ

# ファイル一覧から「.txt」を含むものだけ抽出
$ ls | grep .txt

# プロセス一覧から nginx を含む行を抽出
$ ps aux | grep nginx

# ログを新しい順に表示
$ cat access.log | sort -r | head -n 10

パイプは何個でもつなげる

$ コマンド1 | コマンド2 | コマンド3 | ...

各段で「絞り込む」「並び替える」「整形する」と役割を分担させるのがコツ。

4. リダイレクトとパイプの違い

結論: > は出力先がファイル、| は出力先が次のコマンドの入力。保存なら >、加工なら |

リナ: 結果をどこかに送るのは同じに見えるんですけど、>| って何が違うんですか?
ライニー先輩: 行き先が違うんだ。図にするね。

>| の違い

cmd > file    →  出力先が【ファイル】
cmd | cmd2    →  出力先が【次のコマンドの入力】
  • > は保存したいときに使います。
  • | はもう一段加工したいときに使います。
# パターンA: ls の結果をファイルに保存
$ ls > list.txt

# パターンB: ls の結果を grep で絞り込む
$ ls | grep ".log"

# パターンC: 組み合わせ。grep で絞った結果をファイルに保存
$ ls | grep ".log" > log-files.txt

| でつないでから最後に > でファイル化、というのが実務で一番多いパターン。

5. 標準エラー出力(stderr)の扱い

結論: エラーは stderr(番号 2)から出る。2> で別ファイルに分け、2>&1 で標準出力にまとめる。

5-1. エラーは別の口から出ている

$ ls /not-exist > out.txt
ls: '/not-exist' にアクセスできません: そのようなファイルやディレクトリはありません
リナ: あれ? > out.txt でファイルに出したつもりなのに、エラーが画面に出てます...
ライニー先輩: それは エラーは標準エラー出力(stderr)から出ていて、> は標準出力(stdout)しか拾わない から。エラーを拾うには番号 2 を指定するんだ。
リナ: あ、そういうことか!出口が2つあって、> は片方しか拾わないんですね。エラーを取りたいときは 2> を使えばいいんですね。

5-2. エラーを別ファイルに分ける

$ ls /not-exist 2> error.log
(画面には何も出ない)
$ cat error.log
ls: '/not-exist' にアクセスできません: そのようなファイルやディレクトリはありません

5-3. 通常出力とエラーをまとめて1ファイルに

$ コマンド > all.log 2>&1

2>&1 の意味

標準エラー(2)を、標準出力(1)と同じ場所に流す」という指示。 ログ収集で頻出する書き方なので、形で覚えてしまうのがおすすめ。

書く順番に注意。2>&1 > all.log ではなく > all.log 2>&1 の順序が正しい。逆にすると stderr がリダイレクト前の場所(画面)に流れてしまう。

6. よくある初心者のつまずき

結論: 自分自身へのリダイレクトはファイルを空にする。tee を使えばパイプ途中の内容も保存できる。

6-1. > を使ったらファイルが空になった

$ cat important.txt > important.txt   # NG: ファイルが空になる

>コマンド実行前にファイルを空にする 動きをする。cat important.txt が読む前に中身が消えている。 自分自身に向けてリダイレクトしない のが鉄則。

6-2. | の前後にスペースが要る? 要らない?

どちらでも動く。ただし 読みやすさのため前後にスペースを入れる のが慣習。

$ ls|grep txt       # OK だが見づらい
$ ls | grep txt     # 推奨

6-3. パイプの途中の結果が見たい

$ ls | tee list.txt | wc -l

tee流れている内容をファイルに記録しつつ、そのまま次に渡す コマンド。デバッグや「途中経過も保存しておきたい」ときに便利。

7. ミニ課題:実際にやってみよう

結論: 保存・件数カウント・絞り込み保存の 3 問で、リダイレクトとパイプの基本を手で確かめる。

リナ: 知識は入りました! 実際に手を動かしてみたいです。
ライニー先輩: いいね、3問用意したよ。ターミナルで試してみて。

課題1: 自分のホームディレクトリのファイル一覧を home-files.txt に保存しよう。

ヒント1(方向づけ)を見る

一覧を出すコマンドは知っていますね。その結果の行き先を、画面からファイルに付け替えます。

ヒント2(コマンド名)を見る

使うのは ls です。行き先を変える記号は > です。ホームディレクトリは ~ で表します。

答えを見る
$ ls ~ > home-files.txt
$ cat home-files.txt
Documents
Downloads
Pictures
home-files.txt

> はコマンドを動かす前にファイルを作ります。そのため home-files.txt 自身も一覧に入ります。中身はお使いの環境で変わります。

課題2: /etc 以下のファイル数を数えて画面に表示しよう(パイプを使う)。

ヒント1(方向づけ)を見る

一覧を出すコマンドの結果を、行数を数えるコマンドに渡します。ファイルには保存しません。

ヒント2(コマンド名)を見る

使うのは lswc です。行数を数えるオプションは -l、2つをつなぐ記号は | です。

答えを見る
$ ls /etc | wc -l
220

表示される数はお使いの環境で変わります。数字が1つだけ出れば成功です。

課題3: /etc の中で .conf で終わるファイルだけ取り出して、conf-list.txt に保存しよう。

ヒント1(方向づけ)を見る

一覧を出し、そこから条件に合う行だけを残し、最後にファイルへ保存します。3段構えです。

ヒント2(コマンド名)を見る

使うのは lsgrep です。つなぐのは |、保存するのは > です。「.conf で終わる」は "\.conf$" と書きます。

答えを見る
$ ls /etc | grep "\.conf$" > conf-list.txt
$ cat conf-list.txt
adduser.conf
ca-certificates.conf
debconf.conf
nsswitch.conf
resolv.conf

grep "\.conf$"$ は「行末」を意味する正規表現です。そのため「.conf で終わる行」だけが残ります。並ぶファイル名はお使いの環境で変わります。

8. 振り返り

結論: 行き先がファイルなら >、次のコマンドなら |。エラーは別の口から出る。この3点を言葉にして確認する。

リナ: 保存したいときは >、次のコマンドに渡したいときは | なんですね。
ライニー先輩: その通り。> は行き先がファイル、| は行き先が次のコマンド。ここさえ押さえれば迷わないよ。
リナ: エラーが画面に残ったのは、エラーだけ別の口から出ていたからでしたね。
ライニー先輩: うん。エラーも一緒に記録したいときは > ファイル名 2>&1 と書けばいいよ。

9. 今日の3行まとめ

結論: リダイレクト・パイプ・エラー出力の3点を3行で整理して定着させる。

  1. > は上書き保存、>> は追記。中身を消したくないときは >> を使う
  2. | は左のコマンドの結果を右のコマンドに渡す
  3. エラーは別の口(2番)から出る。2> で分け、2>&1 でまとめる

10. コピペ用テンプレート

結論: 保存・追記・絞り込み・ログ収集・途中保存のよく使う型をまとめて手元に置いておく。

よく使う型をまとめておく

# 結果をファイルに保存(上書き)
コマンド > out.txt

# 結果をファイルに追記
コマンド >> out.txt

# 結果を絞り込む
コマンド | grep キーワード

# 結果を並び替えて先頭10件
コマンド | sort | head -n 10

# 通常出力とエラーをまとめて記録
コマンド > all.log 2>&1

# エラーだけ別ファイルに
コマンド 2> error.log

# 途中経過もファイルに残しつつ次へ
コマンド | tee progress.txt | 次のコマンド

次に読む