Ich möchte zwei Programme in eins zusammenführen. Wenn meine Shell das unterstützt, kann ich verwendenProzesssubstitution. Um beispielsweise die gemeinsamen Zeilen zweier Dateien in beliebiger Reihenfolge aufzulisten, kann ich verwenden
comm -12 <(sort a) <(sort b)
Allerdings gibt es Prozesssubstitution nicht in plain sh
. Ich kann es mit voller POSIX-Portabilität tun, indem ich einenBenannte Pipe, aber das ist mühsam, da man dafür ein Verzeichnis für die FIFO suchen und anschließend aufräumen muss. Ein guter praktischer Kompromiss ist, zwei Shell-Pipe-Konstrukte zu verwenden und File Descriptor Shuffling zu verwenden, um eine Pipe in einen anderen File Descriptor zu verschieben, und dann zu verwenden, /dev/fd
um die Pipe zu bezeichnen, was bei den meisten Unix-Varianten funktioniert:
sort a | { exec 3<&0; sort b | comm -12 /dev/fd/0 /dev/fd/3; }
Dies funktioniert in Dash, Bash, BusyBox sh usw., aber nicht in KSH93 und MKSH. Warum?
$ mksh -c 'sort a | { exec 3<&0; sort b | comm -12 /dev/fd/0 /dev/fd/3; }'
$ ksh93 -c 'sort a | { exec 3<&0; sort b | comm -12 /dev/fd/0 /dev/fd/3; }'
comm: /dev/fd/0: No such device or address
Antwort1
Im Gegensatz zu Umleitungen bei anderen Befehlen können Umleitungen beim exec
integrierten Befehl geschlossen werden, wenn die Shell ein externes Programm ausführt.POSIX erlaubt beide Verhaltensweisen. Ksh (sowohl ATT ksh als auch pdksh und mksh) schließen diese Deskriptoren, wenn sie ein externes Dienstprogramm ausführen (d. h. für eine Umleitung auf das exec
integrierte Programm dup2
setzen sie nach dem Aufruf zur Durchführung der Umleitung das FD_CLOEXEC
Flag auf dem neuen Deskriptor). Die Bourne-Shell, dash, bash, zsh und BusyBox sh behandeln diese Umleitung wie jede andere Umleitung.
Eine portablere Lösung für das Problem mit den zwei Eingabepipes (unter der Annahme, dass vorhanden ist /dev/fd
) besteht darin, eine weitere Umleitung für den Befehl auszuführen, der die Eingabe liest, und den Dateideskriptor auf einen neuen zu verschieben. Diese zusätzliche Umleitung setzt das Flag „Close-on-Exec“ für den neuen Deskriptor nicht.
sort a | { exec 3<&0; sort b | comm -12 /dev/fd/0 /dev/fd/4 4<&3; }
Dies funktioniert in pdksh/mksh und in ksh93r, aber nicht in neueren Versionen von ksh (93s+ 2008-01-31 oder 93u+ 2012-08-01). Ich verstehe nicht, was ksh dort macht.