OS X, Bash: Weniger funktioniert bei offenen Dateideskriptoren, Cat nicht

10

In einem Bash-Skript, an dem ich arbeite (das unter Ubuntu und OS X ausgeführt werden muss), muss ich die Ausgabe von Hunderten von Befehlen in eine Datei umleiten.
Anstatt &>...an alle anzuhängen, mache ich es einfach

exec 9>&1
exec 5<>/tmp/some-file.txt
exec 1>&5

So weit so gut, aber nach der Hälfte all dieser Befehle muss ich alles lesen, was bisher geschrieben wurde, während der Dateideskriptor offen bleibt.
Jetzt kann ich unter Ubuntu einfach machen

cat /dev/fd/5

oder

tee </dev/fd/5

Unter OS X wird jedoch überhaupt nichts gedruckt (und die Befehle werden sofort beendet).
Mit kann lessich jedoch den Inhalt der Datei auf beiden sehen.
Ich kann den obigen Effekt (bei beiden Betriebssystemen) mit erzielen

less /dev/fd/5 | tee

aber das scheint ein hack zu sein.

Warum kann man also lessanscheinend Dinge sehen, catdie unter OS X nicht möglich sind? (Oder sind alle BSD-Nachkommen betroffen?)
Oder mache ich etwas falsch?

Siguza
quelle

Antworten:

13

Unter OS X, wie auf allen Systemen, auf denen sie unterstützt werden, mit Ausnahme von Linux , ist das Öffnen /dev/fd/xwie bei a dup(x). Das resultierende fd zeigt mehr oder weniger auf dieselbe Beschreibung der geöffneten Datei wie auf fd x und hat insbesondere den gleichen Versatz innerhalb der Datei.

Linux ist hier die Ausnahme. Ist unter Linux /dev/fd/xein Symlink zu /proc/self/fd/xund /proc/self/fd/xeine Pseudo-Symlink zu der auf fd x geöffneten Datei. Wenn Sie unter Linux open("/dev/fd/x", somemode)eine ausführen, erhalten Sie eine brandneue Beschreibung der geöffneten Datei für dieselbe Datei wie beim Öffnen x. Das neue fd, das Sie erhalten, ist in keiner Weise mit fd x verbunden. Insbesondere befindet sich der Offset am Anfang der Datei (außer wenn Sie sie O_APPENDnatürlich mit öffnen ) und der Modus (Lesen / Schreiben / Anhängen ...) kann sich von dem auf fd x unterscheiden (Sie können ihn sogar erhalten etwas ganz anderes als das, was sich auf fd x befindet, wie das andere Ende des Rohrs, wenn es im entgegengesetzten Modus geöffnet wird). (Das bedeutet auch, dass dies beispielsweise für Sockets nicht funktioniert, die Sie nicht öffnen können () ).

Also, unter Linux, wenn Sie es tun

exec 5<> file
echo test >&5

Der Versatz des fd 5 befindet sich am Ende der Datei. Wenn Sie tun

cat <&5

Du bekommst nichts.

Immer noch, wenn Sie:

cat /dev/fd/5

Sie sehen, testweil catein neues schreibgeschütztes fd filenicht mit fd 5 zusammenhängt.

Auf anderen Systemen auf

cat /dev/fd/5

cat erhält eine fd, die ein Duplikat von fd 5 ist, also immer noch mit einem Versatz am Ende der Datei.

Der Grund, warum es funktioniert, lessist, dass aus irgendeinem Grund lessa lseek()auf diesem fd bis zum Anfang der Datei ausgeführt wird (führt a aus, lseek(1); lseek(0)um festzustellen, ob die Datei durchsuchbar ist oder nicht).

Hier möchten Sie wahrscheinlich einen fd zum Lesen und einen zum Schreiben haben, wenn beide unterschiedliche Offsets haben sollen:

exec 5< file 9>&1 > file

Oder Sie müssen die Datei erneut öffnen, wenn sie noch vorhanden ist, oder eine lseek()Aktion lessausführen.

ksh93und zshsind die einzigen Shells mit einem eingebauten lseek()Operator:

cat <&5 <#((0)) # ksh93
{sysseek 0; cat} <&5 # zsh, zmodload zsh/system to enable that builtin

Oder:

cat /dev/fd/5 5<#((0))  # ksh93
sysseek -u 5 0; cat /dev/fd/5 # zsh
Stéphane Chazelas
quelle