Як розібрати файл CSV у Bash?


112

Я працюю над довгим сценарієм Баша. Я хочу прочитати клітинки з файлу 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)

І $ у є b. Чому?


7
Ви розглянули awkвикористання $1, $2і т.д.?
BeemerGuy

4
як sidenote: команда <<(echo "string") ---> команда <<< "string"
tokland

1
Програма командного рядка 'cut' була розроблена для цього: ss64.com/bash/cut.html
Jay

Відповіді:


215

Вам потрібно використовувати IFSзамість -d:

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

Зауважте, що для загального аналізу CSV вам слід використовувати спеціалізований інструмент, який може обробляти цитовані поля внутрішніми комами, серед інших питань, з якими Bash не може впоратися сам. Прикладами таких інструментів є cvstoolі csvkit.


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. робота

1
@ thomas.mc.work: Це правда у випадку з крапками з комою та іншими символами, особливими для оболонки. У випадку з комою це не обов’язково, і я, як правило, вважаю за краще опускати непотрібні символи. Наприклад, ви завжди можете вказати змінні для розширення за допомогою фігурних дужок (наприклад ${var}), але я опускаю їх, коли вони не потрібні. Мені це виглядає чистіше.
Призупинено до подальшого повідомлення.

10

Зі manсторінки:

-d delim Перший символ delim використовується для припинення введення рядка, а не нового рядка.

Ви використовуєте, -d,який припинить рядок введення на кому. Він не буде читати решту рядка. Тому $ y порожній.


3

Ми можемо розібрати файли csv із цитованими рядками та розмежуватись через say | із наступним кодом

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
Добре, ви також можете використовувати coma (,)
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"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.