Existe uma ferramenta de linha de comando robusta para o processamento de arquivos CSV?

47

Trabalho com arquivos CSV e, às vezes, preciso verificar rapidamente o conteúdo de uma linha ou coluna na linha de comando. Em muitos casos cut, head, tail, e amigos vão fazer o trabalho; no entanto, o corte não pode lidar facilmente com situações como

"this, is the first entry", this is the second, 34.5

Aqui, a primeira vírgula faz parte do primeiro campo, mas cut -d, -f1discorda. Antes de escrever uma solução, eu me perguntava se alguém sabia de uma boa ferramenta que já existe para esse trabalho. Teria que, no mínimo, conseguir manipular o exemplo acima e retornar uma coluna de um arquivo formatado em CSV. Outros recursos desejáveis ​​incluem a capacidade de selecionar colunas com base nos nomes de coluna fornecidos na primeira linha, suporte para outros estilos de cotação e suporte para arquivos separados por tabulação.

Se você não conhece essa ferramenta, mas tem sugestões sobre a implementação de um programa no Bash, Perl ou Python ou outras linguagens de script comuns, não me importo com essas sugestões.

Steven D
fonte

Respostas:

38

Você pode usar o csvmódulo do Python .

Um exemplo simples:

import csv
reader = csv.reader(open("test.csv", "r"))
for row in reader:
    for col in row:
        print col
dogbane
fonte
Minha solução final foi em python, pois meu Perl estava muito enferrujado. Obrigado.
Steven D
2
Melhor ainda, use Pandas . Ele foi projetado explicitamente para trabalhar com dados tabulares.
21714 Josh
38

Provavelmente estou um pouco atrasado, mas há outra ferramenta que vale a pena mencionar: csvkit

http://csvkit.readthedocs.org/

Possui muitas ferramentas de linha de comando que podem:

  • reformatação de arquivos CSV,
  • converter de e para CSV de vários formatos (JSON, SQL, XLS),
  • o equivalente a cut, grep, sorte outros, mas CSV-aware,
  • juntar diferentes arquivos CSV,
  • faça consultas gerais de SQL sobre dados de arquivos CSV.
Roma
fonte
6
Uma excelente ferramenta que atende maravilhosamente aos critérios de pergunta (em particular, não requer pular para uma linguagem de programação e é bem criada para se encaixar em outros utilitários Unix).
precisa saber é o seguinte
15

Parece um trabalho para Perl Text::CSV.

perl -MText::CSV -pe '
    BEGIN {$csv = Text::CSV->new();}
    $csv->parse($_) or die;
    @fields = $csv->fields();
    print @fields[1,3];
'

Consulte a documentação para saber como lidar com nomes de colunas. O separador e o estilo de citação podem ser ajustados com os parâmetros para new. Veja também Text::CSV::Separatorpara adivinhação do separador.

Gilles 'SO- parar de ser mau'
fonte
Existe um liner no qual você pode compactar isso. I como perl, mas só quando eu posso chamá-lo directamente a partir da linha de comando em vez de com um script
Sridhar Sarnobat
2
@ user7000, a menos que o seu shell seja (t)cshesse comando funcionaria bem no prompt do seu shell. Você sempre pode unir essas linhas se desejar em uma linha. nova linha é geralmente apenas como espaço na sintaxe Perl como em C.
Stéphane Chazelas
Eu acho. Embora esmagar mais de 2 linhas em 1 não seja o que eu realmente quero dizer com uma linha. Eu esperava que houvesse algum açúcar sintático que o fizesse implicitamente (como a forma como -ecria um loop implícito).
Sridhar Sarnobat
10

Eu encontrei o csvfix, uma ferramenta de linha de comando faz o trabalho bem. Você precisará fazer você mesmo, no entanto:

http://neilb.bitbucket.org/csvfix

Ele faz tudo o que você esperaria, ordenar / selecionar colunas, dividir / mesclar e muitos que você não gostaria de gerar inserções SQL a partir de dados CSV e diferenciar dados CSV.

Daniel Burke
fonte
8

Se você deseja usar a linha de comando (e não criar um programa inteiro para fazer o trabalho), gostaria de usar linhas , um projeto no qual estou trabalhando: é uma interface de linha de comando para dados tabulares, mas também uma biblioteca Python para usar em seus programas. Com a interface da linha de comandos, você pode imprimir praticamente qualquer dado em CSV, XLS, XLSX, HTML ou qualquer outro formato de tabela suportado pela biblioteca com um comando simples:

rows print myfile.csv

Se myfile.csvé assim:

state,city,inhabitants,area
RJ,Angra dos Reis,169511,825.09
RJ,Aperibé,10213,94.64
RJ,Araruama,112008,638.02
RJ,Areal,11423,110.92
RJ,Armação dos Búzios,27560,70.28

Em seguida, as linhas imprimirão o conteúdo de uma maneira bonita, assim:

+-------+-------------------------------+-------------+---------+
| state |              city             | inhabitants |   area  |
+-------+-------------------------------+-------------+---------+
|    RJ |                Angra dos Reis |      169511 |  825.09 |
|    RJ |                       Aperibé |       10213 |   94.64 |
|    RJ |                      Araruama |      112008 |  638.02 |
|    RJ |                         Areal |       11423 |  110.92 |
|    RJ |            Armação dos Búzios |       27560 |   70.28 |
+-------+-------------------------------+-------------+---------+

Instalando

Se você é um desenvolvedor Python e já tem pipinstalado em sua máquina, basta executar dentro de um virtualenv ou com sudo:

pip install rows

Se você estiver usando o Debian:

sudo apt-get install rows

Outros recursos interessantes

Convertendo Formatos

Você pode converter entre qualquer formato suportado:

rows convert myfile.xlsx myfile.csv

Consulta

Sim, você pode usar o SQL em um arquivo CSV:

$ rows query 'SELECT city, area FROM table1 WHERE inhabitants > 100000' myfile.csv
+----------------+--------+
|      city      |  area  |
+----------------+--------+
| Angra dos Reis | 825.09 |
|       Araruama | 638.02 |
+----------------+--------+

Também é possível converter a saída da consulta em um arquivo em vez de stdout usando o --outputparâmetro

Como uma biblioteca Python

Você também pode nos seus programas Python:

import rows
table = rows.import_from_csv('myfile.csv')
rows.export_to_txt(table, 'myfile.txt')
# `myfile.txt` will have same content as `rows print` output

Espero que goste!

Álvaro Justen
fonte
6

R não é minha linguagem de programação favorita, mas é boa para coisas assim. Se o seu arquivo csv for

***********
foo.csv
***********
 col1, col2, col3
"this, is the first entry", this is the second, 34.5
'some more', "messed up", stuff

Dentro do tipo de intérprete R

> x=read.csv("foo.csv", header=FALSE)

> x
                     col1                col2   col3
1 this, is the first entry  this is the second   34.5
2              'some more'           messed up  stuff
> x[1]  # first col
                      col1
1 this, is the first entry
2              'some more'
> x[1,] # first row
                      col1                col2  col3
1 this, is the first entry  this is the second  34.5

Em relação aos seus outros pedidos, para "a capacidade de selecionar colunas com base nos nomes de coluna fornecidos na primeira linha", consulte

> x["col1"]
                      col1
1 this, is the first entry
2              'some more'

Para "suporte a outros estilos de citação", consulte o quoteargumento read.csv (e funções relacionadas). Para "suporte a arquivos separados por tabulação", consulte o separgumento read.csv (definido sepcomo '\ t').

Para mais informações, consulte a ajuda online.

> help(read.csv)
Faheem Mitha
fonte
Eu estou muito familiarizado com o R, mas meu objetivo era ter algo que eu pudesse usar facilmente do Bash.
61111 Steven D
1
@Steven: R pode ser facilmente executado a partir da linha de comando, da mesma maneira que Python ou Perl, se essa for sua única preocupação. Veja Rscript(parte da distribuição R básica) ou o pacote adicional littler. Você pode fazer #!/usr/bin/env Rscriptou similar.
Faheem Mitha
Ah sim. Sou bastante proficiente em R, mas não o usei muito para criar esse tipo de utilitário. Eu tenho algo trabalhando em Python, mas também posso tentar criar algo em R.
Steven D
4

Miller é outra ferramenta interessante para manipular dados baseados em nomes, incluindo CSV (com cabeçalhos). Para extrair a primeira coluna de um arquivo CSV, sem se preocupar com o nome, faça algo como

printf '"first,column",second,third\n1,2,3\n' |
  mlr --csv --implicit-csv-header --headerless-csv-output cut -f 1
Stephen Kitt
fonte
Miller é muito impressionante. Eu compararia com awk, mas altamente compatível com DSV.
Derek Mahar
3

Ou você pode tentar um pouco de mágica awk . No entanto, não sou um bom usuário do awk e não posso confirmar se isso funcionaria corretamente e como fazê-lo.

rvs
fonte
9
Aqui é um awk CSV Parser eu usei um tempo atrás .. parece bastante bem pensado ... lorance.freeshell.org/csv
Peter.O
2

tente "csvtool" este pacote, é uma ferramenta útil de linha de comando para lidar com arquivos CSV

dominic
fonte
1
Já mencionado, com mais detalhes ...
jasonwryan 03/09
2

cissy também fará o processamento de linha de comando csv. Está escrito em C (pequeno / leve) com pacotes rpm e deb disponíveis para a maioria das distribuições.

Usando o exemplo:

echo '"this, is the first entry", this is the second, 34.5' | cissy -c 1
"this, is the first entry"

ou

echo '"this, is the first entry", this is the second, 34.5' | cissy -c 2
 this is the second

ou

echo '"this, is the first entry", this is the second, 34.5' | cissy -c 2-
 this is the second, 34.5
slass100
fonte
1

Há também uma biblioteca Curry para leitura / gravação de arquivos no formato CSV : CSV .

imz - Ivan Zakharyaschev
fonte
2
Você se importaria de publicar algum código de exemplo, como as respostas Perl, Python e R? (Especialmente desde Curry não é uma linguagem de script comum unix.)
Gilles 'SO parada sendo maus'
@ Gilles: Sim, você está certo, devo postar um código de exemplo para melhorar a resposta. Eu vou fazer isso daqui a pouco.
IMZ - Ivan Zakharyaschev
1

Uma das melhores ferramentas é Miller ( http://johnkerl.org/miller/doc/index.html ). É como awk, sed, recortar, ingressar e classificar para dados indexados por nome, como CSV, TSV e JSON tabular.

Exemplo

echo '"this, is the first entry", this is the second, 34.5' | \
mlr --icsv --implicit-csv-header cat

da-te

1=this, is the first entry,2= this is the second,3= 34.5

Se você quer um TSV

echo '"this, is the first entry", this is the second, 34.5' | \
mlr --c2t --implicit-csv-header cat

dá a você (é possível remover o cabeçalho)

1       2       3
this, is the first entry         this is the second      34.5

Se você deseja a primeira e a terceira coluna, altere sua ordem

echo '"this, is the first entry", this is the second, 34.5' | \
mlr --csv --implicit-csv-header --headerless-csv-output cut -o -f 3,1

da-te

 34.5,"this, is the first entry"
aborruso
fonte
1

Se você deseja uma ferramenta visual / interativa no terminal, recomendo sinceramente o VisiData.

insira a descrição da imagem aqui

Possui tabelas de frequência (mostradas acima), pivô, fusão, gráficos de dispersão, filtragem / computação usando Python e muito mais.

Você pode passar arquivos csv assim

vd hello.csv

Há opções específicas CSV: --csv-dialect, --csv-delimiter, --csv-quotechar, e --csv-skipinitialspacepara aperfeiçoá-lo manipulação de arquivos CSV.

DameDebugger
fonte
0

Uma solução awk

awk -vq='"' '
func csv2del(n) {
  for(i=n; i<=c; i++)
    {if(i%2 == 1) gsub(/,/, OFS, a[i])
    else a[i] = (q a[i] q)
    out = (out) ? out a[i] : a[i]}
  return out}
{c=split($0, a, q); out=X;
  if(a[1]) $0=csv2del(1)
  else $0=csv2del(2)}1' OFS='|' file
Srini
fonte