Help us understand the problem. What is going on with this article?

Linuxのパイプをちょっとだけ理解する

More than 1 year has passed since last update.

この記事は ゆめみ Advent Calendar 2017 の 16 日目の記事です。

Linuxのパイプを理解して、Linuxをコマンドを便利に使いこなそうとする記事です。

Linuxのプロセスの入出力

パイプはプロセス間の入出力を繋げる仕組みなので、まずは、プロセスの入出力を知る必要があります。

標準ストリーム

プロセスは、明示的にファイルをオープンしなくても利用できる入出力があります。

  • 標準入力 (stdin)
  • 標準出力 (stdout)
  • 標準エラー出力 (stderr)

Javaでは System.inSystem.outSystem.err 。PHPでは STDINSTDOUTSTDERR で扱えるやつです。

C言語で割り当てられるファイルディスクリプタ番号は 0番が標準入力、1番が標準出力、標準エラー出力が2番です。そして、標準入力はキーボード、標準出力と標準エラー出力はモニータが接続されています。

標準ストリームの図
上の図は wikipedia の 標準ストリーム にあるものです。

無名パイプ

無名パイプは、コマンド間の入出力を繋げるときによく使う | です。これを使うことで | の左側のコマンドの標準出力を右側の標準入力に繋げる仕組みです。

例えば ls | more は下の図になります。

linux-pipe-4.png

lsの#1と moreの #0 をつなげているのがパイプです。ls コマンドは ls(1) を見ると下のように書かれています。

出力は標準出力に対して行われ、 -C オプションで複数列出力が要求されない限り、1 行に 1 エントリである。 しかし、端末に対する出力では、出力が 1 列または複数列の どちらになるかが定められていない。 オプション -1 と -C は、 それぞれ 1 列出力と複数列出力を強制させるために使用される。

パイプで処理したいコマンドがあるときには、manを見て、入出力を確認すると良いです。

複数のパイプを利用することもできるので、ファイル名に qiita を含むファイル名を数えるために ls |grep 'qiita' |wc -l を実行すると下のようになります。

linux-pipe-2.png

名前付きパイプ

無名パイプは使い終わると廃棄されますが、名前付きパイプは mkfifoコマンドで ファイルシステムに作ることができます。作成した名前付きパイプはリダイレクトを利用して、標準入出力と繋げることができます。

$ echo "Regular file" > regular_file
$ mkfifo named_pipe
$ ls -l
total 4
prw-rw-r-- 1 user1 group1  0 Dec 14 03:22 named_pipe
-rw-rw-r-- 1 user1 group1 13 Dec 14 03:21 regular_file
$

上では、 named_pipe という名前付きパイプを作成しています。ls -l で(左端の「p」だから)ファイルタイプがパイプということが分かります。

この名前付きパイプを使って ls -l |more と同等のことを行なってみます。
二つのターミナルを使い、一つ目のターミナルでは、 named_pipeを作成したディレクトリで 下のコマンドを実行します。

$ more named_pipe

実行した直後は何も動きがありませんが、そのままにしておきます。more コマンドは第1引数に指定したファイルを読み込みます。今回はnamed_pipe を指定したので、名前付きパイプ named_pipe からの読み込みを待っている状態です。

二つ目のターミナルでは named_name を作成したディレクトリで下のコマンドを実行します。

$ ls -l /usr/bin/ > named_pipe

ls -l の結果を事前に作成した名前付きパイプ named_pipe に書き込みます。そうすると、 一つ目のターミナルに moreコマンドの結果が表示され、1ページを表示すると待機します。あとは、スペースキーでページ送りやqでmoreを終了できます。

linux-pipe-named-pipe.png

名前付きパイプの使い所

処理結果の書き込み先はコマンドごとにオプション指定があります。

  • mysqldumpは --result-file (-r)でファイルを指定します。オプションが無ければ標準出力です。
  • pg_dumpは --file(-f) でファイルを指定します。オプションがなければ標準出力です。
  • tar は c オプションで指定するファイル名に - を指定すると標準入力、標準出力を使います。
  • zip は ファイル名に - を指定すると、標準出力です。

これらの様にオプションで標準出力を指定できるコマンドもありますが、そうではないコマンドもあります。古いコマンドで恐縮ですが、 Oracleの ダンプファイルを作成するexp は標準出力に出力することができませんでした。そういう時に名前付きパイプを使いました。

$ cat named_pipe | zip > db_hoge.dmp.gz &
$ exp user_name file=named_pipe full=y

先に、バックグラウンドでzipコマンドを起動しておき、expコマンドの fileオプションに名前付きパイプを指定しています。

インポートする時はバックグラウンドで unzip を行い、名前付きパイプに書き込みます。imp ユーティリティは名前付きパイプを読み込みます。

$ cat db_hoge.dmp.gz | unzip - > named_pipe &
$ imp user_name file=name_pipe

ディスクを節約するためにお世話になりました。

akym03
株式会社ゆめみ でシステムエンジニアをやっています。
yumemi
みんなが知ってるあのサービス、実はゆめみが作ってます。スマホアプリ/Webサービスの企画・UX/UI設計、開発運用。Swift, Kotlin, PHP, Vue.js, React.js, Node.js, AWS等エンジニア・クリエイターの会社です。Twitterで情報配信中https://twitter.com/yumemiinc
http://www.yumemi.co.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away