Como analisar um arquivo CSV no Bash?

112

Estou trabalhando em um longo script Bash. Quero ler células de um arquivo CSV em variáveis ​​Bash. Posso analisar linhas e a primeira coluna, mas não qualquer outra coluna. Este é meu código até agora:


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

Está apenas imprimindo a primeira coluna. Como um teste adicional, tentei o seguinte:

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

E $ y está vazio. Então eu tentei:

read x y < <(echo a b)

E $ y está b. Por quê?

Usuário1
fonte
7
você já pensou em awkusar $1, $2, etc?
BeemerGuy
4
como nota secundária: comando <<(echo "string") ---> comando <<< "string"
tokland
1
O programa de linha de comando 'cut' foi projetado para isso: ss64.com/bash/cut.html
Jay

Respostas:

215

Você precisa usar em IFSvez de -d:

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

Observe que para a análise de CSV de propósito geral, você deve usar uma ferramenta especializada que pode lidar com campos citados com vírgulas internas, entre outros problemas que o Bash não pode lidar sozinho. Exemplos dessas ferramentas são cvstoole csvkit.

Pausado até novo aviso.
fonte
7
A solução proposta é adequada para arquivos CSV muito simples, ou seja, se os cabeçalhos e valores estiverem livres de vírgulas e aspas embutidas. Na verdade, é bastante complicado escrever um analisador CSV genérico (especialmente porque existem vários "padrões" de CSV). Uma abordagem para tornar os arquivos CSV mais acessíveis às ferramentas * nix é convertê-los em TSV (valores separados por tabulação), por exemplo, usando o Excel.
pico de
É interessante que não posso fazer mkdir no corpo. Estou conseguindo command not found. Apenas as echoobras.
Zsolt de
1
@Zsolt: Não há razão para que seja assim. Você deve ter um erro de digitação ou um caractere não imprimível perdido.
Pausado até novo aviso.
2
@DennisWilliamson Você deve incluir o separador, por exemplo, ao usar ;:while IFS=";" read col1 col2; do ...
thomas.mc.work
1
@ thomas.mc.work: Isso é verdade no caso de ponto e vírgula e outros caracteres que são especiais para a casca. No caso de uma vírgula, não é necessário e tendo a preferir omitir caracteres desnecessários. Por exemplo, você sempre pode especificar variáveis ​​para expansão usando chaves (por exemplo ${var}), mas eu as omito quando não forem necessárias. Para mim, parece mais limpo.
Pausado até novo aviso.
10

Da manpágina:

-d delim O primeiro caractere de delim é usado para encerrar a linha de entrada, em vez de nova linha.

Você está usando o -d,que encerrará a linha de entrada na vírgula. Não vai ler o resto da linha. É por isso que $ y está vazio.

dogbane
fonte
3

Podemos analisar arquivos csv com strings entre aspas e delimitados por say | com o seguinte 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 analisa os campos de string para variáveis ​​e tr remove a citação.

Um pouco mais lento conforme o awk é executado para cada campo.

Maithilish
fonte
1
Ótimo, você também pode usar coma (,)
pkarc
0

Se você deseja ler um arquivo CSV com algumas linhas, esta é a solução.

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
fonte