Zwei Eingabe-Pipes durch File-Descriptor-Shuffling und /dev/fd

Zwei Eingabe-Pipes durch File-Descriptor-Shuffling und /dev/fd

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/fdum 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 execintegrierten 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 execintegrierte Programm dup2setzen sie nach dem Aufruf zur Durchführung der Umleitung das FD_CLOEXECFlag 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.

verwandte Informationen