Eu tenho um arquivo CSV de aproximadamente 1.000 linhas e, para onde devo importá-lo, recebo um erro na linha 700. No entanto, as entradas neste CSV contêm novas linhas (e estão entre aspas) e, portanto, não posso usá-lo rapidamente awk
ou similar para mostrar o que é a linha 700.
Então eu encontreiExiste uma ferramenta robusta de linha de comando para processar arquivos CSV?, e instalou ambos csvfix
e csvkit
; no entanto, parece que nenhum desses aplicativos suporta simplesmente a especificação de um número de linha (ou um intervalo de linhas) e sua saída. Por exemplo:
$ csvfix help echo
echo input CSV data to output
usage: csvfix echo [flags] [file ...]
where flags are:
-ibl ignore blank input lines
-sep s specify CSV field separator character
-rsep s as for -sep but retain separator on output
-osep s specifies output separator
-hdr s write the string s out as a header record
-ifn ignore field name record
-smq use smart quotes on output
-sqf fields specify fields that must be quoted
-o file write output to file rather than standard output
-skip t if test t is true, do not process or output record
Eu teria pensado echo
que é o que preciso, assim que pude especificar quais linhas devem ser ecoadas, mas quando olho parahttp://neilb.bitbucket.org/csvfix/manual/csvfix16/csvfix.html?unique.html, apenas colunas são descritas.
Como eu poderia usar essas ferramentas - ou outras ferramentas - para simplesmente despejar, digamos, a linha 700 (ou as linhas 702-705) de um CSV de 1.000 linhas para o stdout?
EDITAR: Encontrado (http://neilb.bitbucket.org/csvfix/manual/csvfix16/ExpressionLanguage.html) isso csvfix
tem:
csvfix find -if '$line == 407' data.csv
... no entanto, este é realmente o número da linha e não o número da linha; portanto, se a linha começar na linha 406, quebrará na linha 407 e terminará na linha 407; então o comando acima não produzirá nada - mas se você voltar uma linha, -if '$line == 406'
a linha será descartada. Isso também é útil, mas ainda não é um número de linha....
Responder1
O comando csvfix find
suporta o despejo de uma linha por intervalo ou número. O comando a seguir extrairia as linhas 3 e 4 de um arquivo chamado file.csv.
csvfix find -if '$line >= 3 && $line < 5' file.csv
Responder2
Você pode remover temporariamente todas as novas linhas citadas para poder usar ferramentas de texto normais e adicionar novamente as novas linhas.
Por exemplo, no caso de aspas duplas:
gawk -v RS='"' 'NR % 2 == 0 { gsub(/\n/, "%NEWLINE%") } { printf("%s%s", $0, RT) }' file.csv > tmp.csv
head -n 700 tmp.csv | sed 's/%NEWLINE%/\n/g' > file_1-700.csv
Responder3
Você pode obter uma posição do Text::CSV_XS do perl assim:
perl -MText::CSV_XS -E 'open(my $fh, "<:encoding(utf8)", $ARGV[0]) or die "open: $!"; $csv = Text::CSV_XS->new({binary => 1, auto_diag => 9, diag_verbose => 1 } ); while (my $row = $csv->getline($fh)) { say tell $fh }' FILENAME.csv
Observe o FILENAME.csv
no final da linha.
Depois de analisar cada linha com sucesso, ele imprimirá obytedesvio.
Desempacotando o one-liner:
use Text::CSV_XS;
use feature 'say';
open(my $fh, '<:encoding(utf8)', $ARGV[0]) or die "open: $!";
$csv = 'Text::CSV_XS'->new({'binary' => 1, 'auto_diag' => 9, 'diag_verbose' => 1});
while (my $row = $csv->getline($fh)) {
say tell $fh
}
Eu alimentei esse CSS defeituoso ( new.css
):
r1c1,"r1
c2",r1c3
r2c1,"r2c2,r2c3
r3c1,r3c2,r3c3
Saída:
18
# CSV_XS ERROR: 2027 - EIQ - Quoted field not terminated @ rec 1 pos 15 field 2
(se houvesse mais linhas boas antes da corrompida, haveria mais deslocamentos de bytes impressos. Use o último.)
Então, após o byte 18, encontrou um erro. Fácil o suficiente para obter um número de linha: head -c 18 new.csv | wc -l
, que diz 2 (o número de linhas boas). Portanto, o erro está na linha 3 – e de fato está, a cotação em torno de r2c2 não está fechada.