Process-Substitution

如何在沒有它的 shell 中實現程序替換(使用 bash 腳本)?

  • March 30, 2016

我已經看到 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 那樣使用,因為那是不夠便攜。

引用自:https://unix.stackexchange.com/questions/272838