web-dev-qa-db-ja.com

一時データの疑似ファイル

比較的短い文字列データ(ただし、数行になる可能性があります)を、ファイル(wdiffなど)からの入力のみを繰り返し受け入れるコマンドラインプログラムにフィードすることがよくあります。確かに、1つ以上の一時ファイルを作成し、そこに文字列を保存して、ファイル名をパラメーターとしてコマンドを実行できます。しかし、データが実際にディスクに書き込まれる場合、この手順は非常に非効率的であり、この手順を何度も繰り返すと、必要以上にディスクに損傷を与える可能性があるように見えます。長いテキストファイルの1行をwdiffにフィードする場合。これを回避する推奨される方法はあります。たとえば、パイプなどの疑似ファイルを使用して、実際にデータをディスクに書き込むことなく(またはクリティカルな長さを超えた場合にのみ書き込む)、データを一時的に格納します。 wdiffは2つの引数を取ることに注意してください。私が理解している限り、wdiff <"text"のような処理を行うデータをフィードすることはできません。

108
highsciguy

名前付きパイプ を使用します。例として:

mkfifo fifo
echo -e "hello world\nnext line\nline 3" > fifo

-eは、エコーに改行エスケープ(\n)。これはブロックします。つまり、何かがパイプからデータを読み取るまでシェルはハングします。

同じディレクトリにある別のシェルを開きます。

cat fifo

エコーを読んで、他のシェルを解放します。パイプはディスク上のファイルノードとして存在しますが、通過するデータは存在しません。それはすべてメモリ内で行われます。背景(&)エコー。

パイプには64kバッファー(Linuxの場合)があり、ソケットと同様に、いっぱいになるとライターがブロックされるため、ライターを途中で終了しない限り、データが失われることはありません。

58
goldilocks

Bashでは、command1 <( command0 )リダイレクト構文を使用できます。これは、_command0_のstdoutをリダイレクトし、コマンドライン引数としてファイル名を受け取る_command1_に渡します。これは プロセス置換 と呼ばれます。

ファイル名のコマンドライン引数を取る一部のプログラムは、実際には実際のランダムアクセスファイルを必要とするため、この手法はそれらでは機能しません。ただし、wdiffでは問題なく動作します。

_user@Host:/path$ wdiff <( echo hello; echo hello1 ) <( echo hello; echo hello2 )
hello
[-hello1-]
{+hello2+}
_

バックグラウンドで、これはFIFOを作成し、<( )内のコマンドをFIFOにパイプし、引数としてFIFOのファイル記述子を渡します。何が起こっているかを確認するには、echoと一緒に使用して、何もせずに引数を出力します。

_user@Host:/path$ echo <( echo hello )
/dev/fd/63
_

名前付きパイプの作成は(複数のプロセスを使用して複雑なリダイレクトロジックを記述したい場合)より柔軟ですが、多くの目的でこれで十分であり、明らかに使いやすくなっています。

また、出力として使用する場合の>( )構文もあります。

_$ someprogram --logfile >( gzip > out.log.gz )
_

関連するテクニックについては Bashリダイレクトのチートシート も参照してください。

143

wdiffは、2つのファイル名引数を必要とするため、特殊なケースですが、1つの引数しか必要とせず、頑固にファイル名引数以外のものを取ることを拒否するすべてのコマンドには、2つのオプションがあります。

  • ファイル名 '-'(つまり、マイナス記号)は、時間の約1/2で機能します。問題のコマンドと、コマンドの開発者がそのケースをトラップして期待どおりに処理するかどうかに依存するようです。例えば.

    $> ls |ネコ -

  • Linuxに存在する/ dev/stdinという名前の疑似ファイルがあり、コマンドでファイル名が絶対に必要な場合に使用できます。コマンドから特別なファイル名を処理する必要がないため、これは機能する可能性が高くなります。 fifoが機能する場合、またはbash プロセス置換メソッドが機能する場合、これも機能し、シェル固有ではありません。例えば.

    $> ls |猫/ dev/stdin

11
dabuntu