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


97

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


これは次の方法で解決できますxargsか?
NN

わからないが、どのように私には明らかではないだろう。私の知る限りxargs、コマンドのファイル文字列引数から入力行を作成します。しかし、私は反対が必要です。
highsciguy

@rahmu見てみましたが、問題の設定は少し違うと思います。少なくとも、答えがどのように役立つかはわかりません。一時ファイルを適切に作成するために受け入れられた答えは、基本的に私が回避したくないものです。一時ファイルがどのように機能するかについての理解は限られています!
highsciguy

何が問題なのecho $data_are_here | dumb_programですか?
フォンブランド

1
これは1つの入力ファイルのみをサポートし、すべてのプログラムが標準入力から読み取るわけではありません。
highsciguy

回答:


55

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

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

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

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

cat fifo

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

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


わかりました、ありがとう、これは2つの名前付きパイプとwdiffでも機能します。しかし、バッファとしてパイプに使用可能な一定の(少量の)メモリがあることを理解したいと思いました。バッファサイズを超えるとどうなりますか?
highsciguy

その問題に関する最後の段落を追加しました。
goldilocks

2
/tmpほとんどのディストリビューションtmpfsでは、RAMにあるファイルシステムを使用するように設定されています。ファイルを書き込む/tmpと、RAMに直接移動するため、迅速にアクセスして何度も書き換える必要がある半復元性のあるファイルに適しています。

127

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リダイレクトのチートシートも参照してください。


これはKSHではサポートされていません
chanchal1987 14

5
kshはこれを発明しました。それをサポートしていないkshのバリアントを使用している
ニールマクギガン

2
ファイル名のコマンドライン引数をとるプログラムの中には、実際に実際のランダムアクセスファイルが必要なものがあるため、この手法はそれらに対して機能しません。これらの場合、あなたは何をしますか。たとえば、ssh -F <(vagrant ssh-config) default本当にいいですが、悲しいかな。
スキマスイッチ

9

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

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

    $> ls | ネコ -

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

    $> ls | 猫/ dev / stdin


1
lessと/ dev / fd / NUMではなく/ dev / stdinのようなopenssl :-)
eel ghEEz
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.