ファイル記述子シャッフリングと/dev/fdを介した2つの入力パイプ

ファイル記述子シャッフリングと/dev/fdを介した2つの入力パイプ

2つのプログラムを1つにまとめたいです。私のシェルがサポートしている場合は使用できますプロセスの置き換え。たとえば、2 つのファイルの共通行を無関係な順序でリストするには、次のようにします。

comm -12 <(sort a) <(sort b)

ただし、プレーンにはプロセス置換はありませんsh。完全なPOSIX移植性を作成してこれを行うことができます。名前付きパイプしかし、FIFOのディレクトリを見つけて整理する必要があるので面倒です。実用的な良いトレードオフは、2つのシェルパイプ構造を使用し、ファイルディスクリプタのミキシングを使用してあるパイプを別のパイプに移動し、次を使用して/dev/fdパイプを指定することです。これはほとんどのUnixバリアントで動作します。

sort a | { exec 3<&0; sort b | comm -12 /dev/fd/0 /dev/fd/3; }

これはdash、bash、BusyBox shなどでは機能しますが、ksh93およびmkshでは機能しません。なぜ?

$ mksh -c 'sort a | { exec 3<&0; sort b | comm -12 /dev/fd/0 /dev/fd/3; }'
$ ksh93 -c 'sort a | { exec 3<&0; sort b | comm -12 /dev/fd/0 /dev/fd/3; }'
comm: /dev/fd/0: No such device or address

答え1

他のコマンドのリダイレクトとは異なり、組み込みexecコマンドのリダイレクトは、シェルが外部プログラムを実行するとオフになる可能性があります。POSIX は両方の動作を許可します。。 Ksh(ATT ksh、pdksh、およびmksh)は、外部ユーティリティを実行するとこれらの記述子を閉じます(つまり、組み込みexecプログラムへのリダイレクトの場合は、dup2リダイレクトを実行するために呼び出し後にFD_CLOEXEC新しい記述子にフラグを設定します)。 Bourne Shell、dash、bash、zsh、および BusyBox sh は、こ​​のリダイレクトを別のリダイレクトとして扱います。

デュアル入力パイプの問題(存在すると仮定/dev/fd)のより移植可能な解決策は、入力を読み取るコマンドの別のリダイレクトを実行して、ファイル記述子を新しいファイル記述子に移動することです。この追加のリダイレクトは、新しい記述子に close-on-exec フラグを設定しません。

sort a | { exec 3<&0; sort b | comm -12 /dev/fd/0 /dev/fd/4 4<&3; }

これはpdksh / mkshとksh93rでは機能しますが、最新バージョンのksh(93s + 2008-01-31または93u + 2012-08-01)では機能しません。私はkshがそこで何をしているのか理解していません。

関連情報