No bash eu tenho que pedir cada linha do primeiro arquivo csv, segundo arquivo csv e as respostas colocadas no terceiro arquivo csv [fechado]

1

No bash eu tenho que pedir cada linha do primeiro arquivo csv, segundo arquivo csv e as respostas colocadas no terceiro arquivo csv ...

primeiro arquivo. por exemplo. aaa.csv :

aaa
bbb
aaa
aaa
ccc
fff
aaa

segundo arquivo, por ex. bbb.csv :

aaa;111
bbb;222
ccc;333
ddd;444
eee;555
ggg;666

terceiro arquivo, por exemplo ccc.csv :

aaa;111
bbb;222
aaa;111
aaa;111
ccc;333
fff;
aaa;111

Isso é possível? Neste lugar vazio pode ser palavra FALSA ou algo assim. Quando eu uso o cat bbb.csv | grep -f aaa.csv > ccc.csv então pegue a resposta com parte do comum a aaa.csv ... só uma vez aia com o 111.

    
por dadu 06.05.2015 / 15:27

4 respostas

4

Outra abordagem possível, como nos comentários, poderia estar usando awk com a ordem alterada de arquivos:

awk -F';' 'FNR == NR { m[$1] = $2; next; } { if ($1 in m) { print $1 ";" m[$1]; } else { print $1 ";FALSE"; } }' bbb aaa

Primeiro, lemos os valores de armazenamento da biblioteca bbb no array com valores de chaves da primeira coluna, do que lemos o arquivo aaa e verificamos se a chave existe no array e imprimimos de acordo. Resultado:

aaa;111
bbb;222
aaa;111
aaa;111
ccc;333
fff;FALSE
aaa;111
    
por 06.05.2015 / 16:18
3

Você pode fazer algo assim:

while read linea
do
grep "$linea" bbb.csv >> ccc.csv || echo "$linea:FALSE" >> ccc.csv
done < aaa.csv

$ cat ccc.csv 
aaa;111 
bbb;222 
aaa;111 
aaa;111 
ccc;333 
fff:FALSE
aaa;111
    
por 06.05.2015 / 15:59
1

Que tal um meta-sed:

sed "$(sed 's^\(.*\);\(.*\)^s//;/;tx^;$as/.*/&;FALSE/\n:x' bbb.csv)" aaa.csv

A expressão sed interna transforma bbb.csv em um programa sed como este:

s/aaa/aaa;111/;tx
s/bbb/bbb;222/;tx
s/ccc/ccc;333/;tx
s/ddd/ddd;444/;tx
s/eee/eee;555/;tx
s/ggg/ggg;666/;tx
s/.*/&;FALSE/
:x

Isso é interpretado pelo sed externo para transformar aaa.csv na saída necessária:

aaa;111
bbb;222
aaa;111
aaa;111
ccc;333
fff;FALSE
aaa;111

Observe o tx no programa sed gerado. Estes são saltos condicionais sed para o rótulo x: se a substituição s anterior corresponder. Isso permite que uma declaração pega-tudo seja inserida por último para substituir o texto "FALSE".

A ressalva com essa resposta é que ela não será dimensionada para grandes arquivos bbb.csv , já que todo o programa gerado é transmitido na linha de comando. Se isso for uma preocupação, o programa gerado pode ser colocado em um arquivo temporário:

sed 's^\(.*\);\(.*\)^s//;/;tx^;$as/.*/&;FALSE/\n:x' bbb.csv > bbb.tmp.sed
sed -f bbb.tmp.sed aaa.csv > ccc.csv

Isso ainda será limitado se bbb.tmp.sed for muito grande - acho que sed tentará ler o arquivo inteiro na memória.

    
por 06.05.2015 / 19:27
0

Eu recomendo strongmente escrever este script específico em Python ao invés de qualquer ferramenta shell, simplesmente porque a biblioteca padrão do Python inclui um analisador CSV que realmente manipula todas as rugas malucas na sintaxe CSV. Você faria algo assim:

import csv
import sys

# sys.argv[1] = "aaa.csv", sys.argv[2] = "bbb.csv"
# sys.argv[3] = default value for mapping
# output written to stdout

with open(sys.argv[2], "rt") as f:
    rd = csv.reader(f, dialect="unix", delimiter=";")
    mapping = { row[0] : row[1] for row in rd }

with open(sys.argv[1], "rt") as f:
    rd = csv.reader(f, dialect="unix", delimiter=";")
    wr = csv.writer(sys.stdout, dialect="unix", delimiter=";",
                    quoting=csv.QUOTE_MINIMAL)

    for row in rd:
        wr.writerow([row[0], mapping.get(row[0], sys.argv[3])])

e depois executá-lo como, por exemplo, python munge.py aaa.csv bbb.csv "" > ccc.csv .

Em geral, se não for óbvio como fazer algo em um shell script, considere não fazê-lo em um shell script . A menos que portabilidade para instalações arbitrariamente encrostadas seja mais importante do que qualquer outra coisa (por exemplo, nas entranhas de uma macro do Autoconf) você será mais feliz escrevendo Perl, Python, Ruby, node.js, etc.

    
por 06.05.2015 / 19:50