Filtre um arquivo .CSV com base nos valores da 5ª coluna de um arquivo e imprima esses registros em um novo arquivo

16

Eu tenho um arquivo .CSV com o formato abaixo:

"column 1","column 2","column 3","column 4","column 5","column 6","column 7","column 8","column 9","column 10
"12310","42324564756","a simple string with a , comma","string with or, without commas","string 1","USD","12","70%","08/01/2013",""
"23455","12312255564","string, with, multiple, commas","string with or, without commas","string 2","USD","433","70%","07/15/2013",""
"23525","74535243123","string , with commas, and - hypens and: semicolans","string with or, without commas","string 1","CAND","744","70%","05/06/2013",""
"46476","15467534544","lengthy string, with commas, multiple: colans","string with or, without commas","string 2","CAND","388","70%","09/21/2013",""

A quinta coluna do arquivo possui diferentes cadeias de caracteres. Preciso filtrar o arquivo com base no valor da 5ª coluna. Digamos, preciso de um novo arquivo do arquivo atual que tenha registros apenas com o valor "string 1" em seu quinto campo.

Para isso, tentei o comando abaixo,

awk -F"," ' { if toupper($5) == "STRING 1") PRINT }' file1.csv > file2.csv

mas estava lançando um erro da seguinte maneira:

awk: { if toupper($5) == "STRING 1") PRINT }
awk: ^ syntax error
awk: { if toupper($5) == "STRING 1") PRINT }
awk: ^ syntax error

Eu então usei o seguinte, o que me dá uma saída ímpar.

awk -F"," '$5="string 1" {print}' file1.csv > file2.csv

Resultado:

"column 1" "column 2" "column 3" "column 4" string 1 "column 6" "column 7" "column 8" "column 9" "column 10
"12310" "42324564756" "a simple string with a comma" string 1 without commas" "string 1" "USD" "12" "70%" "08/01/2013" ""
"23455" "12312255564" "string with string 1 commas" "string with or without commas" "string 2" "USD" "433" "70%" "07/15/2013" ""
"23525" "74535243123" "string with commas string 1 "string with or without commas" "string 1" "CAND" "744" "70%" "05/06/2013" ""
"46476" "15467534544" "lengthy string with commas string 1 "string with or without commas" "string 2" "CAND" "388" "70%" "09/21/2013" ""

PS: usei o comando toupper para estar do lado seguro, pois não tenho certeza se a string estará em letras minúsculas ou maiúsculas. Preciso saber o que há de errado com meu código e se o espaço na sequência é importante ao procurar um padrão usando o AWK.

Dhruuv
fonte

Respostas:

17
awk -F '","'  'BEGIN {OFS=","} { if (toupper($5) == "STRING 1")  print }' file1.csv > file2.csv 

Resultado

"12310","42324564756","a simple string with a , comma","string with or, without commas","string 1","USD","12","70%","08/01/2013",""
"23525","74535243123","string , with commas, and - hypens and: semicolans","string with or, without commas","string 1","CAND","744","70%","05/06/2013",""

Eu acho que é isso que você quer.

limovala
fonte
A saída é exatamente como eu precisava. Eu não pensei de fazer '","'como delimitador, caso contrário, teria resolvido meu problema ... ótima solução ...
Dhruuv
@Dhruuv fazer '","'o delimitador é o que mais respostas à sua pergunta anterior sugeriu :).
terdon
@terdon: sim, eu sei, mas isso não me ocorreu quando eu estava tendo o problema. Francamente, eu pensei que poderia ser algo com o comando ou algo diferente do que os delimitadores que estava causando o problema ... :) Por isso não experimentá-lo ... :(
Dhruuv
2
@ Druuv não tem certeza dos detalhes, já que não sei dizer o que você está tentando fazer, mas sua outra condição está quase certamente errada. Você está tentando imprimir apenas se $ 5 for HYPERION? Se sim, tente else{if(toupper($5)=="HYPERION"){print}}. No momento, não no meu computador, por isso posso estar com a sintaxe errada, mas você não pode dar uma condição a uma declaração else.
terdon
11
awk -F '","' 'BEGIN {OFS=","} { if (NR==1) {print} else{if (toupper($5) == "STRING 1") print} }' file1
limovala
2

O problema com o CSV é que não há padrão. Se você precisar lidar com dados formatados em CSV com frequência, convém procurar um método mais robusto, em vez de apenas usá-lo ","como seu separador de campos. Nesse caso, os Text::CSVmódulos CPAN do Perl são excepcionalmente adequados para o trabalho:

$ perl -mText::CSV_XS -WlanE '
    BEGIN {our $csv = Text::CSV_XS->new;} 
    $csv->parse($_); 
    my @fields = $csv->fields(); 
    print if $fields[4] =~ /string 1/i;
' file1.csv
"12310","42324564756","a simple string with a , comma","string with or, without commas","string 1","USD","12","70%","08/01/2013",""
"23525","74535243123","string , with commas, and - hypens and: semicolans","string with or, without commas","string 1","CAND","744","70%","05/06/2013",""

fonte
-1
awk 'BEGIN {FS = "," }'  '{ (if toupper($5)  == "STRING 1") print; }'  file1.csv > file2.csv
PersianGulf
fonte
Desculpe dizer, mas, sua solução does not devolver todos os registros do arquivo ... Eu acho que apenas adicionando o delimitador como '","'vai fazer ... obrigado ... :)
Dhruuv
@Mohsen -1 porque 1) você precisa escapar do "ou eles não são entendidos como partes do delimitador de arquivo. Veja as respostas para a outra pergunta do OP e 2) você está separando o bloco BEGIN do resto do comando, que completamente Tente awk 'BEGIN {FS = "," }' '{print $0}', você verá que não produz saída No futuro, teste suas respostas para verificar se elas realmente funcionam antes de publicá-las.
terdon