De acordo com as Leis 12.965/2014 e 13.709/2018, que regulam o uso da Internet e o tratamento de dados pessoais no Brasil, ao me inscrever na newsletter do portal DICAS-L, autorizo o envio de notificações por e-mail ou outros meios e declaro estar ciente e concordar com seus Termos de Uso e Política de Privacidade.
Colaboração: Julio Cezar Neves
Data de Publicação: 02 de outubro de 2019
Um lembrete, as inscrições para o curso Programação Shell Linux estão abertas, mas apenas até a próxima segunda-feira, às 23h59m. No dia 8 de outubro começamos a pleno vapor. É a última turma deste ano. Para saber mais, clique aqui.
Prá começar com o pé esquerdo, note que quando o Shell examina uma linha de comandos, se não for uma atribuição, a primeira coisa que ele fará são os redirecionamentos. Tenha isso sempre em vista!
Por exemplo, se você fizer:
$ echo Seu nome > arq
$ cat arq
Seu nome
$ cat arq > arq
$ cat arq
$
Dentro de arq não havia nada porque a primeira coisa que o Shell fez, foi criar um arquivo arq vazio para receber a saída do comando (e ele não tem a menor ideia do que o cat faz).
Assim sendo, se você quiser engordar arq com mais dados, você deverá fazer:
echo mais dados >> arq
Parece ate piada, mas 90% das pessoas criam arquivos usando o comando touch. Isso é infinitamente mais lento que simplesmente usar um redirecionamento de entrada para criá-lo.
O comando touch é para trabalhar o timestamp dos arquivos. Para criar ARQ vazio faça:
> ARQ
Vou criar 200 vezes o arquivo Lixo usando o comando touch e medir o tempo:
time for ((i=1; i<200; i++))
{
    touch Lixo
}
real	0m0.145s
user	0m0.016s
sys	0m0.020s
Agora vou fazer o mesmo usando o redirecionamento da saída (>):
time for ((i=1; i<200; i++))
{
    > Lixo
}
real	0m0.008s
user	0m0.008s
sys	0m0.000s
Como dá para notar, é muuuito mais rápido.
Como nós já vimos, o operador FD1&>FD2 que também pode ser FD1>&FD2 associa a saída do file descriptor FD1 à do file descriptor FD2. Então quando você deseja mandar a saída primária e a de erros do programa PRG para /dev/null, por exemplo, você deve fazer:
PRG > /dev/null 2>&1
Onde 1 é o file descriptor da entrada primária (não esqueça que > é o mesmo que 1>) e 2 é o file descriptor da saída de erros. Dessa forma, você associa a saída de erros ao mesmo descritor da saída primária que foi ligada a /dev/null.
Mas veja isso:
 ls NaoExiste
ls: não é possível acessar 'NaoExiste': Arquivo ou diretório não encontrado
O que eu teria de fazer para pegar somente o pedaço da mensagem de erros compreendida entre os dois dois pontos (:)?
Vamos tentar:
ls NaoExiste | cut -f2 -d:
ls: não é possível acessar 'NaoExiste': Arquivo ou diretório não encontrado
Não funcionou porque o cut atuou na saída primária (que estava vazia) e deveria ter atuado na saída de erros. Temos 2 formas de resolver isso:
1. Associar a saída de erros à saída primária que por default já vem associada ao terminal via /dev/pts/1 e então cortar o que interessa:
ls NaoExiste 2>&1 | cut -f2 -d:
não é possível acessar 'NaoExiste'
2. Mandar ambas as saídas para o cut:
 ls NaoExiste |& cut -f2 -d:
não é possível acessar 'NaoExiste'
O problema dessa segunda forma de redirecionamento é que o cut está atuando em ambas as saídas (primária e de erros). No nosso exemplo, sabíamos de antemão que não havia nada para a saída primária, mas se houvesse, o cut poderia gerar um resultado indesejável.
A ordem que você declara os redirecionadores é fundamental. Veja esses 2 casos a seguir:
 ls NaoExiste >x 2>&1; echo Saida = $(cat x)
Saida = ls: não é possível acessar 'NaoExiste': Arquivo ou diretório não encontrado
Aqui correu tudo bem. O erro foi redirecionado para o arquivo x, que foi listado.
 ls NaoExiste 2>&1 >x; echo Saida = $(cat x)
ls: não é possível acessar 'NaoExiste': Arquivo ou diretório não encontrado
Saida =
Assim não funcionou, porque a saída de erros foi associada ao file descriptor 1 que por padrão é o /dev/tty e caso o NaoExiste existisse, seu nome iria para o arquivo x que foi associado à saída primária.