Làm cách nào để phân tích cú pháp tệp CSV trong Bash?


111

Tôi đang làm việc trên một kịch bản Bash dài. Tôi muốn đọc các ô từ tệp CSV thành các biến Bash. Tôi có thể phân tích cú pháp các dòng và cột đầu tiên, nhưng không phải bất kỳ cột nào khác. Đây là mã của tôi cho đến nay:


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

Nó chỉ in cột đầu tiên. Như một bài kiểm tra bổ sung, tôi đã thử những cách sau:

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

Và $ y trống. Vì vậy, tôi đã thử:

read x y < <(echo a b)

Và $ y là b. Tại sao?


7
có bạn xem là awksử dụng $1, $2, vv?
BeemerGuy

4
dưới dạng chú thích bên: command <<(echo "string") ---> command <<< "string"
tokland

1
Chương trình dòng lệnh 'cắt' được thiết kế cho điều đó: ss64.com/bash/cut.html
Jay

Câu trả lời:


214

Bạn cần sử dụng IFSthay vì -d:

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

Lưu ý rằng đối với phân tích cú pháp CSV cho mục đích chung, bạn nên sử dụng một công cụ chuyên dụng có thể xử lý các trường được trích dẫn bằng dấu phẩy bên trong, trong số các vấn đề khác mà Bash không thể tự xử lý. Ví dụ về các công cụ như vậy là cvstoolcsvkit.


7
Giải pháp được đề xuất phù hợp với các tệp CSV rất đơn giản, nghĩa là nếu tiêu đề và giá trị không có dấu phẩy và dấu ngoặc kép được nhúng. Thực sự khá phức tạp khi viết một trình phân tích cú pháp CSV chung chung (đặc biệt là vì có một số "tiêu chuẩn" CSV). Một cách tiếp cận để làm cho các tệp CSV dễ sử dụng hơn với các công cụ * nix là chuyển đổi chúng thành TSV (các giá trị được phân tách bằng tab), ví dụ: sử dụng Excel.
cao điểm

Điều thú vị là tôi không thể làm mkdir trong cơ thể. Tôi nhận được command not found. Chỉ các echocông trình.
Zsolt

1
@Zsolt: Không có lý do gì phải như vậy. Bạn phải có lỗi đánh máy hoặc ký tự không in được.
Tạm dừng cho đến khi có thông báo mới.

2
@DennisWilliamson Bạn nên kèm theo seperator ví dụ như khi sử dụng ;:while IFS=";" read col1 col2; do ...
thomas.mc.work

1
@ thomas.mc.work: Điều đó đúng trong trường hợp dấu chấm phẩy và các ký tự khác đặc biệt đối với shell. Trong trường hợp dấu phẩy, nó không cần thiết và tôi có xu hướng muốn bỏ qua những ký tự không cần thiết. Ví dụ: bạn luôn có thể chỉ định các biến để mở rộng bằng cách sử dụng dấu ngoặc nhọn (ví dụ ${var}), nhưng tôi bỏ qua chúng khi chúng không cần thiết. Đối với tôi, nó trông sạch sẽ hơn.
Tạm dừng cho đến khi có thông báo mới.

10

Từ mantrang:

-d delim Ký tự đầu tiên của delim được sử dụng để kết thúc dòng đầu vào, thay vì dòng mới.

Bạn đang sử dụng -d,sẽ kết thúc dòng nhập trên dấu phẩy. Nó sẽ không đọc phần còn lại của dòng. Đó là lý do tại sao $ y trống.


3

Chúng tôi có thể phân tích cú pháp các tệp csv bằng các chuỗi được trích dẫn và được phân tách bằng dấu | với mã sau

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 phân tích cú pháp các trường chuỗi thành các biến và tr xóa dấu ngoặc kép.

Chậm hơn một chút vì awk được thực thi cho mỗi trường.


1
Tốt, bạn cũng có thể sử dụng tình trạng hôn mê (,)
pkarc

0

Nếu bạn muốn đọc tệp CSV với một số dòng, thì đây là giải pháp.

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"
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.