2009/03/19

CLI to rescue!

Nunca precisei fazer uma planilha. Não que eu me orgulhe disso, mas é algo que eu quase tenho como um desafio pessoal, permanecer invicto contra o Excel e sua trupe. BTW, dia destes eu precisa adicionar o número da linha atual como o primeiro campo em um arquivo CSV. Já estava quase apelando quando achei o csvtool no apt-cache do ubuntu.

Meu arquivo era mais ou menos assim:
$ cat arquivo_1.csv
1997,"Ford","E350","ac, abs, moon",3000
1999,"Chevy","Venture ""Extended Edition""",,4900
1996,"Jeep","Grand Cherokee","MUST SELL!
air, moon roof, loaded",4799
O one-liner era esse:
$ for i in $(seq 1 $(csvtool height arquivo_1.csv ))
do echo -ne "${i},$(csvtool head $i arquivo_1.csv | csvtool drop $(( $i - 1 )) -)\n"
done > arquivo_2.csv

E na saída, voilá:
$ cat arquivo_2.csv
1,1997,Ford,E350,"ac, abs, moon",3000
2,1999,Chevy,"Venture ""Extended Edition""",,4900
3,1996,Jeep,Grand Cherokee,"MUST SELL!
air, moon roof, loaded",4799
Nada mal, não? PS: menos um post antigo na lista dos rascunhos

5 comentários:

  1. Nada mal?

    Você percebeu que a última linha veio sem prefixo? Não entendi, mas acho que o csvtool head 3 arquivo_1.csv tem um comportamento esquisito.

    Percebeu que podia ter substituído o 'csvtool height' pelo 'wc -l' e os 'csvtool head' e 'csvtool drop' pelos famosos 'head' e 'tail', respectivamente?

    Viu que o loop é bastante ineficiente, pois a cada volta chama dois processos csvtool só pra imprimir uma linha específica do arquivo? Um sed Np seria mais rápido.

    Ainda assim, o sed teria que ler o arquivo a cada volta do loop. Que tal um while read line; do ...; done <arquivo_1.csv? Ele só leria o arquivo uma vez e você podia manter o número da linha numa variável da shell.

    Melhor ainda não precisar do loop. Sabia que o 'cat -n' numera as linhas? O que você acha de cat -n arquivo_1.csv | sed 's/ *\([0-9]*\)\t\(.*\)/\1,\2/'?

    Ah, mas pra que tanto esforço, não é? Vamos ape(r)lar de uma vez:

    perl -lpe '$_ = "$.,$_"' arquivo_1.csv

    :-)

    ResponderExcluir
  2. Ops, o último campo da terceira (e última linha) tinha um '\n', por isso não usar o 'cat -n ... | sed ...', 'head', 'tail' e 'wc'... Bem que eu queria, mas desta vez não deu!

    ;-)

    ResponderExcluir
  3. Putz... o que que eu posso dizer? Foi mal. Você tem razão. Eu não percebi que a entrada só tinha mesmo três linhas.

    Lendo o help do csvtool parece que não tem jeito mesmo de otimizar seu código.

    Seria legal se o 'csvtool replace' pudesse "inserir" uma nova coluna. Ou, então, se houvesse um 'csvtool row' equivalente ao 'csvtool col'.

    ResponderExcluir