Linuxのリダイレクトとパイプ入門|初心者でも迷わないコマンド連携の基本

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOMELinux技術 リナックスマスター.JP(Linuxマスター.JP)【Linux入門】初心者のための基礎知識・講座 > Linuxのリダイレクトとパイプ入門|初心者でも迷わないコマンド連携の基本
「lsの結果をファイルに保存したいけど、コピペするしかないの?」
「エラーメッセージだけを別のファイルに残したい」
Linuxを触り始めた人が、最初にぶつかる壁がこれです。

この記事では、Linuxのリダイレクトパイプについて、完全初心者向けに手順と実行例で解説します。
ターミナルの使い方に少し慣れてきた段階で読むと、コマンドの世界が一気に広がります。
Ubuntu 24.04 LTS / Rocky Linux 9 / WSL2環境で動作確認済みです。

この記事のポイント

・リダイレクト「>」でコマンドの結果をファイルに保存できる
・パイプ「|」で前のコマンドの出力を次のコマンドに渡せる
・「2>」でエラーだけ、「&>」「2>&1」で出力をまとめてファイルに書ける
・xargsを使うとパイプ結果をコマンドの引数として扱える
・ヒアドキュメント「<<EOF」でスクリプト内に複数行テキストを書ける


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
図解60P/登録10秒/解除も3秒 / 詳細はこちら

なぜリダイレクトとパイプを覚えるのか?(背景・原理)

Linuxのコマンドは、ひとつひとつが小さな道具です。
ひとつで完結するものは少なく、つなげて使うことで本来の力を発揮します。

そのつなぎ役がリダイレクトとパイプです。
リダイレクトは「コマンドの出力先をファイルに切り替える」機能、パイプは「前のコマンドの出力を次のコマンドに渡す」機能です。
この2つを理解すると、次のようなことが1行でできるようになります。

・ディレクトリ一覧をテキストファイルに保存する
・ログから特定のキーワードを含む行だけ取り出す
・エラーメッセージだけを別ファイルに記録する
・コマンド結果を画面で見つつ、同時にファイルにも残す

コピペや手作業で頑張っていた作業が、一気に自動化の入り口に変わります。
WindowsでいうとエクスプローラーやExcelで人手でやっていたファイル操作・集計が、1行のコマンドで自動化できるイメージです。

Linuxには「標準入力(stdin)」「標準出力(stdout)」「標準エラー出力(stderr)」という3本の流れ(ストリーム)があり、リダイレクトとパイプはこれらを切り回す仕組みです。
OSの内部では、それぞれにファイルディスクリプタ番号が割り振られています。

標準入力(0 / stdin):コマンドへのデータの流れ込み口(キーボード入力など)
標準出力(1 / stdout):正常な結果の出口(通常はターミナル画面)
標準エラー出力(2 / stderr):エラーメッセージ専用の出口(同じく画面)

この番号が「2>」や「2>&1」のような構文の「2」に直結しています。
「2>」は「ファイルディスクリプタ2(stderr)をファイルへ向け直す」という意味です。
記号の意味をこう理解しておくと、応用構文を見たときに「なぜそう書くのか」が腑に落ちやすくなります。

リダイレクトはこの出口をファイルに切り替え、パイプは出口を次のコマンドの入口につなぎます。

まずはリダイレクト「>」で結果をファイルに保存する

リダイレクトは「出力先を切り替える」機能です。
普段、コマンドの結果は画面(ターミナル)に表示されますが、これをファイルに向け直せます。

1. ls の結果をファイルに書き出す

ホームディレクトリの一覧を、file.txtというファイルに保存してみます。

# カレントディレクトリの一覧をファイルに保存 $ ls > file.txt # 中身を確認 $ cat file.txt Desktop Documents Downloads Pictures file.txt

「>」の右側に書いたファイル名に、lsの結果がまるごと書き込まれます。
画面には何も表示されません。これで正常です。
リダイレクト先のファイルが存在しない場合は自動で新規作成されるので、touchで先に作る必要はありません。

2. 上書きと追記の違いを覚える

ここが初心者のつまずきポイントです。

>(上書き):毎回ファイルを空にしてから書き込む
>>(追記):既存の中身は残したまま末尾に書き足す

# 上書き(以前のfile.txtの内容は消える) $ date > file.txt $ cat file.txt Mon May 4 12:30:01 JST 2026 # 追記(前の内容の下に日時が追加される) $ date >> file.txt $ cat file.txt Mon May 4 12:30:01 JST 2026 Mon May 4 12:30:15 JST 2026

大事なファイルを誤って「>」で潰してしまう事故はよくあります。
一度実行するとファイルの中身は戻ってこないので注意してください。
ログのように「履歴を残したい」用途では必ず「>>」を使うクセをつけてください。

なお、上書き事故を防ぐシェルオプションとして「noclobber」があります。
設定しておくと「>」での既存ファイル上書きをシェルがエラーにしてくれます。

# noclobberを有効にする $ set -C # 既存ファイルへの上書きリダイレクトがエラーになる $ date > file.txt bash: file.txt: cannot overwrite existing file # 強制上書きしたいときは |> を使う(noclobber無効化上書き) $ date |> file.txt # noclobberを解除する $ set +C

本番サーバーの設定ファイルをうっかり上書きしそうな場面で活用できます。

3. エラーメッセージだけをファイルに分ける

先ほど説明した標準出力(1)と標準エラー出力(2)を使い分けます。
「2>」を使うと、エラー(標準エラー出力)だけを別のファイルに書き出せます。

# 存在しないファイルをlsした場合 $ ls /not_exist_dir 2> error.log # error.logにエラーだけ記録される $ cat error.log ls: cannot access '/not_exist_dir': No such file or directory

正常出力とエラー出力を両方まとめて1つのファイルに入れたいときは「&>」が便利です。

# 正常出力もエラーも all.log に全部入れる(bash拡張構文) $ ls /etc /not_exist_dir &> all.log # 中身を確認すると、正常出力とエラーが混ざって記録されている $ cat all.log ls: cannot access '/not_exist_dir': No such file or directory /etc: NetworkManager bash.bashrc hosts (以下省略)

「&>」はbash固有の構文です。sh(POSIX sh)でも動く書き方が「> ファイル 2>&1」で、意味は同じです。
cronスクリプトのログ記録でよく使うパターンなので、どちらの書き方も覚えておくと後で必ず助かります。

4. ヒアドキュメント(<<EOF)で複数行テキストをコマンドに渡す

「<<」は「ここに書いた複数行テキストをコマンドの標準入力に渡す」機能です。
ヒアドキュメント(here-document)と呼ばれ、スクリプト内でファイルを外から用意せずに複数行を入力したいときに使います。

# catでヒアドキュメントをファイルに書き出す $ cat > /etc/motd << EOF Welcome to my server. Please read the rules before proceeding. EOF # シェルスクリプト内でsshに複数コマンドをまとめて渡す $ ssh user@remote-server << EOF sudo systemctl restart nginx sudo systemctl status nginx EOF

「EOF」は「End Of File」の慣用語で、区切り文字は任意の単語が使えます(「SCRIPT」「TEXT」でも動きます)。
変数展開を防ぎたい場合は先頭に「'」を付けて「<<'EOF'」と書きます。

1行だけ渡す場合は「<<<」(ヒアストリング)も便利です。

# 1行の文字列をbase64に渡す $ base64 <<< "hello world" aGVsbG8gd29ybGQK # grepに文字列を渡して判定する(パイプのecho代替) $ grep -q "root" <<< "root:x:0:0:root:/root:/bin/bash" && echo "found" found

ヒアドキュメント・ヒアストリングを知っておくと、シェルスクリプトで「一時ファイルを作らずにデータを渡す」設計ができるようになります。
現場でスクリプトを書くときに覚えておくと、コードがすっきりします。

パイプ「|」でコマンドをつなげる

パイプは「前のコマンドの結果を、次のコマンドの入力に渡す」機能です。
記号は縦棒「|」。日本語キーボードでは Shift + ¥(円マーク)で入力します。

1. ファイル一覧を less で1画面ずつ見る

/etcディレクトリのように、ファイル数が多すぎて画面からあふれてしまう場合があります。
そのままlsするとスクロールが追いつきません。

# lsの結果をlessに渡して、1画面ずつ表示する $ ls /etc | less

lessは「スペースキーで次ページ、bで前ページ、qで終了、/で文字列検索」の使い勝手のいいビューアです。
パイプで渡せば、どんなコマンドの結果にも使えます。

2. grep と組み合わせて「必要な行だけ」抜き出す

パイプの真価が出るのがgrepとの組み合わせです。
grepは「指定した文字を含む行だけを表示する」コマンドです。

# 起動中のプロセスから「nginx」を含む行だけ表示 $ ps aux | grep nginx nginx 1234 0.0 0.5 56432 5120 ? S 10:00 0:00 nginx: master process nginx 1235 0.0 0.3 56988 3072 ? S 10:00 0:00 nginx: worker process # /etc配下のファイルからconfを含むファイル名だけ表示 $ ls /etc | grep conf resolv.conf nsswitch.conf sysctl.conf # -v オプションで「含まない行」だけ表示(grep自身を除外する定番パターン) $ ps aux | grep nginx | grep -v grep nginx 1234 0.0 0.5 56432 5120 ? S 10:00 0:00 nginx: master process nginx 1235 0.0 0.3 56988 3072 ? S 10:00 0:00 nginx: worker process

「grep nginx」を実行すると自分自身(grep nginx というプロセス)も結果に含まれてしまいます。
「grep -v grep」を追加してgrepプロセスを除外するのが現場の定番パターンです。
これを覚えるだけで、ログ調査や設定ファイル探しのスピードが段違いになります。

3. wc -l で行数を数える

パイプは何段でもつなげられます。

# /etc配下のファイル数を数える $ ls /etc | wc -l 214 # ログの中で「error」を含む行数を数える $ cat /var/log/syslog | grep error | wc -l 17 # 起動中のnginxワーカープロセス数を数える $ ps aux | grep nginx | grep -v grep | wc -l 2

「ls → grep → wc -l」のように、小さな道具をつなぐ発想がLinuxらしさです。
1つのコマンドで全部やろうとせず、それぞれ得意なコマンドを直列につなぐのが正解です。

4. sort と uniq で「集計」する

ログから「同じ単語が何回出ているか」を数えるのも、パイプの定番パターンです。

# アクセスログから接続元IPを上位5件抽出 $ awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -5 1043 192.168.1.10 827 192.168.1.22 415 192.168.1.30 198 192.168.1.55 47 192.168.1.78

awkで1列目だけ取り出し、sortで並べ替え(uniqは隣接行しか比較しないため事前sort必須)、uniq -cで重複行をカウント、sort -rnで多い順に並べる。
小さなコマンドを5段つないだだけで、立派な集計ツールになります。

障害調査でアクセス集中元を探すとき、このワンライナーは本当によく使います。

5. xargs でパイプ結果をコマンドの「引数」に変換する

パイプは「標準入力」にデータを渡しますが、コマンドによっては引数でしかデータを受け取れないものがあります。
そういうときに使うのがxargsです。

# findで見つけたファイルをxargsでrmに渡す(30日以上前の.tmpファイルを一括削除) $ find /tmp -name "*.tmp" -mtime +30 | xargs rm -f # grepで見つかったファイルにchmodを一括適用 $ find /home/user/scripts -name "*.sh" | xargs chmod +x # ファイルの中身(URL一覧)を1行ずつcurlに渡す $ cat url_list.txt | xargs -I{} curl -s {} -o /dev/null -w "%{http_code}\n"

xargsの「-I{}」は「渡されたデータをここに挿入する」という意味です。
ファイル名にスペースが含まれる場合は「xargs -d '\n'」や「xargs -0」(null区切り)を組み合わせると安全です。
一括処理の場面でパイプとxargsの組み合わせは定番になるので、頭の片隅に置いておくと便利です。

応用・実務Tips

1. リダイレクトとパイプを組み合わせる

ここまで来たら、両方を一緒に使えます。

# syslogからerrorを含む行を抽出して、result.txtに保存 $ cat /var/log/syslog | grep error > result.txt # psの結果から特定プロセスを抜き出して追記保存 $ ps aux | grep nginx >> nginx_check.log # 直近1時間のエラーをカウントしてログに追記 $ awk -v since="$(date -d '1 hour ago' '+%Y-%m-%dT%H')" '$0 ~ since' /var/log/syslog | grep -i error | wc -l >> /var/log/hourly_error_count.log

これは現場でも本当によく使います。
調査系の作業はほぼこの形で済むと言ってもいいくらいです。

2. tee で「画面表示しつつファイルにも保存」する

パイプで結果をファイルに送ると、画面には何も出なくなります。
「画面でも確認したいし、同時にファイルにも残したい」というときはteeコマンドが便利です。

# 画面表示と同時にlog.txtにも書き込む $ ls /etc | tee log.txt NetworkManager bash.bashrc hosts (以下省略) # -aオプションで追記モード $ date | tee -a log.txt # パイプの途中で挟んでデバッグに使う $ cat /var/log/syslog | grep error | tee /tmp/errors.txt | wc -l

長時間かかるコマンドの進捗を画面で見ながら結果も残す、という用途で重宝します。
パイプの途中に tee を挟むと「ここまでの中間結果を保存しつつ次の処理に渡す」デバッグ技としても使えます。

3. /dev/null で「いらない出力を捨てる」

エラー出力が多くて邪魔なときは「2> /dev/null」で捨ててしまえます。
/dev/null は何を入れても消えるLinux特有の「ブラックホール」です。

# findで権限エラー(Permission denied)が大量に出るのを抑制 $ find / -name "*.conf" 2> /dev/null # 正常出力もエラーも全て捨てる(cron等で結果を見ない場合) $ some_command > /dev/null 2>&1

「> /dev/null 2>&1」はcronスクリプトの定番イディオムです。
意味は「標準出力(1)を/dev/nullへ → さらに標準エラー出力(2)を標準出力(1)と同じ場所へ転送」。
2つの記述順序に注意が必要で、「2>&1 > /dev/null」と逆に書くとエラーだけ残る挙動になります。

4. cronスクリプトでのログ記録パターン

cronで自動実行するスクリプトは、実行結果をファイルに残しておかないと「動いたかどうか」がわかりません。
現場でよく使う3パターンを整理します。

# パターン1: 正常出力だけログに残す(エラーは捨てる) 0 2 * * * /home/user/scripts/backup.sh > /var/log/backup.log 2>/dev/null # パターン2: 正常・エラー両方をログに残す(最も一般的) 0 2 * * * /home/user/scripts/backup.sh >> /var/log/backup.log 2>&1 # パターン3: 完全サイレント(ログも通知も不要な場合のみ) 0 2 * * * /home/user/scripts/cleanup.sh > /dev/null 2>&1

パターン2の「>> logfile 2>&1」は「追記モードで正常出力を記録しつつエラーも同じログに流す」です。
毎回上書きではなく追記にする理由は、前回の実行ログが消えてしまうと原因調査ができなくなるからです。

また、crontabのバックアップ自体もリダイレクトで一発でできます。

# 現在のcrontabをファイルに保存(バックアップ) $ crontab -l > ~/crontab_backup.txt # 保存したバックアップを確認 $ cat ~/crontab_backup.txt

5. AIツールと組み合わせて学習を加速する

リダイレクトとパイプは、組み合わせ次第で無数のパターンが生まれます。
最初は「こういうときどう書くの?」と迷いますが、ここでAIツールが役に立ちます。

ChatGPTやGitHub Copilotに、次のように聞いてみてください。

・「/var/log/syslog からerrorかwarnを含む行を抽出してcount.txtに保存するコマンドを教えて」
・「lsの結果を日付順に並べて上位10件だけ取り出すワンライナーを教えて」

提案されたコマンドを、意味を確認しながら自分の手で打ってみる。
この往復を繰り返すと、パイプとリダイレクトの感覚が短期間で身につきます。

大事なのは、丸暗記ではなく「つなげる発想」を持つことです。

「Permission denied」「Broken pipe」が出た時の対処法

1. 「Permission denied」でファイルに書けない

書き込み権限のないディレクトリ(/etcなど)にリダイレクトするとこのエラーになります。
ホームディレクトリ配下に書き出すか、管理用途であればsudoを使います。

# これはエラーになる $ ls > /etc/mylist.txt bash: /etc/mylist.txt: Permission denied # ホーム配下に書き出せばOK $ ls > ~/mylist.txt

2. 「sudo echo xxx > ファイル」が書けない

これも初心者が必ずハマるパターンです。
sudoは「echo」には効きますが「>」はシェル側の処理なので、権限が引き継がれません。
teeコマンドを使うのが定番の解決策です。

# NG: リダイレクトの部分に権限がない $ sudo echo "test" > /etc/test.conf bash: /etc/test.conf: Permission denied # OK: teeを使うとsudo配下でファイルに書ける $ echo "test" | sudo tee /etc/test.conf test # 既存ファイルに追記したいときは tee -a $ echo "additional line" | sudo tee -a /etc/test.conf

3. パイプでつないでも結果が出ない

grepで何も出ない場合は、大文字小文字の違いを疑います。「-i」で無視できます。

# 大文字小文字を区別すると一致しない $ cat app.log | grep error (何も表示されない) # -iで大文字小文字を無視するとマッチする $ cat app.log | grep -i error 2026-05-04 10:21:33 [ERROR] connection refused 2026-05-04 10:25:18 [Error] timeout

4. 「Broken pipe」が出る

パイプの後段(受け側)が早く終了した場合に「Broken pipe」エラーが出ることがあります。
代表例は head との組み合わせです。

# 大量のログをheadで先頭10行だけ取り出す(残りは破棄) $ cat huge.log | head (10行表示) cat: write error: Broken pipe # エラー出力を捨てれば見た目はきれいになる $ cat huge.log 2> /dev/null | head

これは異常ではなく「受け側が必要分だけ取って打ち切った」サインです。
動作には影響しないので、見た目が気になるなら 2> /dev/null で抑えれば十分です。

5. パイプ後にシェル変数が反映されない

実務でハマりやすい落とし穴がもうひとつあります。
パイプの後段はサブシェル(子プロセス)で動くため、そこで変数に代入しても親シェルに反映されません。

# NG: パイプ後のwhileループ内で変数に加算してもループ外で0のまま $ count=0 $ cat numbers.txt | while read n; do count=$((count + n)); done $ echo $count 0 ← 期待した合計が反映されない! # OK: プロセス置換 <() でサブシェル回避 $ count=0 $ while read n; do count=$((count + n)); done < numbers.txt $ echo $count 55 ← 正しく合計される

「パイプを使ったループで変数が更新されない」は、シェルスクリプトをはじめて書く人が高確率でぶつかるバグです。
パイプの代わりに「<( )」(プロセス置換)かリダイレクトでファイルを渡す書き方に切り替えると解決します。

本記事のまとめ

やりたいこと コマンド
結果をファイルに保存(上書き) ls > file.txt
結果をファイルに追記 date >> file.txt
エラーだけ別ファイルに保存 ls /not_exist 2> error.log
正常もエラーもまとめて保存 ls /etc /not_exist &> all.log
正常もエラーも追記保存(sh互換) script.sh >> out.log 2>&1
上書き事故を防ぐ set -C
複数行をコマンドに渡す cat > file.txt << EOF ... EOF
コマンドをつないで絞り込む ps aux | grep nginx
結果を1画面ずつ見る ls /etc | less
行数を数える cat app.log | grep error | wc -l
画面表示しつつファイル保存 ls /etc | tee log.txt
不要な出力を捨てる find / -name "*.conf" 2> /dev/null
sudo配下でファイルに書く echo "test" | sudo tee /etc/test.conf
パイプ結果をコマンド引数に渡す find /tmp -name "*.tmp" | xargs rm -f
crontabをバックアップする crontab -l > ~/crontab_backup.txt
リダイレクトとパイプは、Linuxの「コマンドをつなぐ文法」です。
最初は記号が多くて戸惑いますが、毎日触っていれば1週間で体に馴染みます。
「画面に出すか、ファイルに送るか」「次のコマンドに渡すか」を意識するだけで、作業効率は10倍変わります。

次に学ぶべき関連記事

リダイレクトとパイプを覚えたら、実務でよく使うコマンドと組み合わせて練習しましょう。
以下の記事はどれも、この記事と同じ考え方で理解できるはずです。

ポート確認(ss / lsof)の使い方
DNS設定 resolv.conf と nmcli の使い方
tarコマンドで圧縮・解凍する方法
mountとfstabでディスクをマウントする方法
Postfixのバージョンを確認する方法
chkconfigとsystemctlでサービスを管理する方法
ftpコマンドで複数ファイルをまとめて転送する方法
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、
無料の「Linuxサーバー構築入門マニュアル(図解60ページ)」をプレゼントしています。
コマンド学習の先にある「サーバーをゼロから組み立てる力」を、初心者が迷わない順序で学べる一冊です。
無料マニュアルを受け取る >>

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は1分、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

登録10秒/合わなければ解除3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。