コマンドのリダイレクトについて解説(標準入力や標準出力の接続先を変更)

リダイレクトの解説ページアイキャッチ

このページでは、コマンド操作時に利用されるリダイレクトについて解説していきます。

最初に簡単にリダイレクトの概要について解説し、その後、リダイレクトが実現される仕組みや様々なリダイレクトの使い方について解説していきたいと思います。

コマンド操作を行うのであれば必ずリダイレクトは利用することになります。是非このページでリダイレクトについて理解していってください!

リダイレクト

では、まずはリダイレクトの概要をさらっと解説していきます。

リダイレクトとは

リダイレクトとは、コマンドの標準入力・標準出力・標準エラー出力の接続先を変更することです。

これにより、コマンドの出力結果をファイルに保存したり、コマンドにファイルを入力したりすることが出来るようになります。

スポンサーリンク

リダイレクトの使い方

このリダイレクトを利用する際には、>< といった記号を利用します。

例えば、> を用いて下記のような形式でコマンドを実行した場合、

% コマンド >ファイルのパス

コマンド の出力を ファイルのパス のファイルに出力することができます。

リダイレクトでファイルへ出力を行う様子

また、< を用いて下記のような形式でコマンドを実行した場合、

% コマンド <ファイルのパス

コマンド に ファイルのパス のファイルを入力することができます。

リダイレクトでファイルからコマンドへ入力を行う様子

リダイレクトで出来ること

次は、簡単なリダイレクトの利用例を示しながら、リダイレクトでどのようなことが出来るのかを説明しておきたいと思います。

例えば下記のようにコマンドを実行すれば、コマンドの実行結果を画面に出力することができます。ls - l はカレントディレクトリ内に存在するファイルやディレクトリをリスト形式で出力するコマンドになります。

% ls -l
total 8
drwxr-xr-x  2 daeu  staff   64 12  6 06:34 document
drwxr-xr-x  2 daeu  staff   64 12  6 06:34 picture
drwxr-xr-x@ 4 daeu  staff  128 12  6 06:35 programming
drwxr-xr-x  2 daeu  staff   64 12  6 06:34 report
-rw-r--r--@ 1 daeu  staff   23  2 19 10:38 text.txt

それに対し、下記のようにコマンドを実行すれば、コマンドの実行結果をファイルに出力することができます。

% ls -l >result.txt

こんな感じで > の後ろ側に result.txt のようなファイルのパスを指定すれば、そのファイルにコマンドの実行結果を出力することができます。

実際に cat コマンド等で result.txt の中身を出力すれば、コマンドの実行結果がファイルに出力されていることも確認できるはずです。

% cat result.txt
total 8
drwxr-xr-x  2 daeu  staff   64 12  6 06:34 document
drwxr-xr-x  2 daeu  staff   64 12  6 06:34 picture
drwxr-xr-x@ 4 daeu  staff  128 12  6 06:35 programming
drwxr-xr-x  2 daeu  staff   64 12  6 06:34 report
-rw-r--r--@ 1 daeu  staff   23  2 19 10:38 text.txt

また、例えば下記のようにコマンドを実行すれば、コマンドへ文字列をキーボードから入力することができます。hexdump は入力された文字列を16進数の文字コードで出力するコマンドです。おそらく hexdump 実行後に16文字以上入力してからエンターキーを押せば16進数が表示されると思います。

% hexdump
abcdefghijklmnop
0000000 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70

上記は hexdump コマンド実行後にキーボードで abcdefghijklmnop を入力してからエンターキーを押した例となります。エンターキーを押しても hexdump は終了しないので、control + c を押して強制終了する必要があります。

上記に対し、次のようにコマンドを実行すれば、コマンドへ文字列をファイルから入力することができます(result.txt は先ほど ls コマンドの出力先としたファイルとしています)。

% hexdump <result.txt
0000000 74 6f 74 61 6c 20 38 0a 64 72 77 78 72 2d 78 72
0000010 2d 78 20 20 32 20 64 61 65 75 20 20 73 74 61 66
0000020 66 20 20 20 36 34 20 31 32 20 20 36 20 30 36 3a

こんな感じで < の後ろ側に result.txt のようなファイルのパスを指定すれば、そのファイルの内容をコマンドに入力することができます。

リダイレクトで入出力先が変わる仕組み

ここまで簡単にリダイレクトについて解説してきましたが、大体リダイレクトでできることは理解していただけたのではないかと思います。

次は、リダイレクトでコマンドからファイルへの出力やコマンドへのファイルからの入力が実現される仕組みについて解説していきたいと思います。

スポンサーリンク

標準入力・標準出力・標準エラー出力

最初にも述べたように、リダイレクトとは、コマンドの「標準入力・標準出力・標準エラー出力」の接続先を変更することを言います。

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

例えばプログラミングで「ファイルを開く」処理を行うことがあると思いますが、このファイルを開くことでもプログラムからファイルへの入出力経路の確保を行うことができます。

ただし、この入出力経路は別途プログラム内で確保したものであり、標準入力・標準出力・標準エラー出力とは異なる経路となります。

入出力先として特に何も指定をしなかった場合、コマンド(プログラム)はこの「標準入力・標準出力・標準エラー出力」を利用して入出力を行います。

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

コマンドと標準ストリームとの関係性

標準出力への出力

例えば、リダイレクトで出来ること で下記の ls コマンドを実行した際には結果が画面に出力されました。

% ls -l

では ls コマンドが画面に直接結果を出力したのかというと、そうではなく、ls コマンドからの出力先はあくまでも標準出力となります。で、標準出力の接続先が画面なので、ls コマンドの結果は標準出力を介して画面に出力されることになります。

lsの結果が標準出力に出力される様子

標準入力からの入力

また、リダイレクトで出来ること で下記の hexdump コマンドを実行した際にはキーボードから文字列の入力を行うことができました。

% hexdump

では hexdump コマンドがキーボードから直接入力を取得しているかというと、そうではなく、hexdump コマンドに対する入力元はあくまでも標準入力となります。で、標準入力の接続先がキーボードなので、hexdump コマンドは標準入力を介してキーボードの入力を取得し、その入力に応じた処理を行うことができます(そしてその結果が標準出力を介して画面に表示される)。

hexdumpに標準入力から入力される様子

標準エラー出力への出力

あらかじめ確保されている出力経路は標準出力の他にもう1つあって、それが標準エラー出力となります。

正常時のメッセージや正常終了時の結果などの出力に関しては標準出力を利用されることが多いですが、エラー発生時などのメッセージに関しては標準エラー出力を利用されることが多いです(結局コマンドやプログラムが “エラー出力” するかどうかで変わる)。

例えば find コマンドでは、下記のように画面に Permission denied というエラーが出力されることがありますが、これは find から標準エラー出力に対して出力された結果となります。それに対し、下記の text.txt の行の出力は find による検索結果であり、これに関しては標準出力に対して出力された結果となります。

% find . -name "*.txt"
text.txt
find: ./himitu: Permission denied

標準エラー出力も標準出力も両方とも接続先は画面であることが多いので、この2つの違いを意識したことがない方も多いのではないかと思いますが、リダイレクトを使いこなしていくうちに、この2つの違いも自然と意識するようになると思います。

findのエラーが標準エラー出力に出力される様子

ここまでの説明で一番重要なポイントは、ここまで紹介したような入力や出力は全て、コマンドからは「標準入力・標準出力・標準エラー出力」に対して行われているという点です。

キーボードから入力されたり画面に出力されたりするのは、これらに「標準入力・標準出力・標準エラー出力」が接続されているからです。コマンドが接続先に対して直接入出力を行なっているわけではありません。

要は、コマンドが「標準入力・標準出力・標準エラー出力」への入出力を実行すれば、それらの入出力は自動的に接続先に対して行われるということです。

リダイレクトによる接続先の変更

ということは、もし「標準入力・標準出力・標準エラー出力」の接続先を変更することができれば、コマンドの入出力先を「標準入力・標準出力・標準エラー出力」から変更しなくても、キーボード以外から入力を取得したり画面以外に出力を行えるということになります。

そして、この「標準入力・標準出力・標準エラー出力」の接続先を変更するのがリダイレクトになります。

このリダイレクトを利用することで、これらの接続先を変更し、ファイル等に対して入力や出力を行うことが出来るようになります。

リダイレクトにより標準ストリームの接続先を変更する様子

標準入力のリダイレクト

このリダイレクトは、標準入力・標準出力・標準エラー出力それぞれに対して個別に行うことが可能です。

まずは標準入力に対するリダイレクトについて説明していきます。

ある コマンド の標準入力に対するリダイレクトを行う際には、その コマンド の後ろ側に < もしくは 0< を、さらにその後ろ側に 接続先 を指定します。

% コマンド <接続先

例えばファイルを入力したい場合は、接続先 に ファイルのパス を指定します。

これにより、コマンド は標準入力から ファイルのパス で指定されたファイルの中身を受け取って処理を行うことができます。

ここで リダイレクトで出来ること で示した下記のコマンドについて考えると、このコマンドでは hexdump の標準入力の接続先を result.txt へ変更していることになります。

% hexdump <result.txt

なので、hexdumpresult.txt の中身を標準入力から取得し、それに応じた処理結果(16進数への変換結果)を出力することが出来ることになります。

リダイレクトでhexdumpの標準入力の接続先をresult.txtに変更する様子

スポンサーリンク

標準出力のリダイレクト

次は標準出力に対するリダイレクトについて説明していきます。

ある コマンド の標準出力に対するリダイレクトを行う際には、その コマンド の後ろ側に > もしくは 1> を、さらにその後ろ側に 接続先 を指定します。

% コマンド >接続先

例えばファイルに出力したい場合は、接続先 に ファイルのパス を指定します。

これにより、コマンド は標準出力から ファイルのパス で指定されたファイルに出力を行うことができます。

ここで リダイレクトで出来ること で示した下記のコマンドについて考えると、このコマンドでは ls の標準出力の接続先を result.txt へ変更していることになります。

% ls -l >result.txt

なので、ls の標準出力への出力はファイル result.txt に出力されることになります。逆に、画面は標準出力の接続先ではなくなるため、ls の出力結果は画面に表示されなくなります。 

リダイレクトでlsの標準出力の接続先をresult.txtに変更する様子

標準エラー出力のリダイレクト

3つ目として標準エラー出力に対するリダイレクトについて説明していきます。

ある コマンド の標準エラー出力に対するリダイレクトを行う際には、その コマンド の後ろ側に 2> を、さらにその後ろ側に 接続先 を指定します。

% コマンド 2>接続先

例えばファイルに出力したい場合は、接続先 に ファイルのパス を指定します。

これにより、コマンド は標準エラー出力から ファイルのパス で指定されたファイルに出力を行うことができます。

例えば、下記では find の標準エラー出力の接続先を error.txt へ変更していることになります。

% find / -name "*.txt" 2>error.txt

なので、find からの標準エラー出力への出力はファイル error.txt に出力されることになります。ただし、標準出力の接続先は変更していませんので、標準出力への出力は通常通り画面に出力されることになります。

リダイレクトでfindの標準エラー出力の接続先をerror.txtに変更する様子

おそらくですが、Mac や Linux であれば上記のコマンドを実行すると、いずれはエラーが発生して find から標準エラー出力への出力が行われる様子が確認できると思います。

012 の意味

ここまで標準入力・標準出力・標準エラー出力のリダイレクトを行うために、下記を指定する必要があることを説明してきました。

  • 標準入力:< or 0<
  • 標準出力:> or 1>
  • 標準エラー出力:2>

ここで、012 という数値が出てきていますが、これらは入出力経路(標準入力・標準出力・標準エラー出力など)を示すハンドル(ファイルディスクリプタ)という識別子になります。

基本的には、リダイレクトを行う際には <> の前にハンドルを記述して、リダイレクトを行う入出力経路を指定する必要があります。

ただし、単に < と記述した際には標準入力に対するリダイレクトであると認識され、さらに単に > と記述した際には標準出力に対するリダイレクトであると認識されるようになっています。

そのため、標準入力と標準出力に対するリダイレクトのみ、ハンドルの指定は不要となります。逆にそれ以外の入出力経路に対してリダイレクトを行いたい場合は、ハンドルの指定を行う必要があります。なので、標準エラー出力に対するリダイレクトを行う際には 2> と記述する必要があります。

スポンサーリンク

さまざまなリダイレクト

最後に様々なリダイレクトの例を紹介していきます。

よく利用するものもありますし、リダイレクトの仕組みとして重要な要素の解説もありますので、最後までぜひ読んでみてください。

標準入力からファイルを入力する

これはここまでも紹介してきましたが、下記は hexdump の標準入力からファイル(text.txt)を入力する際のリダイレクトの使用例となります。

% hexdump <text.txt

標準出力からファイルへ出力する

これもここまで何度も使ってきましたね!

下記は ls の標準出力からファイル(text.txt)へ出力する際のリダイレクトの使用例となります。

% ls -l  >text.txt

スポンサーリンク

標準出力からファイルに追記する

先程紹介した > を利用したリダイレクトでは、接続先のファイルが既に存在する場合、そのファイルに上書きする形でファイルへの出力が行われることになります。

つまり、元々存在していたファイルの内容が全て削除され、ファイルの先頭から出力が行われていくことにになります。

それに対し、下記のように > の代わりに >> と指定することで、ファイルが存在する場合はファイルの末尾から追記を行う形で出力を行うことができます。

% ls -l  >>text.txt

接続先のファイルが存在しない場合は、> でのリダイレクトでも >> でのリダイレクトでもファイルが新規作成され、ファイルの先頭から出力されていくことになります。

複数のリダイレクトを同時に行う

また、リダイレクトは複数同時に行うことが可能です。

例えば下記では、hexdump の標準入力が input.txt に、hexdump の標準出力が output.txt にそれぞれ接続されることになります。

% hexdump <input.txt >output.txt

これにより、hexdumpinput.txt のファイル内の文字列を16進数(文字コード)に変換した結果を output.txt に出力することになります。

2つのリダイレクトを行う様子

また、上記のように複数のリダイレクトを行う場合、左側に記述したリダイレクトから順に接続先が設定されていくことになります

そのため、上記のコマンドでは、まず標準入力の接続先が input.txt に設定され、

左側のリダイレクトから先に行われていく様子1

その後に標準出力の接続先が output.txt に設定されることになります。

左側のリダイレクトから先に行われていく様子2

で、これら2つの接続先の設定が行われた後に、hexdump が実行されることになります。

今回の例の場合は、<input.txt>output.txt の順番が変わっても同じ結果を得ることができます。ただし、このリダイレクトの記述順によって得られる結果が変わることもあるので注意してください。

その実際の例を 標準出力と標準エラー出力を同じファイルへ出力する で示します。

標準エラー出力を標準出力に合流する

また、ある入出力経路を、他の入出力経路に合流させることも可能です。

例えば下記は、find の標準エラー出力を標準出力に合流させる例となります。

% find . -name "*.txt" 2>&1
./abc.txt
./redirect.txt
./err.txt
./text.txt
./find.txt
find: ./himitu: Permission denied
./output.txt

ここで指定している 1 は、0・1・2 の意味 で説明した標準出力のハンドルです。

n>&m のように記述することで、ハンドル n が割り当てられた出力経路をハンドル m が割り当てられた出力経路に合流させることができます(n<&m と記述することで入力経路の合流も可能)。n を省略した場合は標準出力の出力経路がハンドル m の出力経路に合流させられることになります。

上記では 2>&1 と記述しているため、標準エラー出力の出力経路が標準出力の出力経路に合流することになります。

標準エラー出力を標準出力に合流する様子

元々標準エラー出力と標準出力の接続先が一緒なので意味がないようにも思えますが、次の 標準出力と標準エラー出力を同じファイルへ出力する の例のように、他のリダイレクトと組み合わせることでこのコマンドは効果を発揮します。

また、上記において & を忘れてしまうと、find / -name "*.txt" 2> 1 が実行されることになり、find の標準エラー出力から 1 という名前のファイルに出力が行われることになりますので注意してください。

スポンサーリンク

標準出力と標準エラー出力を同じファイルへ出力する

次は、ここまで説明してきた内容を利用して標準出力と標準エラー出力の同じファイルへの出力を実現していきたいと思います。

結論としては、下記のようにリダイレクトを行うことで、標準出力と標準エラー出力を同じファイルへ出力することができます(下記は find コマンドに対する例となり、当然他のコマンドでも同様のことが行えます)。

% find . -name "*.txt" >output.txt 2>&1

上記では2つのリダイレクトを行なっています。

複数のリダイレクトを行う場合、複数のリダイレクトを同時に行う で解説したように、左側に記述したリダイレクトから順に実施されていくことになります。

なので、最初に実施されるリダイレクトは >output.txt となり、これにより標準出力の接続先が output.txt に設定されます。

1つ目のリダイレクトによる接続先の変更

続いて 2>&1 のリダイレクトが行われます。標準エラー出力を標準出力に合流する で解説したように、これにより標準エラー出力が標準出力に合流することになります。

2つ目のリダイレクトによる接続先の変更

この2つのリダイレクトにより、標準出力と標準エラー出力の同じファイルへの出力を実現しています。

上記は find コマンドでの例になりますが、次の形式でリダイレクトを行えば、他のコマンドに対しても同様の出力を実現することができます。

% コマンド >ファイルのパス 2>&1

さらに、このリダイレクトは下記の2種類の簡略版の形式で指定することも可能です。

% コマンド &>ファイルのパス
% コマンド >&ファイルのパス

コマンド 2>&1 >ファイルのパス は間違い

ちなみに、下記のようにリダイレクトを行なっても、標準出力と標準エラー出力の同じファイルへの出力は実現できないので注意してください。

% コマンド 2>&1 >ファイルのパス

これもで上手くいきそうな気もしますが、複数のリダイレクトを同時に行う で解説したように、複数のリダイレクトを行う場合は左側に記述したリダイレクトから順に実施されていくことになります。

なので、上記の場合、まず標準エラー出力が標準出力に合流することになります。

1つ目のリダイレクトによる標準エラー出力の接続先の変更

そして、その後に標準出力の接続先がファイルに変更されるため、標準エラーは元々の標準出力の接続先である画面に接続されたままとなってしまいます。

2つ目のリダイレクトによる標準出力の接続先の変更

そのため、上記のようにリダイレクトを行なった場合、標準エラーは画面に出力されることになりますので、標準出力と標準エラー出力を同じファイルに出力することはできません。

コマンド >ファイルのパス 2>ファイルのパス は間違い

また、下記のようにリダイレクトを行なった場合、確かに標準出力と標準エラー出力の同じファイルへの出力は実現できるのですが、おそらく意図した結果にならないので注意してください。

% コマンド >ファイルのパス 2>ファイルのパス

上記の2つの ファイルのパス が同じである場合、確かに標準出力と標準エラー出力は同じファイルに接続されることになります。なので、標準出力への出力と標準エラー出力への出力は同じファイルに出力されることになります。

標準出力と標準エラー出力が同じファイルに接続される様子

ただ、標準出力からファイルに追記する で解説したように、接続先のファイルが存在する場合、> でリダイレクトを行うと元々のファイルの中身は削除され、ファイルの先頭から出力が行われていくことになります。

つまり、上記の場合、標準出力からのファイルへの出力も、標準エラー出力からのファイルへの出力も両方先頭から行われていくことになります。そうなると、お互いの出力が上書きし合うことになってしまい、意図した結果を得ることができません。

標準出力からの出力と標準エラーからの出力とがお互いに上書きし合ってしまう様子

そのため、標準出力と標準エラー出力を同じファイルに出力したい場合は、下記のいずれかの形式でリダイレクトを行うようにした方が良いです。

% コマンド >ファイルのパス 2>&1
% コマンド &>ファイルのパス
% コマンド >&ファイルのパス

標準出力と標準エラー出力を破棄する

先ほど標準出力と標準エラー出力から同じファイルに出力を行うようにしましたが、この出力先のファイルを /dev/null に設定することで、標準出力と標準エラー出力からの出力を破棄することが可能です(つまりどこにも出力されなくなる)。

% コマンド >/dev/null 2>&1

上記では標準出力と標準エラー出力からの出力を両方破棄するようにしていますが、もちろんリダイレクトの仕方を変更することで一方のみの破棄を行うようにすることも可能です。

標準出力から画面とファイル両方へ出力する

ここまで紹介してきたリダイレクトの例では全て、標準出力の出力先は1つのみでした(画面 or ファイル or /dev/null)。なので、ここまでのリダイレクトのやり方だと、画面出力&ファイル出力といったような2つの出力先への同時出力を行うことができません。

このような2つの出力先への同時出力を実現するためには、今までとは異なり tee コマンドを利用する必要があります。

tee コマンドは、標準入力から入力された文字列を標準出力およびファイルに出力するコマンドになります。

teeコマンドの動作の説明図

したがって、あるコマンドの標準出力への出力を tee コマンドの標準入力に入力すれば、そのコマンドの標準出力への出力が「標準出力の接続先(画面)」および「ファイル」の両方に出力されることになります。

さらに、この tee コマンドの標準入力への入力は「パイプ |」を利用することで実現できます。

具体的には、下記を実行することにより、コマンド1 の標準出力への出力を、標準出力の接続先及びファイルに同時出力することができます。

% コマンド1 | tee ファイルのパス

コマンド1 の標準出力への出力のデータの流れを表したのが下の図になります。

コマンド1の標準出力への出力データが受け渡しされていく様子を示す図

パイプを利用することで、コマンドの標準出力への出力を別のコマンドに渡すことができるようになります。パイプの詳細については下記ページで解説していますので、こちらも是非読んでみていただければと思います。コマンドを利用するのであればパイプについても知っておいた方が良いです!

パイプの解説ページアイキャッチパイプ | について解説( | と | xargs の違いも理解できる!)

スポンサーリンク

まとめ

このページでは、コマンド操作時に利用されるリダイレクトについて解説しました!

リダイレクトとは、要は入出力経路の接続先を変更するものであり、このリダイレクトによりコマンドの出力をファイルに保存したり、コマンドへの入力をファイルから行ったりできるようになります。

下記ページではリダイレクト同様にコマンド操作時によく利用する「パイプ」の解説も行っていますので、ぜひこちらも読んでみていただければと思います。

パイプの解説ページアイキャッチパイプ | について解説( | と | xargs の違いも理解できる!)

複数のリダイレクトを同時に行ったり、パイプを併用したりするとコマンドが暗号のように思えるくらい複雑になります。

ただ、標準入力・標準出力・標準エラー出力と絡め、パイプやリダイレクトによって接続先がどのように変化するのかを1つ1つ冷静に考えていけば、複雑なコマンドでも意味合いを理解しやすくなると思います。

特にこのページや上記のパイプの解説ページでは、標準入力・標準出力・標準エラー出力とリダイレクトやパイプとの関係性について重点的に解説していますので、複雑なコマンドの意味合いが分からなかったり、コマンドを組み立てる際にリダイレクトやパイプの使い方に迷うような時は、ぜひこれらのページを読み返してみていただければと思います!

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

コメントを残す

メールアドレスが公開されることはありません。