Para salvar um descritor de arquivo, você o duplica em outro arquivo fd. Salvar um caminho para o arquivo correspondente não é suficiente; você precisará salvar o modo de abertura, os sinalizadores de abertura, a posição atual no arquivo e assim por diante. E, é claro, para tubos ou soquetes anônimos, que não funcionariam, pois não têm caminho. O que você deseja salvar é a descrição do arquivo aberto a que o fd se refere, e a duplicação de um fd está realmente retornando um novo fd à mesma descrição de arquivo aberto .
Para duplicar um descritor de arquivo em outro, com shell semelhante ao Bourne, a sintaxe é:
exec 3>&1
Acima, o fd 1 é duplicado no fd 3.
Qualquer coisa que o fd 3 já estivesse aberto antes seria encerrada, mas observe que os fds 3 a 9 (geralmente mais, até 99 com yash
) são reservados para esse fim (e não têm significado especial contrário a 0, 1 ou 2), o A shell sabe que não deve usá-los para seus próprios negócios internos. A única razão pela qual o fd 3 teria sido aberto anteriormente é porque você fez isso no script 1 ou foi vazado pelo chamador.
Em seguida, você pode alterar o stdout para outra coisa:
exec > /dev/null
E mais tarde, para restaurar o stdout:
exec >&3 3>&-
( 3>&-
sendo fechar o descritor de arquivo que não precisamos mais).
Agora, o problema é que, exceto no ksh, todos os comandos que você executar depois exec 3>&1
herdarão o fd 3. Esse é um vazamento de fd. Geralmente não é grande coisa, mas isso pode causar problemas.
ksh
define o sinalizador close-on-exec nesses fds (para fds acima de 2), mas nenhum outro shells e outros shells não têm como definir esse sinalizador manualmente.
A solução para outro shell é fechar o fd 3 para cada comando, como:
exec 3>&-
exec > file.log
ls 3>&-
uname 3>&-
exec >&3 3>&-
Pesado. Aqui, a melhor maneira seria não usar exec
, mas redirecionar os grupos de comandos:
{
ls
uname
} > file.log
Lá, é o shell que cuida de salvar o stdout e restaurá-lo posteriormente (e o faz internamente duplicando-o em um fd (acima de 9, acima de 99 para yash
) com o conjunto de sinalizadores close-on-exec ).
Nota 1
Agora, o gerenciamento desses fds 3 a 9 pode ser complicado e problemático se você os usar extensivamente ou em funções, especialmente se o seu script usar algum código de terceiros que por sua vez possa usá-los.
Alguns escudos ( zsh
, bash
, ksh93
, tudo foi adicionado o recurso ( sugerido por Oliver Kiddle dezsh
) em torno do mesmo tempo em 2005 depois de ter sido discutido entre seus desenvolvedores) tem uma sintaxe alternativa para atribuir o primeiro fd livre acima de 10 vez que ajuda neste caso:
myfunction() {
local fd
exec {fd}>&1
# stdout was duplicated onto a new fd above 10, whose actual value
# is stored in the fd variable
...
# it should even be safe to re-enter the function here
...
exec >&"$fd" {fd}>&-
}