Как разбить большой файл CSV на несколько маленьких файлов BASH
Иногда нужно делать парсинг тяжёлых csv документов. Можно попытаться выполнить подобную задачу средствами PHP. Но как поведёт себя скрипт, если csv - файл весит 100 Мб. Скрипт не отработает. Произойдёт ошибка. Возможно не хватит оперативной памяти сервера. В этом случае есть выход: нужно разделить один большой csv файл на несколько маленьких. Таким образом вы снизите нагрузку на сервер.
Предлагаю вам своё решение. Посмотрите на файл для парсинга. Я не стал делать его большим, но вы должны понимать, что размер файла может быть достаточно большим. Вся сложность в том, что нужно скопировать названия столбцов и несколько раз вставлять в маленькие файлы. Как только большой файл будет поделён на части, то необходимо вставить названия столбцов в самое начало маленьких файлов. Содержимое большого файла должно быть поделено на равные части и записано в маленькие файлы. В этом заключается вся трудность. Если в csv файле нет первой строки с названиями столбцов, то это не правильный по составу файл.
column1;column2;column3;column4;column5;column6;column7;column8
1text1;text1;text1;text1;text1;text1;text1;text1
2text1;text1;text1;text1;text1;text1;text1;text1
3text1;text1;text1;text1;text1;text1;text1;text1
4text1;text1;text1;text1;text1;text1;text1;text1
5text1;text1;text1;text1;text1;text1;text1;text1
6text1;text1;text1;text1;text1;text1;text1;text1
7text1;text1;text1;text1;text1;text1;text1;text1
8text1;text1;text1;text1;text1;text1;text1;text1
9text1;text1;text1;text1;text1;text1;text1;text1
10text1;text1;text1;text1;text1;text1;text1;text1
11text1;text1;text1;text1;text1;text1;text1;text1
12text1;text1;text1;text1;text1;text1;text1;text1
13text1;text1;text1;text1;text1;text1;text1;text1
Теперь рассмотрим сам скрипт sh для разделения csv файла на куски. Перед тем как запустить скрипт создайте папку parts для записи небольших файлов. Логика работы скрипта:
- Копирую файл file1.txt. Получается новый файл file2.txt без первой строки. На первой строке у нас были названия столбцов.
- Очищаю папку parts от старых файлов
- Из оригинального файла file1.txt беру названия столбцов и записываю в переменную header
- Разбиваю данные из файл file2.txt на маленькие файлы.
- Вывожу данные на экран для понимания работы скрипта
- При помощи цикла for добавляю в каждый файл названия столбцов
- При помощи цикла for меняю названия файлам file1.txt
#!/bin/bash
#Егор Астапов 2017-11-27
#копируем название столбцов + копирование файла без названия столбцов
sed '1,1d' file1.txt > file2.txt
#очистка папки от старых файлов
rm -rf parts/*
header=$(sed -n '1p;1q' file1.txt)
num_rows=$(cat file2.txt | wc -l)
num_rows=$((num_rows - 1))
num_rows_new=3
cd ./parts
#разбиваем большой csv-файл на части
split -l $num_rows_new ../file2.txt
echo "названия столбцов: "$header
echo "Количество строк (всего): "$num_rows
echo "Количество строк в новом файле: "$num_rows_new
i=1
for file in $(ls)
do
sed -i -e "1 s/^/$header\n/;" $file;
#echo "$file";
echo $i": "$file" -> file$i.txt"
#переименование файла
mv $file "file$i.txt"
i=$(($i+1))
done
#вывод:
#названия столбцов: column1;column2;column3;column4;column5;column6;column7;column8
#Количество строк (всего): 12
#Количество строк в новом файле: 3
#1: xaa -> file1.txt
#2: xab -> file2.txt
#3: xac -> file3.txt
#4: xad -> file4.txt
#5: xae -> file5.txt
Обратите внимание на переменную num_rows_new. Документ будет разбит по количеству строк согласно переменной num_rows_new. В итоге у вас будут масса файлов с одинаковым количеством строк, но последний файл будет отличаться от всех остальных. В нём будет наименьшее количество строк по остаточному принципу: 3 + 3 + 3 + 3 + 1 = 13. В последнем документе будет всего 2 строки. Одна с названиями столбцов, другая с данными. Вы можете не переименовывать файлы. В этом случае получится масса файлов с непонятными названиями: xaa, xab. Я советую вам переименовывать файлы. Так порядка больше. В итоге у вас получится несколько файлов. Я выводу содержимое всех файлов без разрывов.
cat parts/*
#вывод:
#column1;column2;column3;column4;column5;column6;column7;column8
#1text1;text1;text1;text1;text1;text1;text1;text1
#2text1;text1;text1;text1;text1;text1;text1;text1
#3text1;text1;text1;text1;text1;text1;text1;text1
#column1;column2;column3;column4;column5;column6;column7;column8
#4text1;text1;text1;text1;text1;text1;text1;text1
#5text1;text1;text1;text1;text1;text1;text1;text1
#6text1;text1;text1;text1;text1;text1;text1;text1
#column1;column2;column3;column4;column5;column6;column7;column8
#7text1;text1;text1;text1;text1;text1;text1;text1
#8text1;text1;text1;text1;text1;text1;text1;text1
#9text1;text1;text1;text1;text1;text1;text1;text1
#column1;column2;column3;column4;column5;column6;column7;column8
#10text1;text1;text1;text1;text1;text1;text1;text1
#11text1;text1;text1;text1;text1;text1;text1;text1
#12text1;text1;text1;text1;text1;text1;text1;text1
#column1;column2;column3;column4;column5;column6;column7;column8
#13text1;text1;text1;text1;text1;text1;text1;text1
Я для примера использовал файл с 13 строками (данные). Вы можете сделать большой файл на несколько мегабайт и разделить его на несколько скриптов.