Nem ls
nem grep
precisam de algo aberto no fd3 (eles não usam esse fd), então é melhor fechá-lo (libere os recursos que você não precisa). Nós só usamos o fd 3 para restaurar ls
stdout para o original (antes de executar ls
).
Lembre-se de que, em uma linha de tubulação, todos os comandos são executados simultaneamente em seu próprio processo. Redirecionamentos se aplicam para cada um separadamente, então fechar o fd 3 para um não pode fechá-lo para o outro.
Não fará muita diferença na prática, neste caso, fechar ou não fechar, a não ser que você alcance um limite no número de descritores de arquivos mais cedo, se não o fizer.
Em outros casos (comandos que iniciam outros processos, por exemplo), podem conter recursos e causar problemas. Pense, por exemplo, se o stdout é um pipe, por exemplo, um processo de segundo plano pode acabar herdando esse fd, impedindo que qualquer leitor desse canal veja o EOF até que o processo retorne.
Uma maneira melhor de escrever seria:
{ ls -l 2>&1 >&3 3>&- | grep bad 3>&-; } 3>&1
Dessa forma, o fd3 é redirecionado apenas temporariamente para a duração desse grupo de comando (e restaurado depois ou fechado).
Veja a diferença:
$ { ls -l /proc/self/fd 2>&1 >&3 3>&- | grep bad 3>&-; } 3>&1
total 0
lrwx------ 1 stephane stephane 64 Apr 2 09:29 0 -> /dev/pts/4
lrwx------ 1 stephane stephane 64 Apr 2 09:29 1 -> /dev/pts/4
l-wx------ 1 stephane stephane 64 Apr 2 09:29 2 -> pipe:[575886]
lr-x------ 1 stephane stephane 64 Apr 2 09:29 3 -> /proc/20918/fd/
$ { ls -l /proc/self/fd 2>&1 >&3 | grep bad 3>&-; } 3>&1
total 0
lrwx------ 1 stephane stephane 64 Apr 2 09:29 0 -> /dev/pts/4
lrwx------ 1 stephane stephane 64 Apr 2 09:29 1 -> /dev/pts/4
l-wx------ 1 stephane stephane 64 Apr 2 09:29 2 -> pipe:[575900]
lrwx------ 1 stephane stephane 64 Apr 2 09:29 3 -> /dev/pts/4
lr-x------ 1 stephane stephane 64 Apr 2 09:29 4 -> /proc/20926/fd/
Na segunda invocação, ls
teve seu fd 3 também aberto para o terminal (que estava aberto no stdout no momento em que executei o pipeline) sem um bom motivo.
Note que em ksh93, com exec
, você não precisa fechar esses fds, pois fds diferentes de 0, 1, 2 são automaticamente fechados após a execução de um comando.
$ ksh93 -c 'exec 3>&1; ls -l /dev/fd/'
total 0
lrwx------ 1 stephane stephane 64 Apr 2 09:34 0 -> /dev/pts/16
lrwx------ 1 stephane stephane 64 Apr 2 09:34 1 -> /dev/pts/16
lrwx------ 1 stephane stephane 64 Apr 2 09:34 2 -> /dev/pts/16
lr-x------ 1 stephane stephane 64 Apr 2 09:34 3 -> /proc/21105/fd
$ ksh93 -c 'exec 3>&1; ls -l /dev/fd/ 3>&3'
total 0
lrwx------ 1 stephane stephane 64 Apr 2 09:34 0 -> /dev/pts/16
lrwx------ 1 stephane stephane 64 Apr 2 09:34 1 -> /dev/pts/16
lrwx------ 1 stephane stephane 64 Apr 2 09:34 2 -> /dev/pts/16
lrwx------ 1 stephane stephane 64 Apr 2 09:34 3 -> /dev/pts/16
lr-x------ 1 stephane stephane 64 Apr 2 09:34 4 -> /proc/21108/fd
Eu não sei porque diz (mas não 'ls') acima, soa como um erro (possivelmente meu; -).