OS X, bash: less de travaux sur les descripteurs de files ouverts, chat ne fait pas

Dans un script bash sur lequel je travaille (qui doit fonctionner sur Ubuntu et OS X), j'ai besoin de redirect la sortie de centaines de commands vers un file.
Plutôt que d'append &>... à tous, je fais simplement

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

Jusqu'ici tout va bien, mais à mi-path de toutes ces commands, j'ai besoin de lire tout ce qui a été écrit jusqu'ici, tout en gardant le descripteur de file ouvert.
Maintenant, sur Ubuntu je peux simplement faire

 cat /dev/fd/5 

ou

 tee </dev/fd/5 

mais sur OS X, rien n'est imprimé du tout (et les commands sortent immédiatement).
Cependant, en utilisant less je peux voir le contenu du file sur les deux.
Je peux atteindre l'effet ci-dessus (travailler sur les deux OS) en utilisant

 less /dev/fd/5 | tee 

mais cela semble être un piratage.

Alors, pourquoi voir less apparemment des choses que ce cat ne peut pas sur OS X? (Ou tous les descendants BSD sont-ils affectés?)
Ou est-ce que je fais quelque chose de mal?

L'ouverture de /dev/fd/x ressemble à celle d'un dup(x) , comme sur tous les systèmes où ils sont supportés sauf Linux , le fd résultant pointe plus ou less vers la même description de file ouverte que sur fd x et en particulier aura le même décalage dans le file.

Linux est l'exception ici. Sous Linux, /dev/fd/x est un lien symbolique vers /proc/self/fd/x et /proc/self/fd/x est un pseudo-lien symbolique vers le file ouvert sur fd x. Sous Linux, lorsque vous open("/dev/fd/x", somemode) , vous obtenez une toute nouvelle description de file ouverte dans le même file que celui ouvert sur x . Le nouveau fd que vous obtenez n'est en aucun cas lié à fd x. En particulier, le décalage sera au début du file (sauf si vous l'ouvrez avec O_APPEND bien sûr) et le mode (lecture / écriture / ajout …) peut être différent de celui sur fd x (vous pouvez même get quelque chose de tout à fait différent de ce qui est sur fd x, comme l'autre bout du tuyau en l'ouvrant dans le mode opposé). (Cela signifie également que cela ne fonctionne pas pour les sockets par exemple que vous ne pouvez pas ouvrir () ).

Donc, sous Linux, quand vous le faites

 exec 5<> file echo test >&5 

Le décalage du fd 5 est à la fin du file. Si tu fais

 cat <&5 

Tu n'as rien.

Toujours quand vous faites:

 cat /dev/fd/5 

Vous voyez le test parce que cat obtient un nouveau fd en lecture seule pour un file non lié à fd 5.

Sur d'autres systèmes, sur

 cat /dev/fd/5 

cat obtient un fd qui est un doublon de fd 5, donc toujours avec un décalage à la fin du file.

La raison pour laquelle il fonctionne avec less est que pour une raison quelconque, less un lseek() sur ce fd au début du file (fait un lseek(1);lseek(0) pour déterminer si le file est ou non) .

Ici, vous voulez probablement avoir un fd pour la lecture et un pour l'écriture si vous voulez avoir des offsets différents:

 exec 5< file 9>&1 > file 

Ou vous devrez rouvrir le file s'il est toujours là, ou faire un lseek() comme less .

ksh93 est le seul shell avec un opérateur lseek() cependant:

 cat <&5 <#((0)) 

Ou:

 cat /dev/fd/5 5<#((0))