OS X, bash: menos funciona en descriptores de archivos abiertos, cat no

10

En un script bash en el que estoy trabajando (que tiene que ejecutarse en Ubuntu y OS X), necesito redirigir la salida de cientos de comandos a un archivo.
En lugar de agregar &>...a todos ellos, simplemente hago

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

Hasta ahora todo bien, pero a la mitad de todos esos comandos, necesito leer todo lo que se ha escrito hasta ahora, manteniendo abierto el descriptor de archivo.
Ahora, en Ubuntu simplemente puedo hacer

cat /dev/fd/5

o

tee </dev/fd/5

pero en OS X, no se imprime nada (y los comandos salen inmediatamente).
Sin embargo, usando lesspuedo ver el contenido del archivo en ambos.
Puedo lograr el efecto anterior (trabajando en ambos sistemas operativos) usando

less /dev/fd/5 | tee

Pero eso parece un truco.

Entonces, ¿por qué lessaparentemente puede ver cosas que catno pueden en OS X? (¿O están afectados todos los descendientes de BSD?) ¿
O estoy haciendo algo mal?

Siguza
fuente

Respuestas:

13

En OS X, como en todos los sistemas donde son compatibles, excepto Linux , la apertura /dev/fd/xes como hacer una dup(x), el fd resultante apunta más o menos a la misma descripción de archivo abierto que en fd x y en particular tendrá el mismo desplazamiento dentro del archivo.

Linux es la excepción aquí. En Linux, /dev/fd/xes un enlace simbólico /proc/self/fd/xy /proc/self/fd/xes un pseudo-enlace simbólico al archivo abierto en fd x. En Linux cuando hace una open("/dev/fd/x", somemode), obtiene una nueva descripción de archivo abierto para el mismo archivo que abierto en x. El nuevo fd que obtenga no está relacionado con fd x de ninguna manera. En particular, el desplazamiento estará al comienzo del archivo (excepto si lo abre, por O_APPENDsupuesto) y el modo (lectura / escritura / anexar ...) puede ser diferente del de fd x (incluso puede obtener algo bastante diferente de lo que está en fd x, como el otro extremo de la tubería al abrirlo en el modo opuesto). (Eso también significa que eso no funciona para sockets, por ejemplo, que no puedes abrir () ).

Entonces, en Linux, cuando lo haces

exec 5<> file
echo test >&5

El desplazamiento del fd 5 está al final del archivo. Si lo haces

cat <&5

No consigues nada.

Aún cuando lo haces:

cat /dev/fd/5

Verá testporque catobtiene un nuevo fd de solo lectura que fileno está relacionado con fd 5.

En otros sistemas, sobre

cat /dev/fd/5

cat obtiene un fd que es un duplicado de fd 5, por lo que aún con un desplazamiento al final del archivo.

La razón por la que funciona lesses que, por alguna razón, lesshace un lseek()f en ese fd al comienzo del archivo (hace un lseek(1); lseek(0)para determinar si el archivo es buscable o no).

Aquí, probablemente desee tener un fd para leer y uno para escribir si desea que ambos tengan diferentes compensaciones:

exec 5< file 9>&1 > file

O tendrá que volver a abrir el archivo si todavía está allí, o hacer lseek()lo lessmismo.

ksh93y zshson las únicas conchas con un lseek()operador incorporado :

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
Stéphane Chazelas
fuente