OS X, bash: moins de travaux sur les descripteurs de fichiers ouverts, cat ne fonctionne pas

10

Dans un script bash sur lequel je travaille (qui doit s'exécuter sur Ubuntu et OS X), j'ai besoin de rediriger la sortie de centaines de commandes vers un fichier.
Plutôt que de les ajouter &>...à tous, je fais simplement

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

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

cat /dev/fd/5

ou

tee </dev/fd/5

mais sous OS X, rien n'est imprimé du tout (et les commandes se terminent immédiatement).
Cependant, en utilisant lessJe peux voir le contenu du fichier sur les deux.
Je peux obtenir l'effet ci-dessus (en travaillant sur les deux OS) en utilisant

less /dev/fd/5 | tee

mais cela ressemble à un hack.

Alors, pourquoi peut-on lessvoir apparemment des choses qui catne peuvent pas sur OS X? (Ou tous les descendants de BSD sont-ils affectés?)
Ou est-ce que je fais quelque chose de mal?

Siguza
la source

Réponses:

13

Sur OS X, comme sur tous les systèmes où ils sont pris en charge sauf Linux , l'ouverture /dev/fd/xest comme faire un dup(x), le fd résultant pointe plus ou moins vers la même description de fichier ouvert que sur fd x et en particulier aura le même décalage dans le fichier.

Linux est l'exception ici. Sous Linux, /dev/fd/xest un lien symbolique vers /proc/self/fd/xet /proc/self/fd/xest un pseudo-lien symbolique vers le fichier ouvert sur fd x. Sous Linux, lorsque vous effectuez une open("/dev/fd/x", somemode), vous obtenez une toute nouvelle description de fichier ouvert dans le même fichier que open on x. Le nouveau fd que vous obtenez n'est en aucun cas lié à fd x. En particulier, l'offset sera au début du fichier (sauf si vous l'ouvrez avec O_APPENDbien sûr) et le mode (lecture / écriture / ajout ...) peut être différent de celui sur fd x (vous pouvez même obtenir quelque chose de très différent de ce qui se trouve sur fd x, comme l'autre extrémité du tuyau lorsque vous l'ouvrez 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 fichier. Si tu fais

cat <&5

Vous n'obtenez rien.

Toujours quand vous le faites:

cat /dev/fd/5

Vous voyez, testcar catobtient un nouveau fd en lecture seule filesans rapport avec fd 5.

Sur d'autres systèmes,

cat /dev/fd/5

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

La raison pour laquelle cela fonctionne lessest que pour une raison quelconque, lessfait un lseek()sur ce fd au début du fichier (fait un lseek(1); lseek(0)pour déterminer si le fichier est consultable ou non).

Ici, vous voulez probablement avoir un fd pour la lecture et un pour l'écriture si vous voulez que les deux aient des décalages différents:

exec 5< file 9>&1 > file

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

ksh93et zshsont les seuls shells avec un lseek()opérateur intégré cependant:

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

Ou:

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