Su OS X, come su tutti i sistemi in cui sono supportati tranne Linux , l'apertura /dev/fd/x
è come fare un dup(x)
, il risultato fd più o meno punta alla stessa descrizione del file aperto di fd x e in particolare avrà lo stesso offset all'interno del file.
Linux è l'eccezione qui. Su Linux, /dev/fd/x
è un collegamento simbolico a /proc/self/fd/x
ed /proc/self/fd/x
è uno pseudo-collegamento simbolico al file aperto su fd x. Su Linux quando si esegue una open("/dev/fd/x", somemode)
, si ottiene una nuova descrizione del file aperto nello stesso file come aperto x
. Il nuovo fd che ottieni non è in alcun modo correlato a fd x. In particolare, l'offset sarà all'inizio del file (tranne se lo si apre O_APPEND
ovviamente con) e la modalità (lettura / scrittura / append ...) può essere diversa da quella su fd x (è anche possibile ottenere qualcosa di molto diverso da quello che c'è su fd x, come l'altra estremità del tubo quando lo si apre nella modalità opposta). (Ciò significa anche che non funziona per i socket, ad esempio che non è possibile aprire () ).
Quindi, su Linux, quando lo fai
exec 5<> file
echo test >&5
L'offset di fd 5 è alla fine del file. Se fate
cat <&5
Non ottieni niente.
Ancora quando lo fai:
cat /dev/fd/5
Vedete test
perché cat
ottiene un nuovo fd di sola lettura su file
non correlato a fd 5.
Su altri sistemi, su
cat /dev/fd/5
cat
ottiene un fd che è un duplicato di fd 5, quindi con un offset alla fine del file.
Il motivo per cui funziona less
è che per qualche motivo, less
fa un lseek()
su quel fd all'inizio del file (fa un lseek(1); lseek(0)
per determinare se il file è ricercabile o meno).
Qui, probabilmente vuoi avere un fd per la lettura e uno per la scrittura se vuoi che entrambi abbiano offset diversi:
exec 5< file 9>&1 > file
Oppure dovrai riaprire il file se è ancora lì, oppure fare lseek()
come less
fa.
ksh93
e zsh
sono le uniche shell con un lseek()
operatore incorporato però:
cat <&5 <#((0)) # ksh93
{sysseek 0; cat} <&5 # zsh, zmodload zsh/system to enable that builtin
O:
cat /dev/fd/5 5<#((0)) # ksh93
sysseek -u 5 0; cat /dev/fd/5 # zsh