OS X, bash: meno funziona con i descrittori di file aperti, cat no


10

In uno script bash su cui sto lavorando (che deve essere eseguito su Ubuntu e OS X), devo reindirizzare l'output di centinaia di comandi su un file.
Piuttosto che aggiungere &>...a tutti loro, lo faccio semplicemente

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

Fin qui tutto bene, ma a metà di tutti quei comandi, ho bisogno di leggere tutto ciò che è stato scritto finora, mantenendo aperto il descrittore di file.
Ora, su Ubuntu posso semplicemente fare

cat /dev/fd/5

o

tee </dev/fd/5

ma su OS X, nulla viene stampato (e i comandi escono immediatamente).
Tuttavia, usando lessposso vedere il contenuto del file su entrambi.
Posso ottenere l'effetto sopra (lavorando su entrambi i sistemi operativi) utilizzando

less /dev/fd/5 | tee

ma sembra un trucco.

Quindi, perché lessapparentemente può vedere cose che catnon possono essere su OS X? (O sono interessati tutti i discendenti di BSD?)
O sto facendo qualcosa di sbagliato?

Risposte:


13

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/xed /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_APPENDovviamente 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 testperché catottiene un nuovo fd di sola lettura su filenon 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, lessfa 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 lessfa.

ksh93e zshsono 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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.