bash
などの一部のシェルは、次のようにプロセス出力をファイルとして表示する方法である Process Substitution をサポートします。
$ diff <(sort file1) <(sort file2)
ただし、この構成は [〜#〜] posix [〜#〜] ではないため、移植できません。 [〜#〜] posix [〜#〜] -フレンドリーな方法でプロセス置換を実現するにはどうすればよいですか(つまり1つどちらが/bin/sh
)で機能するか?
注:質問は、並べ替えられた2つのファイルを比較する方法を問うものではありません。これは、デモを行うための工夫された例にすぎません プロセス置換 !
この機能はksh
(ksh86で最初に文書化)によって導入され、_/dev/fd/n
_機能(一部のBSDおよびAT&Tシステムで以前に個別に追加された)を利用していました。 ksh
およびksh93uまでは、システムが/ dev/fd/nをサポートしていない場合は機能しません。 zsh、bash、および_ksh93u+
_以上では、一時的な名前付きパイプ(SysIIIで追加された名前付きパイプ)を利用できますが、/ dev/fd/nは使用できません。
_/dev/fd/n
_が利用可能なシステムでは(POSIXはそれらを指定しません)、自分でプロセス置換(diff <(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
_
ただし、Linuxでは_ksh93
_では機能せず、シェルパイプはパイプではなくソケットペアで実装され、_/dev/fd/3
_を開くと、fd 3がソケットを指し、Linuxでは機能しません。
ただし、POSIXは_/dev/fd/n
_を指定していません。名前付きパイプを指定します。名前付きパイプは、ファイルシステムからアクセスできることを除いて、通常のパイプと同様に機能します。ここでの問題は、一時的なものを作成して後でクリーンアップする必要があることです。特に、POSIXには一時的なファイルまたはディレクトリを作成するための標準メカニズム(一部のシステムで見られる_mktemp -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"
_
(ここでは信号処理を行いません)。