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.


Substituição de Processos

Colaboração: Julio Cezar Neves

Data de Publicação: 15 de agosto de 2019

Eu quero listar todos os arquivos com os nomes começados por arq de um diretório, contando-os, então eu faço:

ls arq* | while read Arq
do
    echo $((i)) $Arq
done; echo Eu tenho :$i: arquivos

E a saída disso foi a seguinte:

1 arq
2 arq.err
3 arq.err1
4 arq.limpo
5 arq.lixo
6 arq.log
7 arq10
Eu tenho :: arquivos

Ou seja, funcionou tudo beleza, mas na hora de totalizar deu caca. Você sabe por quê? Explico: o while inteiro rodou num subshell provocado pelo pipe (|) e como você pode ver pela contagem, a variável $i foi incrementada, mas ao terminar o subshell, todo seu ambiente foi embora com ele e $i não escapou.

Como fazer então? Se fosse um arquivo que eu estivesse listando, bastaria redirecionar a entrada do loop com um < ARQUIVO logo após o done. Mas o ls não é um arquivo, é um comando, então o que fazer? É para isso que existe a substituição de processos, então você deveria fazer:

while read Arq
do
    echo $((i)) $Arq
done < <(ls); echo Eu tenho :$i: arquivos

onde o 1º menor (<) é o redirecionamento de entrada (stdin) e o <(ls) é a Substituição de Processos.

Veja isso:

cat <(ls arq*)
arq
arq.err
arq.err1
arq.limpo
arq.lixo
arq.log
arq10

Se o cat listou é porque o <(ls arq*) é um arquivo. Então vamos inverter isso para que ver que arquivo é esse:

Disso tudo que vimos até agora, podemos resumir dizendo que a Substituição de Processos é uma técnica na qual se emula a saída de um comando como vindo de um arquivo temporário do tipo FIFO ou Named Pipe e serve para uso em instruções que precisam de um arquivo como entrada.

Como um exemplo final, vejamos o comando comm, muito pouco usado, porém excelente no que se propõe. Sua sintaxe é:

 comm [OPCOES]... ARQ1 ARQ2 

e ele é usado para comparar linha a linha ARQ1 e ARQ2, desde que estejam classificados

Sem nenhuma opção ele produz uma saída com 3 colunas:

  • Coluna 1 - Linhas únicas no ARQ1
  • Coluna 2 - Linhas únicas no ARQ2
  • Coluna 3 - Linhas comuns aos 2 arquivos.

Mas as suas principais opções são:

-1 Suprime a coluna 1
-2 Suprime a coluna 2
-3 Suprime a coluna 3

Uma vez entendido o comando, voltemos à Substituição de Parâmetros: o problema era excluir todos os arquivos que não tivessem uma determinada palavra. Veja o one-liner solução:

 $ rm -i $(comm -13 <(grep -li 'PALAVRA' *) <(ls)) 

Nesta linha o comando rm -i removerá interativamente a saída do comando:

 comm -13 <(grep -li 'PALAVRA' *) <(ls) 

Que nada mais é que a instrução comm comparando 2 arquivos do tipo Named Pipe:

<(grep -li 'PALAVRA' *) Que devolve o nome (-l) de todos os arquivos que contêm PALAVRA e
<(ls) O nome de todos os arquivos.

Com a opção -13, são suprimidas as colunas 1 e 3, sobrando unicamente a coluna 2 que é referente às linhas únicas do arquivo 2, isto é, aqueles nos quais não foi encontrado PALAVRA.

Espero que este artigo tenha sido útil para entender o funcionamento da Substituição de Processos e, de quebra, os macetes do utilíssimo comando comm.

Adicionar comentário

* Campos obrigatórios
5000
Powered by Commentics

Comentários

Nenhum comentário ainda. Seja o primeiro!


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