Estou brincando com descritores de arquivo para melhor grocá-los e não estou entendendo o seguinte.
$ grep "..." 3>&1 1>/dev/null
1
12
13
123
321
3
O acima não mostra no shell nenhuma das correspondências, isso obviamente está acontecendo porque estou redirecionando para /dev/null. O que eu não entendo é porque 3>&1
não faz com que eu ainda veja a saída, já que fiz uma cópia dela no fd 3.
o que estou perdendo?
Seus redirecionamentos fazem do FD 3 uma cópia do FD 1, então o FD 3 apontará para a saída padrão e qualquer coisa gravada nele irá (por padrão) para o TTY. Você então redireciona FD 1 para
/dev/null
, então qualquer coisa escrita em FD 1 será descartada. Porquegrep
nunca escreve para FD 3, nada de visível acontece com ele.Isso acontece em sequência: primeiro uma cópia (
dup2
) de FD 1 é feita para FD 3, então FD 3 daqui em diante aponta para o que FD 1 aponta atualmente e, em segundo lugar, FD 1 é substituído por um ponteiro para/dev/null
.O resultado final é mostrado no diagrama a seguir :
O erro padrão (em rosa, FD 2) e FD 3 são para o TTY, e a saída padrão é para
/dev/null
. O FD 3 ainda aponta para o TTY porque foi para onde o FD 1 apontou quando a cópia foi feita. No entanto, ogrep
comando não tentará escrever nada no FD 3, portanto a cópia nunca terá uso.A "cópia" é direcional: depois
3>&1
de processado, qualquer coisa escrita no FD 3 irá para onde o FD 1 apontou no momento do processamento. Ele não "preserva" nada além disso: se você redirecionar posteriormente o FD 1, qualquer coisa escrita nele vai para o novo local. O que você fez é mantido no destino original do FD 1 caso você queira usá-lo mais tarde. O único redirecionamento que afeta ondegrep
a saída padrão de ' termina é aquele1>...
que fala explicitamente sobre para onde ela vai.Se
grep
fosse gravar no FD 3, ele apareceria no terminal conforme o esperado. Como ele só envia para FD 1 normalmente, toda a sua saída real está sendo descartada.Poderíamos fazer uma saída grep para FD 3 se quiséssemos:
Isso levará a saída regular em FD 1 e apontará para (o recém-criado) FD 3. Isso não funcionará se você executá-lo diretamente, porque o FD 3 não vai a lugar nenhum, mas podemos incorporá-lo em algo assim que faz uso dele:
O comando entre parênteses é enviado para FD 3. Os redirecionamentos depois 1) apontam FD 3 (que agora tem conteúdo nele) em FD 1 e 2) então direcionam FD 1 para longe novamente (o que não tem efeito). O resultado final é que você obterá a
grep "..."
saída para a saída padrão novamente, exatamente onde estaria sem todo o barulho.Um uso prático desse tipo de redirecionamento é algo como
que troca os FDs 1 e 2, usando o FD 3 como local de armazenamento temporário. Às vezes, também é usado para truques de script de shell, como fingir substituição de processo em POSIX sh com
( cmd1 | ( cmd2 | ( main_command /dev/fd/3 /dev/fd/4 ) 4<&0 ) 3<&0 )
. Caso contrário, é bastante raro que os comandos usem inatamente qualquer descritor de arquivo não padrão por número (é claro que muitos abrem um arquivo e obtêm um).Você está redirecionando o descritor de arquivo 3 para o descritor de arquivo 1 e está redirecionando 1 para /dev/null. Você não está fazendo uma cópia de nada.
A maneira normal de copiar um descritor de arquivo é com
tee
.Além disso, não sei qual é o seu contexto, mas 3 não é um descritor de arquivo interno. Presumivelmente você já o configurou para apontar para algo?