Trocando figurinhas sobre o terminal

You are viewing an old revision of this post, from July 24, 2018 @ 09:02:31. See below for differences between this version and the current revision.

Uma das minhas diversões nesta Copa foi montar um álbum de figurinhas. Na verdade, montei o álbum porque me filho queria muito, mas me diverti também, eu acho.

Álbum de figurinhas da Copa do Mundo de 2018, aberto na página da França, com três figurinhas faltando

Infelizmente, não completei ainda

Parte importante de colecionar figurinhas é trocar as repetidas. Através de mensagens em grupos de WhatsApp, dizemos quais repetidas temos e quais figurinhas ainda precisamos. Como programador, me recusei a ficar comparando as listas, então escrevi um programinha em Python (com doctests e tudo) para encontrar intersecções.

O laptop sumido

Semana passada vieram à minha casa para trocar figurinhas. Eu tinha as listas de repetidas e necessárias, tanto minhas quanto da outra colecionadora, mas o meu script estava em um outro laptop. Eu nem sabia onde esse laptop estava, e a visita estava com pressa.

Não daria tempo de achar o computador, ou de reescrever o programa. Ou mesmo de comparar manualmente.

Hora de usar alguns comandos Unix!

O formato das listas

As listas geralmente têm esse formato:

15, 18, 26, 31, 40, 45 (2), 49, 51, 110, 115, 128, 131 (2), 143, 151, 161, 162, 183 (2), 216 (2), 221, 223, 253, 267 (3), 269, 280, 287, 296, 313, 325, 329, 333 (2), 353 (3), 355, 357, 359, 362, 365, 366, 371, 373, 384, 399, 400, 421 (2), 445, 457, 469, 470, 498 (2), 526, 536, 553, 560, 568, 570, 585, 591 (2), 604 (2), 639 (2), 660.

Basicamente, eu precisava remover tudo que não fossem dígitos, além dos números entre parênteses, e comparar duas listas. Fácil até.

Preprocessando com sed

Primeiro, preciso remover os contadores entre parênteses:

$ cat list.txt | sed 's/([^)]*)//g'
15, 18, 26, 31, [...] 591 , 604 , 639 , 660.

(Eu sei, UUOC. Que seja.)

Depois, coloco cada número em uma linha:

$ cat list.txt | sed 's/([^)]*)//g' | sed 's/, */\n/g'

Depois, limpo cada linha de qualquer caractere que não seja um dígito:

cat list.txt | sed 's/([^)]*)//g' | sed 's/, */\n/g' | sed 's/[^0-9]*\([0-9]*\)[^0-9]*/\1/g'

(Na prática chamo sed apenas uma vez, passando duas expressões. Aqui acho que fica mais claro invocar sed várias vezes.)

Por fim, ordeno os valores:

$ cat list.txt | sed 's/([^)]*)//g' | sed 's/, */\n/g' | sed 's/[^0-9]*\([0-9]*\)[^0-9]*/\1/g' | sort -n > mine-needed.txt

Faço isso com a lista de figuras necessárias, e também com a lista de figuras repetidas, conseguindo dois arquivos.

Encontrando intersecções com grep

Agora, preciso compará-los. Há muitas opções, e eu escolhi usar grep.

No caso, chamei grep passando um dos arquivos como entrada, e o outro arquivo como uma lista de padrões para casar, através da opção -f. Além disso, apenas o matching completo das linhas importa, então usaremos a flag -x. Por fim, pedi para grep comparar strings diretamente (ao invés de considerá-las expressões regulares) com a flag -F.

$ fgrep -Fxf mine-needed.txt theirs-repeated.txt
253
269
333
470
639

Pronto! Em um minuto, já sei quais figuras quero. Basta fazer o mesmo com as minhas repetidas.

Por que isto é interessante?

Para mim, hoje, estes one-liners não são grande coisa. O interessante é que, quando comecei a usar o terminal, eles seriam incríveis. Sério, olhe quantos pipes usamos para preprocessar os arquivos! E esse truque com o grep? Eu penava só para fazer uma regex que funcionasse! Na verdade, até solucionar esse problema, eu nem conhecia a opção -x.

Certa vez ajudei um amigo meu a processar um bom número de arquivos. Ele já levava mais de duas horas tentando fazer isso com Java, e resolvemos juntos em dez minutos com shell script. Ele então me falou o quanto queria saber shell script e me perguntou como aprender.

Pois bem, pequenos exemplos como estes, por simples que sejam, me ensinaram muito. É assim que se aprende: tentando resolver problemas, conhecendo comandos e opções aos poucos. E, no final, esta é uma habilidade muito valiosa.

Então, espero que esta pequena brincadeira enriqueça seu dia, também. Certamente enriqueceu o meu – queria ter pensado nela antes de gastar tanto tempo no script Python que escrevi!

Post Revisions:

Changes:

There are no differences between the July 24, 2018 @ 09:02:31 revision and the current revision. (Maybe only post meta information was changed.)

Post a Comment

Your email is never shared. Required fields are marked *

*
*