プロセス置換を実現するポータブル(POSIX)の方法は何ですか?


25

などの一部のシェルは、次のようbashにプロセス出力をファイルとして表示する方法であるプロセス置換をサポートしています。

$ diff <(sort file1) <(sort file2)

ただし、この構造はPOSIXではないため、移植性がありません。どのように達成される置換を処理することができPOSIXにやさしい方法(で動作すなわち1 /bin/sh

注:質問は、ソートされた2つのファイルをどのように比較するかを尋ねているのではありません-これは、プロセス置換を示すための不自然な例です!


mywiki.wooledge.org/ProcessSubstitutionは、そのノートを持っているmywiki.wooledge.org/NamedPipesを使用することができる。..
Sundeep


1
POSIXは/bin/shPOSIXシェルである必要はなくsh、適切な環境でPOSIXに準拠しているどこかで呼び出されるコマンドがあることだけが必要です。たとえば、Solaris 10 /bin/shではPOSIXシェルではなく、古代のBourneシェルであり、POSIXシェルはにあり/usr/xpg4/bin/shます。
ステファンシャゼル

回答:


17

その機能はksh(最初にksh86で文書化された)によって導入され、その機能を利用してい/dev/fd/nました(以前のBSDやAT&Tシステムで独立して追加されました)。内kshとksh93uまで、それが仕事ではないだろう、あなたのシステムはは/ dev / fdを/ nのサポートがあった場合を除きます。zsh、bashなどはksh93u+、/ dev / fd / nが利用できない一時的な名前付きパイプ(SysIIIで追加された名前付きパイプ)を使用できます。

利用可能なシステムでは(POSIXはそれらを指定しません)、自分でプロセス置換を行うことができます():/dev/fd/ndiff <(cmd1) <(cmd2)

{
  cmd1 4<&- | {
    # in here fd 3 points to the reading end of the pipe
    # from cmd1, while fd 0 has been restored from the original
    # stdin (saved on fd 4, now closed as no longer needed)

    cmd2 3<&- | diff /dev/fd/3 -

  } 3<&0 <&4 4<&- # restore the original stdin for cmd2

} 4<&0 # save a copy of stdin for cmd2

ただし、ksh93Linuxでは動作せず、シェルパイプはパイプではなく/dev/fd/3ソケットペアで実装され、Linuxではfd 3がソケットを指す場所を開けません。

POSIXは指定しませんが。名前付きパイプを指定します。名前付きパイプは、ファイルシステムからアクセスできることを除いて、通常のパイプと同様に機能します。ここでの問題は、一時ファイルまたはディレクトリを作成する標準的なメカニズム(一部のシステムで見られるような)がなく、シグナル処理を移植可能に行うことを考えると、一時的なものを作成して後でクリーンアップする必要があることです。(ハングアップまたはキル時にクリーンアップする)も移植性がありません。/dev/fd/nmktemp -d

次のようなことができます:

tmpfifo() (
  n=0
  until
    fifo=$1.$$.$n
    mkfifo -m 600 -- "$fifo" 2> /dev/null
  do
    n=$((n + 1))
    # give up after 20 attempts as it could be a permanent condition
    # that prevents us from creating fifos. You'd need to raise that
    # limit if you intend to create (and use at the same time)
    # more than 20 fifos in your script
    [ "$n" -lt 20 ] || exit 1
  done
  printf '%s\n' "$fifo"
)

cleanup() { rm -f -- "$fifo"; }
fifo=$(tmpfifo /tmp/fifo) || exit

cmd2 > "$fifo" & cmd1 | diff - "$fifo"
rm -f -- "$fifo"

(ここでは信号処理を行いません)。


名前付きパイプの例は私には完全に明らかです(10は任意の制限でしょうか?)が、例がわかりません/dev/fd/n。記述子4が2回閉じられるのはなぜですか?(記述子3も同様です。)私は迷っています。
ワイルドカード

@Wildcard、必要のないコマンドについては閉じられています。ここでは、diffのみがfd 3を必要とします。fd4は必要ありません。fd4は、元のstdinを伝播するためにのみ使用されますcmd2dup2(0,4)外側{...}で、内側で復元されdup2(4,0)ます{...})。
ステファンシャゼル

mktemp -d誰もあなたの新しいランダムな一時ディレクトリに書き込むべきではないので、FIFOを取得できるようにするために使用できます。
ダニエルH

@DanielH、私はすでに言及していmktemp -dます。しかし、これは標準/ POSIXコマンドではありません。
ステファンシャゼル

ええ、私はそれを知りませんでした。おっとっと。すばやく検索すると、ほとんどのシステムでサポートされているように見えるので、まだ移植可能かもしれませんが、POSIXではありません。
ダニエルH

-1

必要に応じてcmd | while read A B C、次の代わりに、useableの変数の損失を回避します。

VAR="before"
while read A B C 
do
  VAR="$A $VAR"
done < <(cmd)
echo "$VAR"

次を使用できます:

VAR="before"
while read A B C 
do
  VAR="$A $VAR"
done << EndOfText
`cmd`
EndOfText
echo "$VAR"

質問に答えるために:

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