Анализ файлов CSV в сценариях Bash в Linux
Работа с файлами CSV в сценариях Bash
Значения, разделенные запятыми, также известные как CSV, – это полуструктурированные данные, в которых в качестве разделителя слов используется запятая. Форматы файлов CSV очень популярны среди специалистов по данным, поскольку им приходится иметь дело с большим количеством файлов CSV и обрабатывать их для получения ценной информации. В этой статье мы сосредоточимся на том, как анализировать CSV-файлы в сценариях оболочки Bash в Linux.
В большей части этой статьи я буду использовать инструменты awk
и sed
для анализа CSV вместо комбинирования различных такие команды, как grep
, cut
, tr
, и т. д.
Утилита awk
упрощает передачу нескольких команд или написание цикла с логикой для получения данных. Вместо этого вы можете написать однострочный код в awk
для выполнения этой работы.
1. Подготовка CSV-файла к обработке.
Ваш CSV-файл может быть создан из базы данных, API или вы могли выполнить некоторые команды и преобразовать выходные данные в формат CSV с разделителями. В любом из случаев вам необходимо сначала проанализировать набор данных, прежде чем запускать поверх него свою логику.
Рекомендуется очистить набор данных перед его использованием. Зачем нам очищать набор данных? Могут возникнуть ситуации, когда в заголовках будут пустые значения ячеек или неправильное форматирование, дополнительные столбцы, не необходимые для обработки, и многое другое.
Я использую приведенные ниже данные в формате CSV, которые я взял из Kaggle для демонстрационных целей.
Player_Id,Player_Name,DOB,Batting_Hand,Bowling_Skill,Country
1,SC Ganguly,8-Jul-72,Left_Hand,Right-arm medium,
2,BB McCullum,27-Sep-81,Right_Hand,Right-arm medium,
3,RT Ponting,19-Dec-74,Right_Hand,Right-arm medium,
4,DJ Hussey,15-Jul-77,Right_Hand,Right-arm offbreak,Australia
5,Mohammad Hafeez,17-Oct-80,,Right-arm offbreak,Pakistan
6,R Dravid,11-Jan-73,,Right-arm offbreak,India
7,W Jaffer,16-Feb-78,,Right-arm offbreak,India
8,V Kohli,5-Nov-88,,Right-arm medium,India
9,JH Kallis,16-Oct-75,,Right-arm fast-medium,South Africa
10,CL White,18-Aug-83,Right_Hand,Legbreak googly,Australia
11,MV Boucher,3-Dec-76,Right_Hand,Right-arm medium,South Africa
12,B Akhil,7-Oct-77,Right_Hand,Right-arm medium-fast,India
13,AA Noffke,30-Apr-77,Right_Hand,Right-arm fast-medium,Australia
14,P Kumar,2-Oct-86,Right_Hand,Right-arm medium,India
15,Z Khan,7-Oct-78,Right_Hand,Left-arm fast-medium,India
1.1. Заменить пустые ячейки
В некоторых случаях файл CSV не будет содержать значений в определенных ячейках. Посмотрите на скриншот ниже, где между столбцами есть пустые ячейки.
Пример CSV-файла
Я бы всегда заменял его на «НП» или «Нет значения», чтобы не было пустых ячеек. Вы можете использовать следующий фрагмент awk
, чтобы заменить любую пустую ячейку желаемым значением. В данном случае я заменяю пустые ячейки на «Нет значения».
awk 'BEGIN{FS=",";OFS=","}
{
for(i=1;i<=NF;i++)
{
if($i == ""){
$i="No Value"
}
}
print
}' ~/Downloads/Player.csv > player_cleaned.csv
Этот фрагмент работает так: я устанавливаю в качестве разделителя полей и разделителя полей вывода значение запятой (FS=",";OFS=","
). Используя цикл for
, выполните итерацию по каждой ячейке в строке, и если ячейка окажется пустой ($i == ""
), замените ее на "No значение"
($i="Нет значения"
). Вам необходимо перенаправить изменения в новый файл.
Рекомендуется прочитать:
- Перенаправление Bash, объясненное примерами
1.2. Используйте заголовок с заглавной буквы
Файлы CSV могут иметь или не иметь заголовки. Но если есть заголовок, я бы всегда писал его с заглавной буквы для лучшей читаемости. Вы можете легко сделать это, используя awk
или sed
. Я покажу вам оба пути.
awk 'BEGIN{FS=",";OFS=","}
{
if(NR==1){
print toupper($0)
} else {
print
}
}' player.csv > player_cleaned.csv
Здесь мы проверяем, является ли строка первой строкой, используя (NR==1
) и используя функцию toupper()
, чтобы использовать ее с заглавной буквы. Тот же фрагмент можно записать в одну строку.
awk 'NR==1{ print toupper($0) }NR>1' player.csv > player_cleaned.csv
Используя awk
, вам придется снова перенаправить изменения в новый файл. Вместо этого вы можете использовать «sed
», чтобы внести изменения непосредственно в файл. Здесь \U
преобразует регистр в верхний регистр. Если вы хотите выполнить преобразование нижнего регистра, используйте \L
.
sed -i -e '1 s/(.*)/\U\1/' player_cleaned.csv
cat player_cleaned.csv
1.3. Удалить конечную запятую
В конце вашего CSV-файла может быть запятая. Чтобы очистить конечные запятые, вы можете воспользоваться приведенным ниже методом.
Я намеренно добавил запятую между строками с 7 по 11 в файле данных.
CSV-файл с запятыми в конце
Чтобы удалить все конечные запятые, выполните следующую команду sed
:
sed -i 's/,$//' ~/Documents/player_cleaned.csv
Удалить конечные запятые в файле CSV
Теперь мы закончили с чистящей частью. Возможно, вам потребуется выполнить еще несколько шагов, но это зависит от того, как структурирован ваш CSV-файл и что необходимо очистить.
2. Красивая печать CSV-файла в терминале
Если вы пытаетесь отобразить файлы CSV в терминале, есть несколько вариантов, где вы можете распечатать файл в табличном формате, что обеспечит лучшую читаемость.
2.1. Команда столбца
Первый подход — использовать команду column
. Команда столбца принимает разделитель, который имеет значение запятой, и разделитель для разделения столбца, который установлен на табуляцию в приведенной ниже команде. Вы также можете установить свои собственные разделители.
cat player_cleaned.csv | column -s, -t
column -s, -t player_cleaned.csv
Отображение CSV-файла с помощью команды столбца
2.2. Команда просмотра CSV
Csvlook — это утилита, входящая в состав пакета csvkit. Нет необходимости устанавливать разделитель, как мы это делали с командой column
.
cat player_cleaned.csv | csvlook
csvlook player_cleaned.csv
Отображение CSV-файла с помощью утилиты Csvlook
2.3. Симпатичный стол Python
Если у вас установлен модуль Python prettytable, вы можете запустить следующую однострочную команду и перенаправить CSV-файл для создания таблицы.
python -c "import sys,prettytable; print(prettytable.from_csv(sys.stdin))" < player_cleaned.csv
Вы также можете создать псевдоним для однострочника и передать имя файла в качестве аргумента.
alias ptable='python -c "import sys,prettytable; print(prettytable.from_csv(sys.stdin))"'
ptable < player_cleaned.csv
Отображение CSV-файла с помощью модуля PrettyTable
3. Получение данных из CSV-файла
3.1. Распечатать количество строк и столбцов
Чтобы получить количество столбцов в CSV-файле, выполните следующую команду. Здесь переменная NF
представляет количество полей, разделенных запятой в качестве разделителя.
awk -F, 'END{print NF}' player_cleaned.csv
6
Чтобы получить количество строк, выполните следующую команду. Здесь переменная NR
представляет текущую запись (т. е. каждая строка рассматривается как одна запись).
awk -F, 'END{print NR}' player_cleaned.csv
16
Чтобы пропустить первую строку (заголовок) и подсчитать количество строк, выполните следующую команду.
awk -F, 'END{print NR-1}' player_cleaned.csv
15
3.2. Распечатать весь файл CSV
Это довольно просто. Вы можете использовать cat
или awk
для печати всего файла CSV.
cat player_cleaned.csv
awk '{print}' player_cleaned.csv
3.3. Печатать только заголовок из файла CSV
Печать одного только заголовка даст вам хорошее представление о том, какой тип данных содержит ваш CSV-файл. Вы можете использовать команду head
или awk
, чтобы получить только заголовок.
head -n 1 player_cleaned.csv
awk 'NR==1' player_cleaned.csv
PLAYER_ID,PLAYER_NAME,DOB,BATTING HAND,BOWLING SKILL,COUNTRY
3.4. Исключить строку заголовка
Чтобы исключить строку заголовка и напечатать все остальные строки, используйте команду awk
. Переменная awk NR > 1
позволит пропустить первую строку.
awk '(NR>1)' player_cleansed.csv
Awk — исключить строку заголовка
Sed также можно использовать для исключения первой строки и печати всех остальных строк. Флаг 1d
удалит первую строку и выведет все остальные строки на стандартный вывод (терминал).
sed 1d < player_cleaned.csv
Sed – исключить строку заголовка
3.5. Печать отдельных столбцов
Мы можем использовать позицию столбца для печати всего столбца. Есть два подхода для достижения этой цели. Первый подход будет использовать awk, а второй подход будет использовать циклы. Awk будет намного проще захватить столбец.
По умолчанию Awk разбивает строку на основе разделителя и сохраняет значения в $1
, $2
, $3
и т. д. Разделитель по умолчанию для awk: пробел.
Взгляните на приведенный ниже фрагмент, где разделитель полей (FS=","
) и разделитель выходных полей (OFS=","
) установлен на запятую. Оператор печати напечатает первый столбец, второй столбец и шестой столбец.
awk 'BEGIN{FS=",";OFS=","}
{
print $1,$2,$6
}' player_cleansed.csv
Вы также можете написать приведенный выше фрагмент в одну строку.
awk 'BEGIN{FS=",";OFS=","}{print $1,$2,$6}' player_cleansed.csv
Печать определенных столбцов
Теперь второй подход — использовать циклы.
IFS=","
while read -r -a fields
do
echo ${fields[0]},${fields[1]},${fields[5]}
done < player_cleaned.csv
Позвольте мне объяснить, что именно происходит, когда вы запускаете приведенный выше фрагмент.
- Мы устанавливаем для внутреннего разделителя полей IFS значение запятой.
- Используя команду чтения, мы создаем массив с именем «поля» и перенаправляем входной файл в цикл
while
. - Для каждой итерации он будет читать построчно и сохранять строку как элементы массива в «полях», поэтому вы можете использовать позицию индекса массива для захвата отдельного столбца.
Примечание. Значение индекса начинается с 0..N.
3.6. Распечатать строку, соответствующую условию
Если вы хотите напечатать строки, соответствующие определенному условию, вы можете легко сделать это, используя awk
. Давайте рассмотрим несколько сценариев.
Чтобы напечатать все строки, соответствующие значению в столбце, выполните следующую команду. Здесь я пытаюсь напечатать все строки, соответствующие значению «Индия» в столбце 6.
awk -F , '$6 == "India"' player_cleaned.csv
Условное совпадение
Чтобы напечатать все строки, которые не соответствуют определенному значению, выполните следующую команду. Вместо оператора равенства мы используем оператор не равно.
awk -F , '$6 != "India"' player_cleaned.csv
Обратное условие
Вы также можете выполнить проверку состояния более чем одного столбца, используя логический оператор «И», логический оператор «ИЛИ». Допустим, я хочу проверить все строки, в которых страна указана как «Индия», а рука, отбивающая мяч, — «Правая рука».
Здесь $4
указывает на 4-й столбец, а $6
указывает на 6-й столбец. Символ &&
используется как логический оператор И для оценки двух условий.
awk -F , '$4 == "Right_Hand" && $6 == "India"' player_cleaned.csv
Множественная условная проверка
Если вы хотите включить заголовок вместе с результатом условной проверки, используйте следующую команду. Сначала я печатаю первую строку, используя NR==1
, затем использую логический оператор И, выполняя условную проверку, чтобы распечатать результаты.
awk 'NR==1' player_cleaned.csv && awk -F , '$4 == "Right_Hand" && $6 == "India"' player_cleaned.csv
Если вы хотите распечатать или перенаправить вывод, запустите всю команду внутри подоболочки, заключив ее в скобки.
(awk 'NR==1' player_cleaned.csv && awk -F , '$4 == "Right_Hand" && $6 == "India"' player_cleaned.csv) | column -t -s,
Условная проверка – заголовок включен
Примечание о Csvkit
До сих пор все, что мы видели в этой статье, было простым и понятным. Но если ваш CSV-файл имеет сложную структуру, его анализ с использованием описанного выше подхода становится утомительным. Существует утилита CSVKIT, которая отлично подходит для работы с CSV-файлами в bash.
Проблема с утилитой csvkit в том, что она установлена в вашем дистрибутиве по умолчанию, и вам, возможно, придется установить ее вручную. В вашей корпоративной среде это может быть невозможно, поскольку могут существовать некоторые ограничения на установку внешних пакетов. Но эта утилита достойна упоминания и о ней мы создадим отдельную подробную статью.
Заключение
В этом руководстве мы увидели, как работать с файлами CSV с помощью awk, sed. Вы также можете использовать другие утилиты, такие как Cut, Grep, Tr и т. д., чтобы получить желаемый результат, но awk и sed сделают вашу жизнь проще и упростят написание большого количества кодов. Если у вас есть какие-либо отзывы, сообщите об этом в разделе комментариев, и мы будем рады услышать их от вас.
Подобное чтение:
- Сценарии Bash: анализ аргументов в сценариях Bash с помощью getopts
- Как разобрать и красиво распечатать JSON с помощью инструментов командной строки Linux