วิธีแยกวิเคราะห์ไฟล์ CSV ใน Bash


112

ฉันกำลังทำงานกับสคริปต์ Bash แบบยาว ฉันต้องการอ่านเซลล์จากไฟล์ CSV เป็นตัวแปร Bash ฉันสามารถแยกวิเคราะห์บรรทัดและคอลัมน์แรก แต่ไม่สามารถแยกวิเคราะห์คอลัมน์อื่นได้ นี่คือรหัสของฉันจนถึงตอนนี้:


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

เป็นการพิมพ์คอลัมน์แรกเท่านั้น ในการทดสอบเพิ่มเติมฉันได้ลองทำสิ่งต่อไปนี้:

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

และ $ y ว่างเปล่า ฉันจึงลอง:

read x y < <(echo a b)

และ $ Y bคือ ทำไม?


7
มีคุณพิจารณาawkที่จะใช้$1, $2etc?
BeemerGuy

4
เป็น sidenote: command <<(echo "string") ---> command <<< "string"
tokland

1
โปรแกรมบรรทัดคำสั่ง 'ตัด' ได้รับการออกแบบมาสำหรับ: ss64.com/bash/cut.html
Jay

คำตอบ:


216

คุณต้องใช้IFSแทน-d:

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

โปรดทราบว่าสำหรับวัตถุประสงค์ทั่วไปในการแยกวิเคราะห์ CSV คุณควรใช้เครื่องมือพิเศษที่สามารถจัดการช่องที่ยกมาด้วยเครื่องหมายจุลภาคภายในท่ามกลางปัญหาอื่น ๆ ที่ Bash ไม่สามารถจัดการได้ด้วยตัวเอง ตัวอย่างของเครื่องมือดังกล่าวและcvstoolcsvkit


7
โซลูชันที่นำเสนอนั้นใช้ได้ดีสำหรับไฟล์ CSV ที่เรียบง่ายนั่นคือหากส่วนหัวและค่าไม่มีเครื่องหมายจุลภาคและเครื่องหมายคำพูดที่ฝังอยู่ จริงๆแล้วการเขียนโปรแกรมแยกวิเคราะห์ CSV ทั่วไปนั้นค่อนข้างยุ่งยาก (โดยเฉพาะอย่างยิ่งเนื่องจากมี "มาตรฐาน" CSV หลายตัว) แนวทางหนึ่งในการทำให้ไฟล์ CSV สามารถตอบสนองต่อเครื่องมือ * nix ได้มากขึ้นคือการแปลงเป็น TSV (ค่าที่คั่นด้วยแท็บ) เช่นการใช้ Excel
สูงสุด

เป็นเรื่องที่น่าสนใจที่ฉันไม่สามารถทำ mkdir ในร่างกายได้ command not foundฉันได้รับ เฉพาะechoผลงาน
Zsolt

1
@ Zsolt: ไม่มีเหตุผลที่ควรเป็นเช่นนั้น คุณต้องพิมพ์ผิดหรือมีอักขระที่ไม่พิมพ์ผิด
หยุดชั่วคราวจนกว่าจะมีประกาศอีกครั้ง

2
@DennisWilliamson คุณควรใส่เครื่องหมายแยกเช่นเมื่อใช้;:while IFS=";" read col1 col2; do ...
thomas.mc.work

1
@ thomas.mc.work: นั่นเป็นความจริงในกรณีของอัฒภาคและอักขระอื่น ๆ ที่พิเศษสำหรับเชลล์ ในกรณีของเครื่องหมายจุลภาคไม่จำเป็นและฉันมักจะชอบที่จะละอักขระที่ไม่จำเป็นออกไป ตัวอย่างเช่นคุณสามารถระบุตัวแปรสำหรับการขยายได้โดยใช้วงเล็บปีกกา (เช่น${var}) แต่ฉันจะละเว้นเมื่อไม่จำเป็น สำหรับฉันมันดูสะอาดกว่า
หยุดชั่วคราวจนกว่าจะมีประกาศอีกครั้ง

10

จากmanหน้า:

-d คั่นอักขระตัวแรกของตัวคั่นถูกใช้เพื่อยุติบรรทัดอินพุตแทนที่จะขึ้นบรรทัดใหม่

คุณกำลังใช้-d,ซึ่งจะยุติบรรทัดอินพุตบนคอมมา มันจะไม่อ่านส่วนที่เหลือของบรรทัด นั่นเป็นเหตุผลที่ $ y ว่างเปล่า


3

เราสามารถแยกวิเคราะห์ไฟล์ csv ด้วยสตริงที่ยกมาและคั่นด้วยคำพูด | ด้วยรหัสต่อไปนี้

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 แยกวิเคราะห์ฟิลด์สตริงเป็นตัวแปรและ tr ลบเครื่องหมายคำพูด

ช้าลงเล็กน้อยเมื่อดำเนินการ awk สำหรับแต่ละฟิลด์


1
ดีคุณยังสามารถใช้โคม่า (,)
pkarc

0

หากคุณต้องการอ่านไฟล์ CSV ด้วยบางบรรทัดดังนั้นนี่คือวิธีแก้ปัญหา

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"
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.