Sur OS X, comme sur tous les systèmes où ils sont pris en charge sauf Linux , l'ouverture /dev/fd/x
est 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/x
est un lien symbolique vers /proc/self/fd/x
et /proc/self/fd/x
est 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_APPEND
bien 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, test
car cat
obtient un nouveau fd en lecture seule file
sans 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 less
est que pour une raison quelconque, less
fait 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.
ksh93
et zsh
sont 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