プロセス交換なしでシェルでプロセス交換を実装する方法(bashスクリプトを使用)

プロセス交換なしでシェルでプロセス交換を実装する方法(bashスクリプトを使用)

Fishシェルがプロセス置換を関数として実装するのを見ました。

# === Fish shell lang:
function psub
   mkfifo $the_pipe
   cat >$the_pipe &
   echo $the_pipe
   # remove pipe when bg job is done
end  

# Example:
diff (echo abc | psub)  (echo def | psub)

完全なコード:https://github.com/fish-shell/fish-shell/blob/master/share/functions/psub.fish

私はFishではなくシェル(mksh)のためにこれを再実装しようとして数時間努力しましたが、うまくいくことはできません。

# Executable file:  my.psub.sh
the_pipe="$(mktemp /tmp/pipe.XXXXXXXXXX)"
mkfifo $the_pipe
cat >$the_pipe &
echo $the_pipe

# Example:
diff $(echo abc | my.psub.sh)  $(echo def | my.psub.sh)

コマンドブロック。私が考えることができるすべてを試しましたが、次にどこに行くべきかわかりません。

ベストアンサー1

これは少し難しいですが、実行可能です。

function die {
        print -ru2 -- "E: $*"
        exit 1
}

function psubin {
        local stdin=$(cat; echo .) pipe

        pipe=$(mktemp /tmp/psub.XXXXXXXXXX) || die mktemp

        # this is racy
        rm -f "$pipe"
        mkfifo "$pipe" || die mkfifo

        (
                # don’t block parent
                exec <&- >&- 2>&-
                # write content to FIFO
                print -nr -- "${stdin%.}" >"$pipe"
                # signal EOF to reader, ensure it’s not merged
                sleep 0.1
                :>"$pipe"
                # clean up
                (sleep 1; rm -f "$pipe") &
        ) &
        print -nr -- "$pipe"
}

diff -u $(echo abc | psubin) $(echo def | psubin)

ここで私が持っている問題は次のとおりです。

  • mkfiform mktemp最初に出力しないと文句を言います
  • mkshは、親プロセスとファイル記述子(stdin、stdout、stderr)をまだ共有している場合は、バックグラウンドプロセスをブロックし>&-ます>/dev/null。使用中、または新しいfdに置き換えられません)
  • バックグラウンドプロセスには標準入力がないため、その内容をバイト単位で正確にキャッシュする必要があります。
  • FIFO(名前付きパイプ)を使用したEOFは容易ではありません。ちょうどそれを置きましょう...(いくつかのトリックを試して、非ブロック的な方法でFIFOを開き、リーダーがあるかどうかを確認し、リーダーが死ぬまでEOF信号をエクスポートすることはできますが、これで十分です。現在)
  • 使用後にFIFOを削除すると良いでしょう...

一方、私たちが今これをやっているのは良いことです。なぜなら、結局私はこれをmksh自体に実装したいと思い<(…)ます。/dev/fd/移植性が十分ではないため、GNU bashと同じです。

おすすめ記事