Shell
實現程序替換的可移植(POSIX)方式是什麼?
一些 shell,如
bash
,支持程序替換,這是一種將程序輸出呈現為文件的方法,如下所示:$ diff <(sort file1) <(sort file2)
但是,此構造不是POSIX,因此不可移植。如何以一種POSIX友好的方式(即在 中工作的方式)實現程序替換?
/bin/sh
注意:問題不是問如何區分兩個排序的文件——這只是一個人為的例子來展示程序替換!
該功能由
ksh
(首先在 ksh86 中記錄)引入並正在使用該功能(之前在某些 BSD 和 AT&T 系統中獨立添加)。在ksh93u 及之前,除非您的系統支持. zsh、bash 及以上版本可以在不可用的地方使用臨時命名管道(系統 III 中添加的命名管道)。/dev/fd/*n*``ksh``/dev/fd/*n*``ksh93u+``/dev/fd/*n*
在可用的系統上(POSIX 未指定這些),您可以自己進行程序替換(例如,):
/dev/fd/*n*``diff <(cmd1) <(cmd2)
{ cmd1 4<&- | { # in here fd 3 points to the reading end of the pipe # from cmd1, while fd 0 has been restored from the original # stdin (saved on fd 4, now closed as no longer needed) cmd2 3<&- | diff /dev/fd/3 - } 3<&0 <&4 4<&- # restore the original stdin for cmd2 } 4<&0 # save a copy of stdin for cmd2
然而,這在 Linux 上不起作用
ksh93
,shell 管道是用套接字對而不是管道實現的,並且/dev/fd/3
fd 3 指向套接字的打開在 Linux 上不起作用。儘管 POSIX 沒有指定,但它確實指定了命名管道。命名管道與普通管道一樣工作,只是您可以從文件系統訪問它們。這裡的問題是您必須創建臨時文件並在之後進行清理,這很難可靠地做到,特別是考慮到 POSIX 沒有標準機制(如在某些系統上找到的)來創建臨時文件或目錄以及信號處理(在掛斷或殺死時進行清理)也很難便攜。
/dev/fd/*n*``mktemp -d
您可以執行以下操作:
tmpfifo() ( n=0 until fifo=$1.$$.$n mkfifo -m 600 -- "$fifo" 2> /dev/null do n=$((n + 1)) # give up after 20 attempts as it could be a permanent condition # that prevents us from creating fifos. You'd need to raise that # limit if you intend to create (and use at the same time) # more than 20 fifos in your script [ "$n" -lt 20 ] || exit 1 done printf '%s\n' "$fifo" ) cleanup() { rm -f -- "$fifo"; } fifo=$(tmpfifo /tmp/fifo) || exit cmd2 > "$fifo" & cmd1 | diff - "$fifo" cleanup
(這裡不處理信號處理)。