você está aqui: Home  → Arquivo de Mensagens

Redirecionamentos - Parte 4 - Redirecionamento da Entrada Primária (StdIn)

Colaboração: Julio Cezar Neves

Data de Publicação: 04 de outubro de 2019

Costumo dizer que a qualidade do programador Shell é inversamente proporcional à quantidade de vezes que ele usa o comando cat e a partir de agora, veremos que essa instrução não deveria quase nunca ser usada em scripts.

Vejo muito algumas coisas assim:

Como vejo por aí Como deveria ser
cat ARQ | grep ... grep ... ARQ
cat ARQ | cut ... cut ... ARQ
cat ARQ | tr ... tr ... < ARQ
cat ARQ | more more ARQ

E a lista não acaba aí, serve pra wc, less, ... já existe até um apelido para isso: cat command abuse.

Redirecionamento da Entrada Primária (StdIn)

O pipe (|) é um cara do qual tenho um excelente conceito porque quebra altos galhos, porém deve ser usado com moderação, pois ele sempre criará um subshell o que implica a carregar um Shell filho e copiar para ele todo o ambiente do Shell pai. Tudo que for alterado ou adicionado no filho, será perdido quando o controle voltar para o Shell pai e muitas vezes o pipe (|) pode ser evitado com um redirecionamento da entrada padrão. Veja um exemplo banal:

Meu script precisa saber quantas palavras tem no arquivo telefones. Eu sei que posso contar palavras com wc -w. Então veja essa análise:

$ wc -w telefones
24 telefones

Ora não era bem o que queria, pois para ter somente a quantidade de palavras eu teria de fazer:

$ wc -w telefones | cut -f 1 -d ' '
24

Puxa lá está o pipe (|). Mas se eu passar o nome do arquivo por pipe (|), o cat não saberá de quem se trata e simplesmente listará somente o que quero. Veja:

$ cat telefones | wc -w
24

Tá melhor mas ainda tem pipe (|). Então a melhor solução é redirecionar o arquivo via entrada padrão fazendo:

$ wc -w < telefones
24

Desta forma o wc não sabia o nome do arquivo, pois seus dados vinham de StdIn e não foi necessário criar o fatídico subshell.

Experimente fazer um loop assim:

time for ((i=1; i<200; i++))
{
    PONHA CADA UM DESSES CMDs AQUI >/dev/null
}

Com isso veremos o tempo de 200 execuções de cada uma dessas linhas de comandos que mostramos, mas não se esqueça de trocar o nome do arquivo para um que você tenha (por exemplo /etc/passwd). Desviei a saída para /dev/null porque o que interessa é o tempo e não a quantidade de palavras.

Aposto o chope como o último é bem mais rápido que os outros e o segundo é o pior deles

Vou executar esse loop, mas com outros exemplos para que você entenda bem. Existem duas formas de colocar o conteúdo de um arquivo dentro de uma variável:

  1. Var=$(cat /etc/passwd)
  2. Var=$(</etc/passwd)

Vamos medir os tempos de cada um fazendo 200 loops:

Primeiro caso:

time for ((i=1; i<200; i++))
{
    Var=$(cat /etc/passwd)
}
real	0m0.262s
user	0m0.032s
sys	0m0.040s

Segundo caso:

time for ((i=1; i<200; i++))
{
    Var=$(< /etc/passwd)
}
real	0m0.149s
user	0m0.032s
sys	0m0.032s

Como vocês viram o negócio é fazer redirecionamento de entrada.

Nessa rodada de dicas sobre redirecionamento já expliquei como mandar erros para a saída de erros (StdErr) na dica de amanhã mostrarei dois macetes matadores:

  1. Como seu script recebe dados via pipe (|), Here Strings (<<<) ou Redirecionamento do StdIn (<);
  2. Como seu script pode gravar ou ler das áres de transferência


Veja a relação completa dos artigos de Julio Cezar Neves