OS X, bash: menos funciona em descritores de arquivos abertos, gato não

10

Em um script bash no qual estou trabalhando (que deve ser executado no Ubuntu e OS X), preciso redirecionar a saída de centenas de comandos para um arquivo.
Em vez de anexar &>...a todos eles, eu simplesmente faço

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

Até aqui tudo bem, mas no meio de todos esses comandos, preciso ler tudo o que foi escrito até agora, mantendo o descritor de arquivo aberto.
Agora, no Ubuntu eu posso simplesmente fazer

cat /dev/fd/5

ou

tee </dev/fd/5

mas no OS X, nada é impresso (e os comandos saem imediatamente).
No entanto, usando lesseu posso ver o conteúdo do arquivo em ambos.
Eu consigo o efeito acima (trabalhando nos dois SOs) usando

less /dev/fd/5 | tee

mas isso parece um hack.

Então, por que lessaparentemente pode ver coisas que catnão podem no OS X? (Ou todos os descendentes do BSD são afetados?)
Ou estou fazendo algo errado?

Siguza
fonte

Respostas:

13

No OS X, como em todos os sistemas em que eles são suportados, exceto no Linux , a abertura /dev/fd/xé como a dup(x), o fd resultante aponta mais ou menos para a mesma descrição de arquivo aberto que no fd x e, em particular, terá o mesmo deslocamento no arquivo.

Linux é a exceção aqui. No Linux, /dev/fd/xé um link simbólico para /proc/self/fd/xe /proc/self/fd/xé um pseudo-link simbólico para o arquivo aberto no fd x. No Linux, quando você faz um open("/dev/fd/x", somemode), você obtém uma nova descrição de arquivo aberto para o mesmo arquivo que o aberto x. O novo fd que você obtém não está relacionado a fd x de forma alguma. Em particular, o deslocamento será no início do arquivo (exceto se você o abrir O_APPENDnaturalmente) e o modo (leitura / gravação / anexação ...) poderá ser diferente daquele no arquivo fd x (você pode até obter algo bem diferente do que está no fd x, como a outra extremidade do tubo ao abri-lo no modo oposto). (Isso também significa que isso não funciona para soquetes, por exemplo, que você não pode abrir () ).

Então, no Linux, quando você faz

exec 5<> file
echo test >&5

O deslocamento do fd 5 está no final do arquivo. Se você fizer

cat <&5

Você não ganha nada.

Ainda quando você faz:

cat /dev/fd/5

Você vê testporque catum novo fd somente leitura é filerelacionado ao fd 5.

Em outros sistemas, mediante

cat /dev/fd/5

cat obtém um fd que é uma duplicata do fd 5, portanto, ainda com um deslocamento no final do arquivo.

A razão pela qual ele trabalha lessé que, por algum motivo, lessfaz um lseek()nesse fd até o início do arquivo (faz um lseek(1); lseek(0)para determinar se o arquivo é procurável ou não).

Aqui, você provavelmente deseja ter um fd para leitura e outro para escrever se quiser que ambos tenham desvios diferentes:

exec 5< file 9>&1 > file

Ou você terá que reabrir o arquivo, se ainda estiver lá, ou fazer o lseek()que lessfaz.

ksh93e zshsão os únicos shells com um lseek()operador interno :

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
fonte