Process-Substitution
如何在沒有它的 shell 中實現程序替換(使用 bash 腳本)?
我已經看到 Fish shell 將程序替換作為一個函式實現:
# === 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 shell (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)
命令方塊。我已經嘗試了我能想到的一切,但我不知道下一步該去哪裡。
這有點困難但可行:
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
先輸出- 如果後台程序仍然與父程序共享任何文件描述符(stdin、stdout、stderr),則 mksh 阻塞後台程序(注意:這可能是使用
>&-
而不是的唯一有效案例>/dev/null
,並且僅因為我們可以保證這些 fds 不再被使用,也不會被任何新的 fds 替換)- 因為我們在後台程序中沒有標準輸入,所以我們需要記憶體它的內容,字節精確
- 帶有 FIFO(命名管道)的 EOF 非常重要。讓我們就這樣離開吧……(我們可以嘗試一些技巧來嘗試打開 FIFO 非阻塞以檢查是否有讀卡器,並發出 EOF 信號直到讀卡器死亡,但這目前已經足夠好了)
- 如果在使用後移除 FIFO 會更好……
另一方面:我們現在這樣做是好事,因為我最終希望自己實現
<(…)
mksh,然後我需要知道要注意什麼,因為我們不能/dev/fd/
像 GNU bash 那樣使用,因為那是不夠便攜。