Extrair (e despejar no stdout) apenas um determinado intervalo de linhas de um CSV?

Extrair (e despejar no stdout) apenas um determinado intervalo de linhas de um CSV?

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 awkou 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 csvfixe 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 echoque é 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 csvfixtem:

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 findsuporta 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.csvno 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.

informação relacionada