Dashでプロセス置換をエミュレートする方法は?


18

ではbash、Process Substitutionを使用して、プロセスの出力をディスクに保存されたファイルのように扱うことができます。

$ echo <(ls)
/dev/fd/63

$ ls -lAhF <(ls)
lr-x------ 1 root root 64 Sep 17 12:55 /dev/fd/63 -> pipe:[1652825]

残念ながら、プロセス置換はでサポートされていませんdash

Process Substitutionダッシュでエミュレートする最良の方法は何でしょうか?

出力を一時ファイルとして保存したくない(/tmp/)ので、それを削除する必要があります。別の方法はありますか?


しようとしていることに応じて、パイプを使用できる場合があります。
エリックルヌーフ

正直なところ、移植性がここでの主な関心事ではない場合、単にbashデバイスにインストールする方が簡単ではないでしょうか?
はArkadiusz Drabczyk

1
バウンティ通知で提供する例は、たまたまこのリンクされた回答の主題です。そこに示されているように、Gillesの回答の簡略版(の代わりに/dev/fdを使用できると仮定)は次のようになります。xz -cd <file>cat <file> | xz -dxz -cd "$1" | { xz -cd "$2" | { diff /dev/fd/3 /dev/fd/4; } 3<&0; } 4<&0
fraさん

1
@ fra-san-それは実際に私が必要としていたものです。必要に応じて、答えにすることができます。ありがとう。
マーティンベグター

回答:


4

現在の報奨通知の質問:

一般的な例は複雑すぎます。誰かが次の例を実装する方法を説明できますか?diff <(cat "$2" | xz -d) <(cat "$1" | xz -d)

ここに答えがあるようです

Gillesの回答に示されているように、一般的な考え方は、パイプラインのさまざまな段階で「プロデューサー」コマンドの出力を新しいデバイスファイル1に送信し、「コンシューマ」コマンドで使用できるようにすることです。システムがファイル記述子へのアクセスを提供すると仮定します/dev/fd/X)。

探しているものを達成する最も簡単な方法は、おそらく次のとおりです。

xz -cd file1.xz | { xz -cd file2.xz | diff /dev/fd/3 -; } 3<&0

(読みやすくするため、および単一のコマンドで十分なため、代わりに使用file1.xzします)。"$1"xz -cdcat ... | xz -d

最初の「プロデューサー」コマンドの出力は、xz -cd file1.xz複合コマンド({...})にパイプされます。ただし、次のコマンドの標準入力としてすぐに消費されるのではなく、ファイル記述子に複製されるため3、複合コマンド内のすべてにアクセスできるようになります/dev/fd/3。次にxz -cd file2.xz、標準入力もファイル記述子からも何も消費しない2番目の「プロデューサー」コマンドの出力は、3「コンシューマ」コマンドdiffにパイプ処理され、標準入力とから読み取ります/dev/fd/3

必要なだけの「プロデューサー」コマンドにデバイスファイルを提供するために、パイピングとファイル記述子の複製を追加することができます。例:

xz -cd file1.xz | { xz -cd file2.xz | { diff /dev/fd/3 /dev/fd/4; } 4<&0; } 3<&0

特定の質問のコンテキストでは無関係かもしれませんが、次のことに注意する価値があります。

  1. cmd1 <(cmd2) <(cmd3)cmd2 | { cmd3 | { cmd1 /dev/fd/3 /dev/fd/4; } 4<&0; } 3<&0および( cmd2 | ( cmd3 | ( cmd1 /dev/fd/3 /dev/fd/4 ) 4<&0 ) 3<&0 )初期実行環境にさまざまな潜在的影響を与えます。

  2. 中に何が起こるかに反してcmd1 <(cmd2) <(cmd3)cmd3そしてcmd1中にはcmd2 | { cmd3 | { cmd1 /dev/fd/3 /dev/fd/4; } 4<&0; } 3<&0、ユーザからの入力を読み取ることができなくなります。それには、さらにファイル記述子が必要です。たとえば、一致する

    diff <(echo foo) <(read var; echo "$var")
    

    あなたのようなものが必要になります

    { echo foo | { read var 0<&9; echo "$var" | diff /dev/fd/3 -; } 3<&0; } 9<&0
    

1 それらの詳細はU&Lで見つけることができます。例えば/ devとそのサブディレクトリとファイルについてです


12

手動で配管を行うことにより、ボンネットの下でシェルが行うことを再現できます。システムにエントリがある場合は、ファイル記述子のシャッフルを使用できます。翻訳できます/dev/fd/NNN

main_command <(produce_arg1) <(produce_arg2) >(consume_arg3) >(consume_arg4)

{ produce_arg1 |
  { produce_arg2 |
    { main_command /dev/fd5 /dev/fd6 /dev/fd3 /dev/fd4 </dev/fd/8 >/dev/fd/9; } 5<&0 3>&1 |
    consume_arg3; } 6<&0 4>&1; |
  consume_arg4; } 8<&0 9>&1

複数の入力と出力を説明するために、より複雑な例を示しました。標準入力から読み取る必要がなく、プロセス置換を使用している唯一の理由が、コマンドに明示的なファイル名が必要な場合だけです/dev/stdin

main_command <(produce_arg1)
produce_arg1 | main_command /dev/stdin

なしでは、名前付きパイプを使用する必要があります。名前付きパイプはディレクトリエントリであるため、どこかに一時ファイルを作成する必要がありますが、そのファイルは単なる名前であり、データは含まれていません。/dev/fd/NNN

tmp=$(mktemp -d)
mkfifo "$tmp/f1" "$tmp/f2" "$tmp/f3" "$tmp/f4"
produce_arg1 >"$tmp/f1" &
produce_arg2 >"$tmp/f2" &
consume_arg3 <"$tmp/f3" &
consume_arg4 <"$tmp/f4" &
main_command "$tmp/f1" "$tmp/f2" "$tmp/f3" "$tmp/f4"
rm -r "$tmp"

2
</dev/fd/8 >/dev/fd/9<&8 >&9Linuxと同等ではないため、避ける必要があります。
ステファンシャゼラス

@Gilles-複雑な例に混乱しています。エミュレートする方法を教えてください: diff <(cat "$2" | xz -d) <(cat "$1" | xz -d)
マーティンベグター

3

誰かが次の例を実装する方法を説明できますか?
diff <(cat "$2" | xz -d) <(cat "$1" | xz -d)

名前付きパイプはリダイレクトよりも簡単に理解できると思うので、最も簡単に言えば:

mkfifo p1 p2               # create pipes
cat "$2" | xz -d > p1 &    # start the commands in the background
cat "$1" | xz -d > p2 &    #    with output to the pipes
diff p1 p2                 # run 'diff', reading from the pipes
rm p1 p2                   # remove them at the end

p1そしてp2一時的な名前付きパイプしている、彼らは何でも名前を付けることができます。

/tmpGillesの答えが示すように、たとえばディレクトリにパイプを作成する方が賢明です。catここでは必要ないことに注意してください。

tmpdir=$(mktemp -d)
mkfifo "$tmpdir/p1" "$tmpdir/p2"
xz -d < "$2" > "$tmpdir/p1" &
xz -d < "$1" > "$tmpdir/p2" &
diff "$tmpdir/p1" "$tmpdir/p2"
rm -r "$tmpdir"

(おそらく、mktemp「素敵な」ファイル名を作成する可能性があるため、引用符なしでも逃げることができます。)

パイプソリューションには、diffすべての入力を読み取る前にメインコマンド()が終了した場合、バックグラウンドプロセスがハングしたままになる可能性があるという警告があります。


0

どうですか:

cat "$2" | xz -d | diff /dev/sdtin /dev/stderr 2<<EOT
`cat "$1" | xz -d`
EOT
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.