このページでは、コマンド実行時によく利用されるパイプ |
について解説していきます。
また、パイプは |
単体で使用される場合もありますが、 | xargs
という風に xargs
と併用される場合も多いです。
この2つの違いについても解説していきたいと思います。
一応 Mac カテゴリのページとして公開していますが、ここで解説するパイプ |
の使い方や仕組みは Linux でも同様なので、Linux ユーザーの方でも参考になると思います。
パイプを利用すれば、コマンドで実現できる操作の幅が一気に広がります。ターミナル等からのコマンド操作を利用するのであれば、是非パイプについて理解しておきましょう!
Contents
パイプとは
では、パイプについて解説していきます。
パイプ自体はプロセス間通信という大きな意味合いを持つ言葉になりますが、このページではシェルで利用する無名パイプ |
に絞って解説をしていきます
パイプ = コマンドの出力を別のコマンドに渡す機能
パイプとは、コマンド(プログラム)の出力を他のコマンドに渡す仕組みのことを言います。
そして、このパイプを利用するために用いる記号が |
となります。
一応補足しておくと、|
は縦棒です。 L
の小文字ではないので注意してください。shift + ¥
キーの押下で |
を入力することができるはずです。
さて、パイプは、下記のようにコマンドとコマンドの間に挟み込む形で |
を記述して利用します。
% コマンド1 | コマンド2
このようにパイプを用いることで、「|
の左側のコマンドの出力」を |
の右側のコマンドに渡すことができます。
また、下記のように |
を複数利用することもできます。
% コマンド1 | コマンド2 | コマンド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
の結果は下記のようになります。
% 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進数の表示結果結果を得ることができます。
ただ、得られる結果は同じだとしても、操作の手間としてはパイプを利用した方が楽ですね!
最初に紹介した手順ではコマンドを二回に分けて実行する必要がありますし、流石にキーボードで文字を入力するようなことはしないにしても、hexdump
に cat
の出力を渡すための何かしらの操作が必要になってその分の手間も必要になります。
それに対し、パイプを利用した際には、コマンドの実行は一回でまとめて行うことができますし、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
コマンドは、引数で指定したパスのファイルの中身の文字を標準出力に出力するコマンドです。なので、標準出力の接続先の画面にファイルの中身の文字列が出力されることになります。
次に実行したコマンドが下記の hexdump
コマンドです。そして、hexdump
コマンド実行後に cat
コマンドで出力された文字をキーボードで入力しましたね!
% hexdump
hexdump
コマンドは標準入力から入力された文字を16進数の文字コードに変換して出力することができるコマンドです(引数で入力ファイルを指定したり、他の進数で表示したりすることも可能)。
で、その標準入力への入力を行うために、標準入力の接続先となるキーボードから文字を入力したというわけです。
これにより、キーボードから入力された cat
コマンドの出力を hexdump
が読み込み、それを16進数の文字コードに変換して出力することで、cat
コマンドの引数に指定した text.txt
のファイルの中身を16進数で表示するという動作を実現しました。
コマンドを実行するだけだとあまり気づかないかもしれないですが、こんな感じでコマンドは標準入力や標準出力を利用して動作します(全てのコマンドが標準入力や標準出力を利用するというわけではないですが…)。
ポイントは、コマンド(プログラム)はあくまでも標準出力に出力し、標準入力から入力を取得しているだけという点です。画面に直接出力したり、キーボードから直接入力を取得しているわけではありません。
なので、コマンドのプログラムを変更・改造しなくても、標準出力や標準入力の接続先さえ変更してやれば、別の経路での出力や入力が可能であることを示します。例えば、他のデバイスから入力したりファイルに出力したりすることも可能です。
スポンサーリンク
パイプで標準出力の接続先を別のコマンドの標準入力に変更
パイプ |
は、この接続先の変更を行うための手段の1つになります。
接続先の変更を行う手段には、他にもリダイレクトなどがあります
具体的には、|
を利用することで、コマンドの標準出力を別のコマンドの標準入力に接続することが出来ます。
図で表すと下の図のようになります。こんな感じで、パイプを介して標準出力が標準入力に接続されます。
そして、このように接続が行われると、|
の左側のコマンドの標準出力への出力は、 |
の右側のコマンドの標準入力に入力されることになります。
もちろん、このように接続が行われることで、|
の左側のコマンドの標準出力への出力は画面には表示されなくなります。ですが、その代わり、その出力が |
の右側のコマンドの標準入力に入力されることになります。
つまり、|
の右側のコマンドは「|
の左側のコマンドの標準出力への出力」を標準入力から受け取って動作することができますので、|
の左側のコマンドの出力に応じた処理を行うことができます。一言で言えばコマンド間で連携して動作できるということですね!
例えば、パイプを利用するメリット で示した「パイプを使って cat
と hexdump
を実行した例」について考えてみましょう。
この際には下記のようにコマンドを実行しましたね!
% cat text.txt | hexdump
上記では |
を利用していますので、 cat
コマンドの標準出力の接続先は hexdump
の標準入力となります。
そのため、cat
コマンドの標準出力への出力、すなわち text.txt
のファイルの中身の文字列は hexdump
の標準入力に入力されることになります。
さらに、hexdump
が標準入力から入力を受け取ることで、cat
コマンドの標準出力への出力に対して hexdump
の処理を実行することができます。
このように、|
を利用することで、コマンドの標準出力の接続先を他のコマンドの標準入力に切り替えることができます。
そしてこれにより、コマンド同士で連携した動作を行うことができるようになり、パイプを利用するメリット で述べたように、コマンド操作が楽になったり、コマンド操作で実現できることの幅を広げることができます。
ページの最初でパイプのことを簡単に「コマンドの出力を他のコマンドに渡す仕組み」と説明してましたが、ここまでの説明の通り、より具体的には、パイプは「コマンドの標準出力への出力を別のコマンドの標準入力に入力する仕組み」となります。
|
と | xargs
の違い
もちろんパイプは非常に便利ですが、これ単体だとまだまだ不便なことが多いです。
この不便さを解消するために、xargs
を利用します。
|
での入力先はあくまでも標準入力
パイプを利用することで、コマンドの標準出力への出力を他のコマンドの標準入力に渡すことができます。
ただ、あくまでも「出力を渡す先がコマンドの標準入力」であることには注意が必要です。
なぜなら、コマンドが標準入力を利用するとは限らないからです。もし |
の右側で実行されるコマンドが標準入力を利用しない場合、どれだけ |
の左側のコマンドが標準出力に出力したとしても、右側のコマンドはそれを受け取らないことになります。
こういった標準入力からの入力を利用しないコマンドは割と多いです。
そして、そういったコマンドは、標準入力からではなく「引数」として入力を受け取ることが多いです。
% コマンド 引数
例えば mkdir
や rm
などのコマンドは、そもそも引数を指定しないと実行できません。
引数と標準入力は異なるものですので、|
を利用して単に標準入力にコマンドの出力を渡したとしても、引数として渡されることを期待しているコマンドに対しては意味がありません。
そういったコマンドに対して別のコマンドの出力を渡したい場合は、コマンドの標準出力への出力を標準入力ではなく「引数」として渡してやる必要があることになります。
スポンサーリンク
xargs
で標準入力の入力を引数として別のコマンドを実行
そして、その「コマンドの標準出力への出力を引数として別のコマンドに渡す」を実現する際に活躍するのが xargs
コマンドになります。
xargs
は、「標準入力からの入力」を引数に指定して別のコマンドを実行するコマンドになります(ファイル等からでも入力できる)。
つまり、xargs
の標準入力にコマンドの標準出力への出力を入力してやれば、そのコマンドの出力を引数に指定して別のコマンドを実行することができることになります。
| xargs
:コマンドの出力を別のコマンドの引数に指定する
で、ここまで解説してきたように、|
を利用することで、コマンドの標準出力への出力を別のコマンド(今回は xargs
)の標準入力に渡すことが出来ます。
ですので、下記のように | xargs
を利用すれば、
% コマンド1 | xargs コマンド2
まず |
の左側のコマンドの標準出力への出力が xargs
の標準入力に入力されます。
さらに、xargs
で標準入力の文字列が読み込まれ、その文字列が xargs
の引数に指定された コマンド2
の引数としてセットされます。そして、その引数をセットした状態で、xargs
から コマンド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
この結果より、Hello
が main.exe
の標準入力から入力されていることが確認できます(echo "Hello"
により Hello
が標準出力に出力される)。
それに対し、下記のコマンドを実行した場合、
% echo "Hello" | xargs ./main.exe
実行結果は下記のようになります(終了しない場合は control
+ c
で強制終了してください)。
#### 引数 #### 1 : Hello #### 標準入力 ####
この結果より、Hello
が main.exe
の引数として入力されていることが確認できます。
これらの結果からも、|
と | xargs
に下記の違いがあることを確認できたのではないかと思います・
|
:左側のコマンドの標準出力への出力を右側のコマンドの標準入力に入力する| args
:左側のコマンドの標準出力への出力を右側のコマンドの引数に指定する
こんな感じで、コマンドライン引数を受け取る&標準入力からの入力を受け付けるプログラムを実際に自身で作成して動作確認をしてみれば、どのようにプログラムに入力が渡されるかがイメージ湧きやすくなるのではないかと思います。
まとめ
このページでは、パイプ(|
)について解説をしました!
パイプはコマンドの標準出力を別のコマンドの標準入力に接続する機能であり、これにより |
の左側のコマンドの標準出力への出力を |
の右側のコマンドの標準入力に渡すことができるようになります。
そしてこれにより、コマンド間のデータのやりとりを簡単に実現することができ、コマンド操作の手間を減らしたり、コマンド操作で実現可能なことの幅を広げることが出来ます。
また、|
は xargs
と併用されることも多く、これによりコマンドの標準出力への出力を別のコマンドに引数として渡すことができるようになります。
コマンドを利用するのであれば、|
と xargs
コマンドを利用する機会は多いと思いますので、ぜひ使い方をマスターしておきましょう!
他にも、このサイトではコマンド関連のページをいくつか公開しておりますので、興味があれば是非読んでみてください。特にリダイレクトに関しては、パイプ同様に標準入出力の接続先の変更を行うことができ、コマンド操作を行う上で必ず必要になるものですので、使い方を覚えておくことをオススメします!
Macでのターミナルアプリの使い方 Macのターミナルでよく使うコマンド集(初心者向け) コマンドのリダイレクトについて解説(標準入力や標準出力の接続先を変更) 【Mac】コマンド実行結果をクリップボードにコピーする方法【pbcopy・pbpaste】