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)
ここで私が持っている問題は次のとおりです。
mkfifo
rm
mktemp
最初に出力しないと文句を言います- mkshは、親プロセスとファイル記述子(stdin、stdout、stderr)をまだ共有している場合は、バックグラウンドプロセスをブロックし
>&-
ます>/dev/null
。使用中、または新しいfdに置き換えられません) - バックグラウンドプロセスには標準入力がないため、その内容をバイト単位で正確にキャッシュする必要があります。
- FIFO(名前付きパイプ)を使用したEOFは容易ではありません。ちょうどそれを置きましょう...(いくつかのトリックを試して、非ブロック的な方法でFIFOを開き、リーダーがあるかどうかを確認し、リーダーが死ぬまでEOF信号をエクスポートすることはできますが、これで十分です。現在)
- 使用後にFIFOを削除すると良いでしょう...
一方、私たちが今これをやっているのは良いことです。なぜなら、結局私はこれをmksh自体に実装したいと思い<(…)
ます。/dev/fd/
移植性が十分ではないため、GNU bashと同じです。
答え2
これは不可能に見える:
diff (echo abc | ./my.psub.sh) (echo def | ./my.psub.sh)
実行する前に2つのサブシェルを終了する必要があるため、ブロックされますdiff
。
これはフィッシュシェルで動作しますが、コマンドやプロセスの置き換えなどの操作を実行している可能性があります。とても違うそしてそれ自体の問題である。
もう一つの選択肢はbusybox
「に従ってください」。mkshのプロセス交換ソリューション":
busybox diff =(sort ./a) =(sort ./b)