Process-Substitution

如何在 Dash 中模擬程序替換?

  • November 21, 2019

bash中,我可以使用 Process Substitution 並將程序的輸出視為保存在磁碟上的文件:

$ echo <(ls)
/dev/fd/63

$ ls -lAhF <(ls)
lr-x------ 1 root root 64 Sep 17 12:55 /dev/fd/63 -> pipe:[1652825]

不幸的是,在dash.

Process Substitution在破折號中模擬的最佳方式是什麼?

我不想將輸出保存為某處(/tmp/)的臨時文件,然後必須將其刪除。有替代方法嗎?

目前賞金通知中的問題:

一般的例子太複雜了。有人可以解釋如何實現以下範例嗎?diff <(cat "$2" | xz -d) <(cat "$1" | xz -d)

似乎這裡有答案。

Gilles 的回答所示,總體構想是將“生產者”命令的輸出發送到管道不同階段的新設備文件1,使它們可用於“消費者”命令,這些命令可能將文件名作為參數(假設您的系統允許您訪問文件描述符作為/dev/fd/X)。

實現您正在尋找的最簡單的方法可能是:

xz -cd file1.xz | { xz -cd file2.xz | diff /dev/fd/3 -; } 3<&0

(使用file1.xz代替是"$1"為了可讀性,xz -cd而不是cat ... | xz -d因為單個命令就足夠了)。

第一個“生產者”命令 的輸出通過xz -cd file1.xz管道傳送到復合命令 ( {...});但是,它不是立即作為下一個命令的標準輸入使用,而是複製到文件描述符中3,因此復合命令中的所有內容都可以訪問/dev/fd/3. 第二個“生產者”命令的輸出,xz -cd file2.xz既不消耗其標準輸入,也不消耗文件描述符3中的任何內容,然後通過管道傳輸到“消費者”命令diff,該命令從其標準輸入和/dev/fd/3.

可以添加管道和文件描述符複製,以便根據需要為盡可能多的“生產者”命令提供設備文件,例如:

xz -cd file1.xz | { xz -cd file2.xz | { diff /dev/fd/3 /dev/fd/4; } 4<&0; } 3<&0

雖然它可能與您的具體問題無關,但值得注意的是:

  1. cmd1 <(cmd2) <(cmd3)cmd2 | { cmd3 | { cmd1 /dev/fd/3 /dev/fd/4; } 4<&0; } 3<&0並對( cmd2 | ( cmd3 | ( cmd1 /dev/fd/3 /dev/fd/4 ) 4<&0 ) 3<&0 )初始執行環境產生不同的潛在影響。
  2. 與 in 中發生的情況相反cmd1 <(cmd2) <(cmd3)cmd3並且cmd1incmd2 | { cmd3 | { cmd1 /dev/fd/3 /dev/fd/4; } 4<&0; } 3<&0將無法讀取使用者的任何輸入。這將需要更多的文件描述符。例如,要匹配
diff <(echo foo) <(read var; echo "$var")

你將需要類似的東西

{ echo foo | { read var 0<&9; echo "$var" | diff /dev/fd/3 -; } 3<&0; } 9<&0

1 可以在 U&L 上找到更多關於它們的資訊,例如在了解 /dev 及其子目錄和文件中。

您可以通過手動進行管道來重現外殼在引擎蓋下的作用。如果你的系統有條目,你可以使用文件描述符改組:你可以翻譯/dev/fd/*NNN*

main_command <(produce_arg1) <(produce_arg2) >(consume_arg3) >(consume_arg4)

{ produce_arg1 |
 { produce_arg2 |
   { main_command /dev/fd5 /dev/fd6 /dev/fd3 /dev/fd4 </dev/fd/8 >/dev/fd/9; } 5<&0 3>&1 |
   consume_arg3; } 6<&0 4>&1; |
 consume_arg4; } 8<&0 9>&1

我展示了一個更複雜的範例來說明多個輸入和輸出。如果您不需要從標準輸入中讀取,並且您使用程序替換的唯一原因是該命令需要一個明確的文件名,您可以簡單地使用/dev/stdin

main_command <(produce_arg1)
produce_arg1 | main_command /dev/stdin

沒有,您需要使用命名管道。命名管道是一個目錄條目,因此您需要在某處創建一個臨時文件,但該文件只是一個名稱,它不包含任何數據。/dev/fd/*NNN*

tmp=$(mktemp -d)
mkfifo "$tmp/f1" "$tmp/f2" "$tmp/f3" "$tmp/f4"
produce_arg1 >"$tmp/f1" &
produce_arg2 >"$tmp/f2" &
consume_arg3 <"$tmp/f3" &
consume_arg4 <"$tmp/f4" &
main_command "$tmp/f1" "$tmp/f2" "$tmp/f3" "$tmp/f4"
rm -r "$tmp"

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