Linuxでのパイプとリダイレクト
1. 序章
ほとんどのシェルは、アプリケーションの入力と出力の流れを変更する機能を提供します。 これにより、出力を端末からファイルや他のアプリケーションに転送したり、端末の代わりにファイルから入力を読み取ったりすることができます。
2. 標準入力および出力
シェルでリダイレクトがどのように機能するかを理解する前に、まず標準の入力および出力プロセスを理解する必要があります。
すべてのアプリケーションには、それらを外部に接続する3つの固有のストリームがあります。 これらは、標準入力またはstdinと呼ばれます。 標準出力、またはstdout; および標準エラー、またはstderr。
標準入力は、対話型プログラムに入力を取得するためのデフォルトのメカニズムです。 これは通常、端末で直接実行している場合はキーボードへの直接リンクであり、他の方法では接続されていません。
標準出力は、プログラムからの出力を書き込むためのデフォルトのメカニズムです。 これは通常、出力端子へのリンクですが、パフォーマンス上の理由からバッファリングされることがよくあります。 これは、プログラムが低速のネットワークリンク上で実行されている場合に特に重要になる可能性があります。
3.ファイルへのリダイレクト
アプリケーションを実行する際の一般的なニーズの1つは、ターミナルではなくファイルに出力を送信することです。 具体的には、ここで行っているのは、標準の出力ストリームを目的の場所(この場合はファイル)に置き換えることです。
これは通常、実行するアプリケーションと出力を書き込むファイルの間で>演算子を使用して行われます。たとえば、lsコマンドの出力を次のファイルに送信できます。 ファイルは次のとおりです。
$ ls > files
$ ls -1 *.txt > text-files
3.1. ファイルへの追加
> を使用すると、出力がファイルに書き込まれ、すべての内容が置き換えられます。 必要に応じて、代わりに>>を使用してファイルに追加することもできます:
$ ls -1 *.txt > files
$ ls -1 *.text >> files
$ ls -1 *.log >> files
これを使用して、 echo を使用して正確な出力行を作成するなど、必要に応じてあらゆる種類の出力を使用してファイルを作成できます。
$ echo Text Files > files
$ ls -1 *.txt >> files
$ echo Log Files >> files
$ ls -1 *.log >> files
3.2. 標準エラーのリダイレクト
場合によっては、標準出力ではなく標準エラーをリダイレクトする必要があります。 これは同じように機能しますが、正確なストリームを指定する必要があります。
3つの標準ストリームはすべて、POSIX仕様で定義され、C言語で使用されるID値を持っています。 標準入力は0、標準出力は1、標準誤差は2です。
リダイレクト演算子を使用する場合、デフォルトでは、これは標準出力に適用されます。 ただし、ストリームIDをプレフィックスとして付けることで、リダイレクトするストリームを明示的に指定できます。
たとえば、標準エラーをリダイレクトするには、catコマンドから2>を使用します。
$ cat does-not-exist 2> log
一貫性を保ち、必要に応じて 1> を使用して標準出力をリダイレクトできますが、これは前に見たものと同じです。
使用することもできます &> 標準出力と標準エラーの両方を同時にリダイレクトするには:
$ ls -1 &> log
これにより、コマンドがどのストリーム上にあるかに関係なく、コマンドからのすべての出力が同じファイルに送信されます。 ただし、これは特定のシェルでのみ機能します。たとえば、これはbashまたはzshで使用できますが、shでは使用できません。
3.3. ストリームへのリダイレクト
$ echo Standard Output >&1
$ echo Standard Error >&2
これを上記と組み合わせて、あるストリームから別のストリームにリダイレクトすることで、ストリームを組み合わせることができます。 一般的な構成は、標準エラーを標準出力に結合して、両方を一緒に使用できるようにすることです。 これを使用して達成します 2>&1 –文字通りストリーム2をストリーム1にリダイレクトします。
# ls -1 2>&1
これを使用して、新しいIDを使用するだけで新しいストリームを作成できる場合があります。 ただし、このストリームは最初に他の場所ですでに使用されている必要があります。そうでない場合はエラーになります。 ほとんどの場合、これは最初にストリームソースとして使用されます。
たとえば、次を使用して3番目のストリームを経由することにより、標準出力と標準エラーを入れ替えることができます。 3>&2 2>&1 1>&3 :
$ ls -1 3>&2 2>&1 1>&3
この構成は、すべてのシェルで正しく機能するわけではありません。 bash では、最終結果として、標準出力と標準エラーが直接交換されます。 zsh では、結果として、標準出力と標準エラーの両方が代わりに標準出力になります。
3.4. 複数のストリームをリダイレクトする
上記を簡単に組み合わせて、標準出力と標準エラーを同時にリダイレクトできます。 これはほとんど期待どおりに機能します。同じコマンドで2つの異なるリダイレクトを組み合わせるだけです。
$ ls -1 > stdout.log 2> stderr.log
$ ls -1 > log 2>&1
4. ファイルからの読み取り
$ wc < /usr/share/dict/words
235886 235886 2493109
これを行うと、アプリケーションが受信できる唯一の入力はこのソースからのものであり、すべてすぐに発生します。 これは、ユーザーがアプリケーションの最初にファイルの内容全体を入力する場合と実質的に同じです。
ただし、ファイルの終わりはアプリケーションにも通知されます。これは、多くのアプリケーションが処理を停止するために使用できます。
5. アプリケーション間の配管
$ ls | wc
11 11 138
これにより、最初のアプリケーションの標準出力が2番目のアプリケーションの標準入力に直接接続され、データがそれらの間を直接流れるようになります。
5.1. 標準エラーの処理
標準エラーはデフォルトでは接続されていないため、コンソールに表示されるそのストリームに書き込まれたものはすべて取得されます。 標準エラーはエラー報告用に設計されており、通常のアプリケーション出力用には設計されていないため、これは仕様によるものです。
標準エラーもリダイレクトする場合は、上記の手法を使用して、最初に標準出力にリダイレクトしてから、次のアプリケーションにパイプすることができます。
$ ls i-dont-exist | wc
ls: i-dont-exist: No such file or directory
0 0 0
$ ls i-dont-exist 2>&1 | wc
1 7 44
標準エラーのみをパイプする場合は、前に見たように、標準出力と標準エラーストリームを入れ替える必要があります。
$ ls 3>&2 2>&1 1>&3 | wc -l
some-file
0
$ ls i-dont-exist 3>&2 2>&1 1>&3 | wc -l
1
5.2. パイプの組み合わせ
アプリケーション間を配管する場合、結果を達成するために、多くのアプリケーション間を配管する任意のチェーンを構築することもできます。
$ docker images | cut -d' ' -f1 | tail -n +2 | sort -u | wc -l
17
- docker images –すべてのDockerイメージのリストを取得します
- cut -d” -f1 –この出力を切り取って、列がスペースで区切られている最初の列のみを返します。
- tail -n +2 –これを2行目から開始するように制限します
- sort -u –このリストをソートし、一意のエントリのみを返します
- wc -l –行数をカウントします
したがって、ここには、イメージのバージョンを無視して、一意のDockerイメージの数を取得するコマンドがあります。
多くのコンソールアプリケーションは、まさにこの用途向けに設計されているため、標準入力からの入力を消費し、標準出力に書き込むことができます。
特定のアプリケーションには、これを可能にする特別なモードもあります。たとえば、 git には、磁器および配管コマンドと呼ばれるものがあり、配管コマンドは特別に設計されています。磁器のコマンドは人間が消費するように設計されていますが、このように組み合わせる必要があります。
6. 概要
ここでは、ファイル間または他のアプリケーション間でアプリケーションの入力と出力をリダイレクトするためのいくつかの手法を見てきました。 これらは、単純な入力から複雑な結果を引き起こす可能性のある説得力のある手法です。
これらで他に何ができるか見てみませんか?