¿Cómo analizar un archivo CSV en Bash?

111

Estoy trabajando en un largo guión de Bash. Quiero leer celdas de un archivo CSV en variables Bash. Puedo analizar líneas y la primera columna, pero no cualquier otra columna. Aquí está mi código hasta ahora:


  cat myfile.csv|while read line
  do
    read -d, col1 col2 < <(echo $line)
    echo "I got:$col1|$col2"
  done

Solo imprime la primera columna. Como prueba adicional, probé lo siguiente:

read -d, x y < <(echo a,b,)

Y $ y está vacío. Así que intenté:

read x y < <(echo a b)

Y $ y lo es b. ¿Por qué?

Usuario1
fuente
7
¿ha considerado awkutilizar $1, $2etc?
BeemerGuy
4
como nota al margen: comando <<(echo "cadena") ---> comando <<< "cadena"
tokland
1
El programa de línea de comandos 'cut' fue diseñado para eso: ss64.com/bash/cut.html
Jay

Respuestas:

214

Necesita usar en IFSlugar de -d:

while IFS=, read -r col1 col2
do
    echo "I got:$col1|$col2"
done < myfile.csv

Tenga en cuenta que para el análisis de CSV de propósito general, debe usar una herramienta especializada que pueda manejar los campos entre comillas con comas internas, entre otros problemas que Bash no puede manejar por sí mismo. Ejemplos de tales herramientas son cvstooly csvkit.

Pausado hasta nuevo aviso.
fuente
7
La solución propuesta está bien para archivos CSV muy simples, es decir, si los encabezados y valores están libres de comas y comillas incrustadas. En realidad, es bastante complicado escribir un analizador CSV genérico (especialmente porque hay varios "estándares" CSV). Un enfoque para hacer que los archivos CSV sean más compatibles con las herramientas * nix es convertirlos a TSV (valores separados por tabulaciones), por ejemplo, usando Excel.
pico
Es interesante que no pueda hacer mkdir en el cuerpo. Estoy consiguiendo command not found. Solo las echoobras.
Zsolt
1
@Zsolt: No hay razón para que ese sea el caso. Debe tener un error tipográfico o un carácter que no se imprime.
Pausado hasta nuevo aviso.
2
@DennisWilliamson Debe adjuntar el separador, por ejemplo, cuando use ;:while IFS=";" read col1 col2; do ...
thomas.mc.work
1
@ thomas.mc.work: Eso es cierto en el caso de punto y coma y otros caracteres que son especiales para el shell. En el caso de una coma, no es necesario y tiendo a preferir omitir los caracteres que son innecesarios. Por ejemplo, siempre puede especificar variables para la expansión usando llaves (p ${var}. Ej. ), Pero las omito cuando no son necesarias. Para mí, parece más limpio.
Pausado hasta nuevo aviso.
10

De la manpagina:

-d delim El primer carácter de delim se usa para terminar la línea de entrada, en lugar de nueva línea.

Está utilizando -d,que terminará la línea de entrada en la coma. No leerá el resto de la línea. Por eso $ y está vacío.

dogbane
fuente
3

Podemos analizar archivos csv con cadenas entre comillas y delimitados por say | con el siguiente código

while read -r line
do
    field1=$(echo $line | awk -F'|' '{printf "%s", $1}' | tr -d '"')
    field2=$(echo $line | awk -F'|' '{printf "%s", $2}' | tr -d '"')

    echo $field1 $field2
done < $csvFile

awk analiza los campos de cadena en variables y tr elimina la cita.

Ligeramente más lento a medida que se ejecuta awk para cada campo.

Maithilish
fuente
1
Bueno, también puedes usar coma (,)
pkarc
0

Si desea leer un archivo CSV con algunas líneas, esta es la solución.

while IFS=, read -ra line
do 
    test $i -eq 1 && ((i=i+1)) && continue
    for col_val in ${line[@]}
    do
        echo -n "$col_val|"                 
    done
    echo        
done < "$csvFile"
Eliya
fuente