プロセス交換を実装する移植可能な(POSIX)方法は何ですか?

プロセス交換を実装する移植可能な(POSIX)方法は何ですか?

たとえば、一部のシェルはbash以下をサポートしています。プロセスの交換これは、次のようにプロセスの出力をファイルにレンダリングする方法です。

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

ただし、この構成はそうではありません。POSIXしたがって、持ち運びが容易ではありません。プロセス置換を達成する方法POSIX- フレンドリーな態度(つまり、で働く/bin/sh

注:質問は、2つのソートされたファイルを区別する方法を尋ねることではありません。これは、説明するために設計された例にすぎません。プロセスの交換

答え1

この機能はksh導入され(ksh86で最初に文書化されている)使用中です(以前は一部のBSDおよびAT&Tシステムに独立して追加されました)。 ksh93u以前では、システムがサポートしていない限り、zsh、bash以降では使用できない場合は、一時的な名前付きパイプ(System IIIに追加された名前付きパイプ)を使用できます。/dev/fd/nksh/dev/fd/nksh93u+/dev/fd/n

使用可能なシステム(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

ksh93ただし、シェルパイプはパイプではなくソケットペアとして実装され、ソケットの場所を指す/dev/fd/3fd 3を開くことはLinuxでは機能しないため、Linuxでは機能しません。

POSIXはこれを指定しませんが、名前付きパイプを指定します。名前付きパイプは、ファイルシステムからアクセスできることを除いて、通常のパイプのように機能します。ここでの問題は、一時ファイルを生成して後でクリーンアップする必要があることです。特に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"

cleanup

(ここでは信号処理を考慮していません。)

答え2

これを達成するには、heredocファイルと/ dev / fd / nファイルを使用できます。たとえば、bash次のようにできます。

#!/usr/bin/env bash

paste  <(echo "$SHELL") <(echo "$TERM") <(echo "$LANG")

ただし、POSIX shでは、次のことを行う必要があります。

#!/bin/sh

paste /dev/fd/3 3<<-EOF /dev/fd/4 4<<-EOF /dev/fd/5 5<<-EOF 
$SHELL
EOF
$TERM
EOF
$LANG
EOF

出力は同じです。

質問に答えるには、次のように動作します。

#!/bin/sh

diff /dev/fd/3 3<<-EOF /dev/fd/4 4<<-EOF
$(sort file1)
EOF
$(sort file2)
EOF

あいまいに見えますが動作します。

答え3

便利な変数を失わないようにするにはcmd | while read A B C:

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

関連情報