Extrai (e despeja para stdout) apenas um determinado intervalo de linhas de um arquivo CSV?

2

Eu tenho um arquivo CSV de aproximadamente 1000 linhas, e onde devo importá-lo, recebo um erro na linha 700. No entanto, as entradas neste CSV contêm novas linhas (e são citadas) e, portanto, não posso realmente rapidamente use awk ou similar para mostrar o que é a linha 700.

Então eu encontrei Existe uma robusta ferramenta de linha de comando para processar arquivos csv? , e instalou ambos csvfix e csvkit ; no entanto, parece que nenhum desses aplicativos suporta simplesmente especificar um número de linha (ou um intervalo de linhas) e gerá-los. 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 que echo é o que eu preciso, assim que eu pudesse especificar qual (is) linha (s) está (m) para ser ecoada, mas quando eu olho para link , apenas são descritas colunas.

Como eu poderia usar essas ferramentas - ou outras ferramentas - para simplesmente descartar a linha 700 (ou linhas 702-705) de um CSV de 1000 linhas para stdout?

EDIT: Encontrado ( link ) que csvfix tem:

csvfix find -if '$line == 407' data.csv

... no entanto, isso é realmente o número da linha e não o número da linha; Portanto, se a linha começa na linha 406, em seguida, interrompe a linha 407 e termina em 407; então o comando acima não produzirá nada - mas se você voltar uma linha, -if '$line == 406' , a linha será descartada. Isso é útil também, mas ainda não é um número de linha ....

    
por sdbbs 27.09.2016 / 18:01

3 respostas

1

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
    
por 27.09.2016 / 18:20
1

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.

Após analisar com sucesso cada linha, ele imprimirá o deslocamento byte .

Desembalando 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 o alimentei com 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 do corrompido, haveria mais offsets de bytes impressos. Use o último.)

Então, depois do byte 18, ele encontrou um erro. Fácil o suficiente para obter um número de linha a partir disso: 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 é, a citação em torno de r2c2 não está fechada.

    
por 27.09.2016 / 18:57
1

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
    
por 19.06.2017 / 21:47