Bash'de bir CSV dosyası nasıl ayrıştırılır?


112

Uzun bir Bash senaryosu üzerinde çalışıyorum. Bir CSV dosyasındaki hücreleri Bash değişkenlerine okumak istiyorum. Satırları ve ilk sütunu ayrıştırabilirim, ancak diğer sütunları ayrıştırabilirim. Şimdiye kadarki kodum:


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

Yalnızca ilk sütunu yazdırıyor. Ek bir test olarak şunları denedim:

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

Ve $ y boş. Ben de denedim:

read x y < <(echo a b)

Ve $ y b. Neden?


7
dikkatinizden kaçmış awkkullanmak $1, $2vb?
BeemerGuy

4
yan not olarak: komut <<(echo "string") ---> komut <<< "string"
tokland

1
'Kes' komut satırı programı bunun için tasarlandı: ss64.com/bash/cut.html
Jay

Yanıtlar:


215

Bunun IFSyerine kullanmanız gerekir -d:

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

Genel amaçlı CSV ayrıştırma için, Bash'in kendi başına halledemediği diğer sorunların yanı sıra, alıntılanmış alanları dahili virgüllerle işleyebilen özel bir araç kullanmanız gerektiğini unutmayın. Bu tür araçların örnekleri, cvstoolve csvkit.


7
Önerilen çözüm, çok basit CSV dosyaları için uygundur, yani, başlıklar ve değerlerde virgül ve gömülü tırnak işareti bulunmuyorsa. Aslında genel bir CSV ayrıştırıcısı yazmak oldukça zordur (özellikle birkaç CSV "standardı" olduğundan). CSV dosyalarını * nix araçlarına daha uygun hale getirmenin bir yolu, bunları TSV'ye (sekmeyle ayrılmış değerler), örneğin Excel kullanarak dönüştürmektir.
en yoğun

İlginçtir ki vücutta mkdir yapamıyorum. Alıyorum command not found. Sadece echoeserler.
Zsolt

1
@Zsolt: Durumun böyle olması için hiçbir sebep yok. Bir yazım hatası veya başıboş basılmayan bir karakteriniz olmalıdır.
sonraki duyuruya kadar duraklatıldı.

2
@DennisWilliamson Ayırıcıyı, örneğin ;while IFS=";" read col1 col2; do ...
şunları

1
@ thomas.mc.work: Bu, noktalı virgül ve kabuğa özel diğer karakterler için geçerlidir. Virgül durumunda, gerekli değildir ve gereksiz olan karakterleri çıkarmayı tercih ederim. Örneğin, genişletme için değişkenleri her zaman küme parantezi kullanarak belirtebilirsiniz (örneğin ${var}), ancak gerekli olmadığında onları ihmal ederim. Bana göre daha temiz görünüyor.
sonraki duyuruya kadar duraklatıldı.

10

Sayfadan man:

-d sınırlandırıcı Sınırın ilk karakteri satırsonu yerine giriş satırını sonlandırmak için kullanılır.

-d,Virgüldeki giriş satırını sonlandıracak olanı kullanıyorsunuz . Satırın geri kalanını okumaz. Bu yüzden $ y boş.


3

Csv dosyalarını alıntı dizeleri ile ayrıştırabilir ve say | aşağıdaki kod ile

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 dize alanlarını değişkenlere ayrıştırır ve tr alıntıyı kaldırır.

Her alan için awk çalıştırıldığı için biraz daha yavaş.


1
Güzel, koma (,) da kullanabilirsiniz
pkarc

0

CSV dosyasını bazı satırlarla okumak istiyorsanız, çözüm budur.

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"
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.