1. ホーム
  2. bash

[解決済み] Bashで2つのパイプラインの差分を取るには?

2022-05-05 22:57:26

質問

どうすれば 差分 Bashで一時ファイルを使用せずに、2つのパイプラインを使用できますか? 2つのコマンドパイプラインがあるとします。

foo | bar
baz | quux

そして、あなたが見つけたいのは diff をその出力に含めることができます。 一つの解決策としては、当然

foo | bar > /tmp/a
baz | quux > /tmp/b
diff /tmp/a /tmp/b

Bashで一時ファイルを使用せずに行うことは可能でしょうか? diffにパイプラインを通すことで、一時ファイルを一つなくすことができます。

foo | bar > /tmp/a
baz | quux | diff /tmp/a -

しかし、両方のパイプラインを同時にdiffにパイプすることはできません(少なくとも、明白な方法ではありません)。 を含む何か巧妙なトリックがあるのでしょうか? /dev/fd 一時ファイルを使用せずにこれを行うには?

解決方法は?

2つのtmpファイルを持つ1行は、(あなたが望むものではありませんが)。

 foo | bar > file1.txt && baz | quux > file2.txt && diff file1.txt file2.txt

バッシュ が、試してみてはいかがでしょうか。

 diff <(foo | bar) <(baz | quux)

 foo | bar | diff - <(baz | quux)  # or only use process substitution once

2番目のバージョンでは、どの入力がどの入力であったかを、より明確に表示することができます。

-- /dev/stdin vs. ++ /dev/fd/63 などと、2つの番号のついたfdを使うのではなく


少なくとも、bashが以下のようなファイル名を使ってプロセス置換を実装できるOSでは、名前付きパイプさえもファイルシステムに現れません。 /dev/fd/63 を使用すると、コマンドを実行する前にbashが設定した、すでに開いているファイル記述子から実際に読み込むために、コマンドが開いて読み込めるファイル名を取得することができます。 (すなわち、bashは pipe(2) フォークする前に dup2 の出力からリダイレクトするために quux の入力ファイル記述子へ diff fd 63にあります)。

魔法のような("magical".)」がないシステムで。 /dev/fd または /proc/self/fd bashはプロセス代替を実装するために名前付きパイプを使うかもしれませんが、少なくとも一時ファイルとは異なり、パイプ自体を管理しますし、データがファイルシステムに書き込まれることもないでしょう。

bashがどのようにプロセス代替を実装しているかは、次のようにして確認することができます。 echo <(true) を使用して、ファイル名から読み込むのではなく、ファイル名を表示します。 これは /dev/fd/63 典型的な Linux システムの場合。 また、bashがどのようなシステムコールを使っているか正確に知りたい場合は、Linuxシステム上のこのコマンドでファイルやファイルディスクリプタのシステムコールをトレースすることができます。

strace -f -efile,desc,clone,execve bash -c '/bin/true | diff -u - <(/bin/true)'


bashがなければ、名前付きパイプを作ることができます。 . 使用方法 - を伝えるために diff で、一方の入力をSTDINから読み、もう一方の入力として名前付きパイプを使用します。

mkfifo file1_pipe.txt
foo|bar > file1_pipe.txt && baz | quux | diff file1_pipe.txt - && rm file1_pipe.txt


パイプは 1つの出力 から 複数入力 をteeコマンドで実行します。

ls *.txt | tee /dev/tty txtlist.txt 

上記のコマンドは、ターミナルに ls *.txt の出力を表示し、テキストファイル txtlist.txt に出力しています。

しかし、プロセス代行では tee を使えば、同じデータを複数のパイプラインに送り込むことができます。

cat *.txt | tee >(foo | bar > result1.txt)  >(baz | quux > result2.txt) | foobar