¿Existe una herramienta de línea de comandos robusta para procesar archivos csv?

47

Trabajo con archivos CSV y, a veces, necesito verificar rápidamente el contenido de una fila o columna desde la línea de comandos. En muchos casos cut, head, tail, y amigos harán el trabajo; sin embargo, cortar no puede lidiar fácilmente con situaciones como

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

Aquí, la primera coma es parte del primer campo, pero cut -d, -f1no está de acuerdo. Antes de escribir una solución yo mismo, me preguntaba si alguien sabía de una buena herramienta que ya existe para este trabajo. Tendría que, como mínimo, poder manejar el ejemplo anterior y devolver una columna de un archivo con formato CSV. Otras características deseables incluyen la capacidad de seleccionar columnas en función de los nombres de columna dados en la primera fila, soporte para otros estilos de cotización y soporte para archivos separados por tabuladores.

Si no conoce dicha herramienta, pero tiene sugerencias sobre la implementación de dicho programa en Bash, Perl o Python, u otros lenguajes de script comunes, no me importaría tales sugerencias.

Steven D
fuente

Respuestas:

38

Puedes usar el csvmódulo de Python .

Un simple ejemplo:

import csv
reader = csv.reader(open("test.csv", "r"))
for row in reader:
    for col in row:
        print col
dogbane
fuente
Mi solución final fue en python ya que mi Perl estaba demasiado oxidado. Gracias.
Steven D
2
Aún mejor, usa pandas . Está diseñado explícitamente para trabajar con datos tabulares.
Josh
38

Probablemente llego un poco tarde, pero hay otra herramienta que vale la pena mencionar: csvkit

http://csvkit.readthedocs.org/

Tiene muchas herramientas de línea de comandos que pueden:

  • reformatear archivos CSV,
  • convertir ay desde CSV desde varios formatos (JSON, SQL, XLS),
  • el equivalente de cut, grep, sorty otros, pero CSV-conscientes,
  • une diferentes archivos CSV,
  • hacer consultas generales de SQL sobre datos de archivos CSV.
romaia
fuente
66
Una herramienta excelente que cumple con los criterios de la pregunta maravillosamente (en particular, no requiere saltar a un lenguaje de programación y está bien diseñada para adaptarse a otras utilidades de Unix).
mm2001
15

Suena como un trabajo 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 la documentación sobre cómo manejar los nombres de columna. El separador y el estilo de comillas se pueden ajustar con parámetros para new. Ver también Text::CSV::Separatorpara adivinar separadores.

Gilles 'SO- deja de ser malvado'
fuente
¿Hay un revestimiento en el que pueda compactar esto? Me gusta Perl, pero solo cuando puedo invocarlo directamente desde la línea de comandos en lugar de hacerlo con un script
Sridhar Sarnobat
2
@ user7000, a menos que su shell sea (t)cshese comando funcionaría bien en el indicador de su shell. Siempre puede unir esas líneas si lo desea en una sola línea. Newline es generalmente como el espacio en la sintaxis de Perl como en C.
Stéphane Chazelas
Supongo. Aunque aplastar más de 2 líneas en 1 no es lo que realmente quiero decir con un trazador de líneas. Esperaba que hubiera algo de azúcar sintáctico que lo hiciera implícitamente (por ejemplo, cómo -ecrea un bucle implícito).
Sridhar Sarnobat
10

He encontrado csvfix, una herramienta de línea de comandos que funciona bien. Sin embargo, deberá hacerlo usted mismo:

http://neilb.bitbucket.org/csvfix

Hace todas las cosas que esperaría, ordenar / seleccionar columnas, dividir / fusionar y muchas que no le gustaría generar inserciones SQL a partir de datos CSV y datos CSV diferentes.

Daniel Burke
fuente
8

Si desea usar la línea de comandos (y no crear un programa completo para hacer el trabajo), le gustaría usar filas , un proyecto en el que estoy trabajando: es una interfaz de línea de comandos para datos tabulares pero también una biblioteca de Python para usar en sus programas. Con la interfaz de línea de comandos, puede imprimir bastante cualquier dato en CSV, XLS, XLSX, HTML o cualquier otro formato tabular admitido por la biblioteca con un comando simple:

rows print myfile.csv

Si myfile.csves así:

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

Luego, las filas imprimirán el contenido de una manera hermosa, como esta:

+-------+-------------------------------+-------------+---------+
| 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

Si usted es un desarrollador de Python y ya ha pipinstalado en su máquina, simplemente ejecute dentro de un virtualenv o con sudo:

pip install rows

Si estás usando Debian:

sudo apt-get install rows

Otras características interesantes

Convertir formatos

Puede convertir entre cualquier formato compatible:

rows convert myfile.xlsx myfile.csv

Consulta

Sí, puede usar SQL en un archivo CSV:

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

También es posible convertir la salida de la consulta a un archivo en lugar de stdout utilizando el --outputparámetro

Como una biblioteca de Python

También puedes en tus programas de 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 lo disfrutes!

Álvaro Justen
fuente
6

R no es mi lenguaje de programación favorito, pero es bueno para cosas como esta. Si su archivo csv es

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

Dentro del 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

Con respecto a sus otras solicitudes, para "la capacidad de seleccionar columnas en función de los nombres de columna dados en la primera fila", vea

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

Para "soporte para otros estilos quotede citas " vea el argumento de read.csv (y funciones relacionadas). Para "soporte para archivos separados por tabulaciones", vea el separgumento de read.csv (establecido sepen '\ t').

Para más información, mire la ayuda online.

> help(read.csv)
Faheem Mitha
fuente
Estoy muy familiarizado con R, pero mi objetivo era tener algo que pudiera usar fácilmente de Bash.
Steven D
1
@Steven: R puede ejecutarse fácilmente desde la línea de comandos, de la misma manera que Python o Perl, si esa es su única preocupación. Ver Rscript(parte de la distribución base R) o el paquete de complementos littler. Puedes hacer #!/usr/bin/env Rscripto similar.
Faheem Mitha
Ah, sí. Soy bastante competente en R pero no lo he usado mucho para crear este tipo de utilidad. Tengo algo funcionando en Python, pero también puedo intentar crear algo en R.
Steven D
4

Miller es otra buena herramienta para manipular datos basados ​​en nombres, incluido CSV (con encabezados). Para extraer la primera columna de un archivo CSV, sin importar su nombre, harí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
fuente
Miller es muy impresionante. Lo compararía con awk, pero muy consciente de DSV.
Derek Mahar
3

O bien, podrías probar algo de magia awk . Sin embargo, no soy un buen usuario awk y no puedo confirmar que esto funcione correctamente, y cómo hacerlo.

rvs
fuente
99
Aquí hay un awk CSV Parser que usé hace un tiempo ... Parece bastante bien pensado ... lorance.freeshell.org/csv
Peter.O
2

pruebe "csvtool" este paquete es una práctica herramienta de línea de comandos para manejar archivos CSV

dominic
fuente
1
Ya se ha mencionado, con más detalle ...
jasonwryan
2

cissy también realizará el procesamiento csv de línea de comandos. Está escrito en C (pequeño / ligero) con paquetes rpm y deb disponibles para la mayoría de las distribuciones.

Usando el ejemplo:

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

o

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

o

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

También hay una biblioteca de Curry para leer / escribir archivos en formato CSV : CSV .

imz - Ivan Zakharyaschev
fuente
2
¿Le importaría publicar un código de muestra, como las respuestas Perl, Python y R? (Especialmente porque Curry no es un lenguaje de script Unix común).
Gilles 'SO- deja de ser malvado'
@Gilles: Sí, tienes razón, debería publicar un código de muestra para mejorar la respuesta. Voy a hacer esto dentro de un rato.
imz - Ivan Zakharyaschev
1

El github repo Structured Text Tools tiene una lista útil de herramientas de línea de comandos de Linux relevantes. En particular, la sección de valores separados del delimitador enumera varias herramientas compatibles con CSV que admiten directamente las operaciones solicitadas.

JonDeg
fuente
1

Una de las mejores herramientas es Miller ( http://johnkerl.org/miller/doc/index.html ). Es como awk, sed, cut, join y sort para datos indexados por nombre como CSV, TSV y JSON tabular.

Por ejemplo

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

te dio

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

Si quieres un TSV

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

te da (es posible eliminar el encabezado)

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

Si desea la primera y tercera columna, cambie su orden

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

te dio

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

Si desea una herramienta visual / interactiva en la terminal, recomiendo VisiData de todo corazón.

ingrese la descripción de la imagen aquí

Tiene tablas de frecuencia (mostradas arriba), pivote, fusión, diagramas de dispersión, filtrado / computación usando Python, y más.

Puede pasar archivos csv así

vd hello.csv

Hay opciones específicas csv: --csv-dialect, --csv-delimiter, --csv-quotechar, y --csv-skipinitialspacepara afinar la manipulación de archivos CSV.

DameDebugger
fuente
0

Una solución 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
fuente