パイプ | について解説( | と | xargs の違いも理解できる!)

パイプの解説ページアイキャッチ

このページでは、コマンド実行時によく利用されるパイプ | について解説していきます。

また、パイプは | 単体で使用される場合もありますが、 | xargs という風に xargs と併用される場合も多いです。

この2つの違いについても解説していきたいと思います。

一応 Mac カテゴリのページとして公開していますが、ここで解説するパイプ | の使い方や仕組みは Linux でも同様なので、Linux ユーザーの方でも参考になると思います。

パイプを利用すれば、コマンドで実現できる操作の幅が一気に広がります。ターミナル等からのコマンド操作を利用するのであれば、是非パイプについて理解しておきましょう!

パイプとは

では、パイプについて解説していきます。

パイプ自体はプロセス間通信という大きな意味合いを持つ言葉になりますが、このページではシェルで利用する無名パイプ | に絞って解説をしていきます

パイプ = コマンドの出力を別のコマンドに渡す機能

パイプとは、コマンド(プログラム)の出力を他のコマンドに渡す仕組みのことを言います。

そして、このパイプを利用するために用いる記号が | となります。

パイプの説明図

一応補足しておくと、| は縦棒です。 L の小文字ではないので注意してください。shift + ¥ キーの押下で | を入力することができるはずです。

さて、パイプは、下記のようにコマンドとコマンドの間に挟み込む形で | を記述して利用します。

% コマンド1 | コマンド2

このようにパイプを用いることで、「| の左側のコマンドの出力」を | の右側のコマンドに渡すことができます。

パイプで2つのコマンドの入出力を連携する様子

また、下記のように | を複数利用することもできます。

% コマンド1 | コマンド2 | コマンド3

この場合も同様で、考え方は「| の左側のコマンドの出力を | の右側のコマンドに渡す」であり、それが左側端のコマンドから順に段階的に渡されていくだけです。

パイプで3つのコマンドの入出力を連携する様子

スポンサーリンク

パイプを利用するメリット

このパイプ(|)を利用することで、コマンドでの操作が楽になりますし、さらにコマンドで実現出来ることの幅を広げることが出来ます。

ここからは具体的な例を用いて、パイプを使用する場合と使用しない場合との手順の違いを考えていきましょう。

今回は「テキストファイル内の文字の文字コードを16進数で表示する」ことを考えていきたいと思います。

コマンド操作で実現したいことを示す図

ちょっと実用性のない例での解説になりますが、今後の説明は理解しやすくなると思います。

これを実現するために、下記の2つの手順を行なっていきます。

  • テキストファイル内の文字を出力する
  • 文字の文字コードを16進数で出力する

1つ目に関しては cat コマンドで、2つ目に関しては hexdump コマンドでそれぞれ行うことができます。

まず、下記のように引数にテキストファイルのパスを指定して cat コマンドを実行すれば、指定したテキストファイル内の文字が出力されます(テキストファイルのパスは text.txt としています)。

% cat text.txt
In the year 1878 I took my degree of Doctor of Medicine of the University of London, and proceeded to Netley to go through the course prescribed for surgeons in the army.

In the year … からの部分が cat の出力となります(つまり text.txt 内の文字)。

なので、後はこの cat の出力を hexdump に渡してやれば「テキストファイル内の文字の文字コードを16進数で表示する」を実現することができます。

で、この cat の出力の hexdump への渡し方がポイントになります。

この渡し方として、ちょっと極端な例になりますが、hexdump コマンドを実行してから cat コマンドで出力された文字を全てキーボードで入力してやることで、cat の出力を hexdump に渡す方法が考えられます。

hexdumpにcatの出力をキーボードから入力する様子

これでもやりたいことは実現できます。実際の hexdump の結果は下記のようになります。

% hexdump
In the year 1878 I took my degree of Doctor of Medicine of the University of London, and proceeded to Netley to go through the course prescribed for surgeons in the army.
0000000 49 6e 20 74 68 65 20 79 65 61 72 20 31 38 37 38
0000010 20 49 20 74 6f 6f 6b 20 6d 79 20 64 65 67 72 65
0000020 65 20 6f 66 20 44 6f 63 74 6f 72 20 6f 66 20 4d
0000030 65 64 69 63 69 6e 65 20 6f 66 20 74 68 65 20 55
0000040 6e 69 76 65 72 73 69 74 79 20 6f 66 20 4c 6f 6e
〜略〜

ただ、これだと流石に大変ですね…。

そこでパイプのお出ましです。前述の通り、| を利用することで、| の左側のコマンドの出力を | の右側のコマンドに渡すことができます。

今回の場合、cat の出力を hexdump に渡したいのですから、下記のように | を利用してコマンドを実行すれば良いことになります。

% cat text.txt | hexdump
0000000 49 6e 20 74 68 65 20 79 65 61 72 20 31 38 37 38
0000010 20 49 20 74 6f 6f 6b 20 6d 79 20 64 65 67 72 65
0000020 65 20 6f 66 20 44 6f 63 74 6f 72 20 6f 66 20 4d
0000030 65 64 69 63 69 6e 65 20 6f 66 20 74 68 65 20 55
0000040 6e 69 76 65 72 73 69 74 79 20 6f 66 20 4c 6f 6e
〜略〜

これでも、先ほど cat の出力をキーボードから文字を入力して hexdump に渡した時と同じ16進数の表示結果結果を得ることができます。

ただ、得られる結果は同じだとしても、操作の手間としてはパイプを利用した方が楽ですね!

最初に紹介した手順ではコマンドを二回に分けて実行する必要がありますし、流石にキーボードで文字を入力するようなことはしないにしても、hexdumpcat の出力を渡すための何かしらの操作が必要になってその分の手間も必要になります。

それに対し、パイプを利用した際には、コマンドの実行は一回でまとめて行うことができますし、cat の出力を hexdump に渡すための操作は不要になります。

こんな感じで、パイプの利用によりコマンドでの操作が楽になり、作業効率をアップさせることができます。

また、例えば下記を実行すれば、拡張子が .c であるファイルを検索し、見つかったファイルから printf というワードを含む行を全て表示することができます。

% find . -name "*.c" | xargs grep printf

xargs が利用されており、この xargs の解説については後述に回させていただきますが、要は find の出力を grep に渡していることになります。

find は「ファイルを検索して見つかったファイルのパスを出力する」コマンドであり、grep は「指定したパスのファイルの中から特定のワードを含む行を出力する」コマンドになります。

これらのコマンド単体では「検索して見つかったファイルから特定のワードを含む行を出力する」ことは実現できません。ですが、パイプを利用すれば、2つのコマンドの機能を組み合わせて「検索して見つかったファイルから特定のワードを含む行を出力する」を実現することができます。

こんな感じで、パイプを利用することで、コマンド(プログラム)同士を連携させて新たな動作を実現することができ、これによりコマンド操作の幅を広げることができます。

パイプで出力を渡す仕組み

パイプがどのようなものであるかイメージが湧いたでしょうか?

ここまでパイプの概要を説明してきましたが、実はかなり曖昧に説明を行なってきました。

| の左側のコマンドの出力とは具体的に何なのか?

その出力が | の右側のコマンドにどのようにして渡されるのか?

この辺りの説明が曖昧になっています。そして、ここの理解が曖昧であると、|| xargs の違いも理解することができません。

ここからは、上記で挙げたここまでの説明の曖昧な部分を補うために、パイプでコマンドの出力が渡される仕組みについて解説していきます。

コマンドと標準入力・標準出力

このパイプの仕組みを理解するにあたって必要になる知識が「標準入力」と「標準出力」になります(標準エラー出力もありますが、このページでは省略して説明していきます)。

標準入力・標準出力とは、簡単に言えばコマンド用(プログラム・プロセス用)にあらかじめ確保されているデータの入出力経路(ストリーム)のことです。

入出力先として特に何も指定をしなかった場合、この標準入力や標準出力を利用して入出力が行われます。

また、デフォルト設定では、標準入力は端末のキーボードに、標準出力は端末の画面にそれぞれ接続されています。

標準入力と標準出力の説明図

ですので、コマンド(プログラム)が出力先を特に指定せずに文字列を出力すれば、その文字列は標準出力に出力されることになります。さらに、その標準出力は画面に接続されているため、画面にその文字列が表示されることになります。

標準出力への説明図

また、コマンド(プログラム)が入力先を特に指定せずに入力を受け付ければ、その入力受付は標準入力に対して行われることになります。さらに、その標準入力はキーボードに接続されているため、キーボードから入力された文字列等が標準入力を介してコマンド(プログラム)に入力されることになります。

標準入力からの入力の説明図

例えば、パイプを利用するメリット で示した「パイプを使わずに cat と hexdump を実行した例」について標準入力と標準出力を踏まえて考えてみましょう。

まず実行したコマンドが下記の cat コマンドでしたね!

% cat text.txt

cat コマンドは、引数で指定したパスのファイルの中身の文字を標準出力に出力するコマンドです。なので、標準出力の接続先の画面にファイルの中身の文字列が出力されることになります。

catコマンドで標準出力への出力が行われる様子

次に実行したコマンドが下記の hexdump コマンドです。そして、hexdump コマンド実行後に cat コマンドで出力された文字をキーボードで入力しましたね!

% hexdump

hexdump コマンドは標準入力から入力された文字を16進数の文字コードに変換して出力することができるコマンドです(引数で入力ファイルを指定したり、他の進数で表示したりすることも可能)。

で、その標準入力への入力を行うために、標準入力の接続先となるキーボードから文字を入力したというわけです。

これにより、キーボードから入力された cat コマンドの出力を hexdump が読み込み、それを16進数の文字コードに変換して出力することで、cat コマンドの引数に指定した text.txt のファイルの中身を16進数で表示するという動作を実現しました。

hexdumpコマンドで標準入力からの取得と標準出力への出力が行われる様子

コマンドを実行するだけだとあまり気づかないかもしれないですが、こんな感じでコマンドは標準入力や標準出力を利用して動作します(全てのコマンドが標準入力や標準出力を利用するというわけではないですが…)。

ポイントは、コマンド(プログラム)はあくまでも標準出力に出力し、標準入力から入力を取得しているだけという点です。画面に直接出力したり、キーボードから直接入力を取得しているわけではありません。

なので、コマンドのプログラムを変更・改造しなくても、標準出力や標準入力の接続先さえ変更してやれば、別の経路での出力や入力が可能であることを示します。例えば、他のデバイスから入力したりファイルに出力したりすることも可能です。

標準出力の接続先を変更する様子

スポンサーリンク

パイプで標準出力の接続先を別のコマンドの標準入力に変更

パイプ | は、この接続先の変更を行うための手段の1つになります。

MEMO

接続先の変更を行う手段には、他にもリダイレクトなどがあります

具体的には、| を利用することで、コマンドの標準出力を別のコマンドの標準入力に接続することが出来ます。

図で表すと下の図のようになります。こんな感じで、パイプを介して標準出力が標準入力に接続されます。

パイプによってコマンドの標準出力と別のコマンドの標準入力が接続される様子

そして、このように接続が行われると、| の左側のコマンドの標準出力への出力は、 | の右側のコマンドの標準入力に入力されることになります。

コマンド1の出力がパイプと標準入力を介してコマンド2に渡される様子

もちろん、このように接続が行われることで、| の左側のコマンドの標準出力への出力は画面には表示されなくなります。ですが、その代わり、その出力が | の右側のコマンドの標準入力に入力されることになります。

つまり、| の右側のコマンドは「| の左側のコマンドの標準出力への出力」を標準入力から受け取って動作することができますので、| の左側のコマンドの出力に応じた処理を行うことができます。一言で言えばコマンド間で連携して動作できるということですね!

例えば、パイプを利用するメリット で示した「パイプを使って cat と hexdump を実行した例」について考えてみましょう。

この際には下記のようにコマンドを実行しましたね!

% cat text.txt | hexdump

上記では | を利用していますので、 cat コマンドの標準出力の接続先は hexdump の標準入力となります。

そのため、cat コマンドの標準出力への出力、すなわち text.txt のファイルの中身の文字列は hexdump の標準入力に入力されることになります。

cat text.text | hexdump 実行時の動作の説明図1

さらに、hexdump が標準入力から入力を受け取ることで、cat コマンドの標準出力への出力に対して hexdump の処理を実行することができます。

cat text.text | hexdump 実行時の動作の説明図2

このように、| を利用することで、コマンドの標準出力の接続先を他のコマンドの標準入力に切り替えることができます。

そしてこれにより、コマンド同士で連携した動作を行うことができるようになり、パイプを利用するメリット で述べたように、コマンド操作が楽になったり、コマンド操作で実現できることの幅を広げることができます。

ページの最初でパイプのことを簡単に「コマンドの出力を他のコマンドに渡す仕組み」と説明してましたが、ここまでの説明の通り、より具体的には、パイプは「コマンドの標準出力への出力を別のコマンドの標準入力に入力する仕組み」となります。

|| xargs の違い

もちろんパイプは非常に便利ですが、これ単体だとまだまだ不便なことが多いです。

この不便さを解消するために、xargs を利用します。

| での入力先はあくまでも標準入力

パイプを利用することで、コマンドの標準出力への出力を他のコマンドの標準入力に渡すことができます。

ただ、あくまでも「出力を渡す先がコマンドの標準入力」であることには注意が必要です。

なぜなら、コマンドが標準入力を利用するとは限らないからです。もし | の右側で実行されるコマンドが標準入力を利用しない場合、どれだけ | の左側のコマンドが標準出力に出力したとしても、右側のコマンドはそれを受け取らないことになります。

コマンドが標準入力からの入力を取得しない様子

こういった標準入力からの入力を利用しないコマンドは割と多いです。

そして、そういったコマンドは、標準入力からではなく「引数」として入力を受け取ることが多いです。

% コマンド 引数

例えば mkdirrm などのコマンドは、そもそも引数を指定しないと実行できません。

引数と標準入力は異なるものですので、| を利用して単に標準入力にコマンドの出力を渡したとしても、引数として渡されることを期待しているコマンドに対しては意味がありません。

そういったコマンドに対して別のコマンドの出力を渡したい場合は、コマンドの標準出力への出力を標準入力ではなく「引数」として渡してやる必要があることになります。

コマンドに別のコマンドの出力を引数として渡す様子

スポンサーリンク

xargs で標準入力の入力を引数として別のコマンドを実行

そして、その「コマンドの標準出力への出力を引数として別のコマンドに渡す」を実現する際に活躍するのが xargs コマンドになります。

xargs は、「標準入力からの入力」を引数に指定して別のコマンドを実行するコマンドになります(ファイル等からでも入力できる)。

xargsの説明図

つまり、xargs の標準入力にコマンドの標準出力への出力を入力してやれば、そのコマンドの出力を引数に指定して別のコマンドを実行することができることになります。

| xargs :コマンドの出力を別のコマンドの引数に指定する

で、ここまで解説してきたように、| を利用することで、コマンドの標準出力への出力を別のコマンド(今回は xargs)の標準入力に渡すことが出来ます。

ですので、下記のように | xargs を利用すれば、

% コマンド1 | xargs コマンド2

まず | の左側のコマンドの標準出力への出力が xargs の標準入力に入力されます。

コマンド1の出力がxargsの標準入力に入力される様子

さらに、xargs で標準入力の文字列が読み込まれ、その文字列が xargs の引数に指定された コマンド2 の引数としてセットされます。そして、その引数をセットした状態で、xargs から コマンド2 が実行されることになります。

xargsからコマンド1の出力を引数として指定してコマンド2が実行される様子

こんな感じで、| xargs を利用すれば、コマンドの出力を他のコマンドの引数として指定して実行することができるようになります。

コマンドを別のコマンドの引数として渡す

前述の通り、標準入力からの入力ではなく、引数から入力を受け付けることを期待しているコマンドは多いので、この xargs は非常に活躍機会の多いコマンドであると言えます。

ですので、コマンドでの操作を行う機会が多いのでれば、| だけでなく | xargs についても必ず覚えておいたほうが良いと思います。

|| xargs の違いと使い分け

ここまでをまとめると、| と | xargs の違いは下記のようになります。

ちょっと標準入力と標準出力がややこしいかもしれませんが、ここを意識することで2つの違いが理解しやすくなると思います。

  • |:左側のコマンドの標準出力への出力を右側のコマンドの標準入力に入力する
  • | args:左側のコマンドの標準出力への出力を右側のコマンドの引数に指定する

では、| と | xargs のどちらを利用すれば良いのでしょうか?

結局これは、| の左側のコマンドの「出力データ」と、| の右側のコマンドが期待する「入力経路(標準入力 or 引数)」や「入力データ」によって異なります。

分かりやすいのが入力経路での使い分けですね。

例えば | の右側のコマンドが期待する入力経路が「標準入力」であれば、| を単体で利用すれば良いです。

それに対し、| の右側のコマンドが期待する入力経路が「引数」であれば | args を利用すれば良いです。

ただ、これだけだと | の左側のコマンドの「出力データ」と | の右側のコマンドが期待する「入力データ」の食い違いによって上手く動作させられないことがありますので注意してください。

例えば、下記のコマンドを実行した場合、text.txt の「ファイル内の文字列」を引数に指定して rm コマンドが実行されることになります。

% cat text.txt | xargs rm

rm コマンドが期待する入力経路は「引数」なので、上記ではそれを満たすことが出来ています。

ですが、rm コマンドが期待する入力データは「ファイルのパス」であり、cat コマンドの出力データである「ファイル内の文字列」ではないため、rm コマンドを上手く動作させることはできません。

それに対し、下記のコマンドを実行した場合、find によって見つけられた「ファイルのパス」が rm コマンドの引数に指定されることになるため、rm コマンドが期待する入力データを満たすことができ、rm コマンドでファイルの削除を行うことができます(実際に実行するとファイルが削除される可能性があるので注意してください)。

% find . -name "text.txt" | xargs rm

この辺りを考慮すると | と | xargs を上手く使い分けるためには、結局は利用するコマンドの仕様(出力データや入力経路・入力データ)をしっかり理解しておく必要があるということになります。

ただ、引数でオプションやパス等の入力を受け付けるコマンドの方が多いと思いますので、迷ったら | xargs を利用してみるので良いと思います。

スポンサーリンク

|| xargs の違いはプログラムを書いてみると分かりやすい

もしかしたら | と | xargs の違いがまだハッキリ理解できていない人もおられるかもしれません。

そういった方には、コマンドライン引数を受け取る&標準入力からの入力を受け付けるプログラムを実際に自身で作成して動作確認してみることをオススメします。

この動作確認をしてみると、| と | xargs の違いがすぐにわかると思います。

例えばC言語であれば、下記のようなソースコード(main.c)のプログラム(main.exe)を作って動作確認をしてみると分かりやすいです。

違いを確認するためのプログラム
#include <stdio.h>

int main(int argc, char *argv[]) {
    printf("#### 引数 ####\n");

    for (int i = 1; i < argc; i++) {
        printf("%d : %s\n", i, argv[i]);
    }

    printf("\n");

    printf("#### 標準入力 ####\n");

    char input[1024];
    scanf("%s", input);
    printf("%s\n", input);
}

ちょっとC言語を利用されていない方には難しいかもしれませんが、このプログラムは引数として受け取った入力を #### 引数 #### の下側に表示し、さらに標準入力として受け取った入力を #### 標準入力 #### の下側に表示するものとなります。

要は、引数で入力された文字列と標準入力で入力された文字列を判別するプログラムになります。

例えば、上記のソースコードをコンパイルして生成されたプログラムを main.exe とし、さらに main.exe と同じフォルダで下記コマンドを実行すれば、

% echo "Hello" | ./main.exe

実行結果は下記のようになります。

#### 引数 ####

#### 標準入力 ####
Hello

この結果より、Hellomain.exe の標準入力から入力されていることが確認できます(echo "Hello" により Hello が標準出力に出力される)。

それに対し、下記のコマンドを実行した場合、

% echo "Hello" | xargs ./main.exe

実行結果は下記のようになります(終了しない場合は control + c で強制終了してください)。

#### 引数 ####
1 : Hello

#### 標準入力 ####

この結果より、Hellomain.exe の引数として入力されていることが確認できます。

これらの結果からも、|| xargs に下記の違いがあることを確認できたのではないかと思います・

  • |:左側のコマンドの標準出力への出力を右側のコマンドの標準入力に入力する
  • | args:左側のコマンドの標準出力への出力を右側のコマンドの引数に指定する

こんな感じで、コマンドライン引数を受け取る&標準入力からの入力を受け付けるプログラムを実際に自身で作成して動作確認をしてみれば、どのようにプログラムに入力が渡されるかがイメージ湧きやすくなるのではないかと思います。

まとめ

このページでは、パイプ(|)について解説をしました!

パイプはコマンドの標準出力を別のコマンドの標準入力に接続する機能であり、これにより | の左側のコマンドの標準出力への出力を | の右側のコマンドの標準入力に渡すことができるようになります。

そしてこれにより、コマンド間のデータのやりとりを簡単に実現することができ、コマンド操作の手間を減らしたり、コマンド操作で実現可能なことの幅を広げることが出来ます。

また、|xargs と併用されることも多く、これによりコマンドの標準出力への出力を別のコマンドに引数として渡すことができるようになります。

コマンドを利用するのであれば、| と xargs コマンドを利用する機会は多いと思いますので、ぜひ使い方をマスターしておきましょう!

他にも、このサイトではコマンド関連のページをいくつか公開しておりますので、興味があれば是非読んでみてください。特にリダイレクトに関しては、パイプ同様に標準入出力の接続先の変更を行うことができ、コマンド操作を行う上で必ず必要になるものですので、使い方を覚えておくことをオススメします!

macのターミナルアプリの使い方の解説ページアイキャッチMacでのターミナルアプリの使い方 Macのターミナルで良く使うコマンド集紹介ページのアイキャッチMacのターミナルでよく使うコマンド集(初心者向け) リダイレクトの解説ページアイキャッチコマンドのリダイレクトについて解説(標準入力や標準出力の接続先を変更)

同じカテゴリのページ一覧を表示