Beberapa shell, seperti bash
, mendukung Proses Substitusi yang merupakan cara untuk menampilkan output proses sebagai file, seperti ini:
$ diff <(sort file1) <(sort file2)
Namun, konstruksi ini bukan POSIX dan, karenanya, tidak portabel. Bagaimana proses substitusi dapat dicapai dengan cara yang ramah POSIX (yaitu yang berfungsi di /bin/sh
) ?
catatan:pertanyaannya bukan menanyakan bagaimana membedakan dua file yang diurutkan – itu hanya contoh yang dibuat-buat untuk mendemonstrasikan proses substitusi!
Jawaban yang Diterima:
Fitur itu diperkenalkan oleh ksh
(pertama didokumentasikan dalam ksh86) dan menggunakan /dev/fd/n
fitur
(ditambahkan secara independen di beberapa BSD dan sistem AT&T sebelumnya).
Dalam ksh
dan hingga ksh93u, itu tidak akan berfungsi kecuali sistem Anda memiliki dukungan untuk /dev/fd/n
. zsh, bash dan ksh93u+
dan di atasnya dapat menggunakan pipa bernama sementara (pipa bernama ditambahkan di Sistem III) di mana /dev/fd/n
tidak tersedia.
Pada sistem di mana /dev/fd/n
tersedia (POSIX tidak menentukannya),
Anda dapat melakukan substitusi proses (mis., diff <(cmd1) <(cmd2)
) sendiri dengan:
{
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
Namun itu tidak berfungsi dengan ksh93
di Linux seperti di sana, pipa shell diimplementasikan dengan socketpairs bukan pipa dan membuka /dev/fd/3
di mana fd 3 menunjuk ke soket tidak berfungsi di Linux.
Meskipun POSIX tidak menentukan /dev/fd/n
, itu menentukan pipa bernama. Pipa bernama berfungsi seperti pipa normal kecuali Anda dapat mengaksesnya dari sistem file. Masalahnya di sini adalah Anda harus membuat yang sementara dan membersihkan setelahnya, yang sulit dilakukan dengan andal, terutama mengingat POSIX tidak memiliki mekanisme standar (seperti mktemp -d
seperti yang ditemukan pada beberapa sistem) untuk membuat file atau direktori sementara, dan penanganan sinyal (untuk membersihkan saat hang-up atau mematikan) juga sulit dilakukan secara portabel.
Anda dapat melakukan sesuatu seperti:
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
(tidak mengurus penanganan sinyal di sini).
Terkait:Proses selesai segera setelah membuka Terminal dan tidak mungkin menambahkan perintah?