Кратко: split - разделяем файлы

split - разделяем файлы

Давненько я тут не писал, хотя заметок накопилось немало.. и начну я пока с кратких заметок. Сегодня речь пойдет об утилите split. Данная утилита позволяет разбивать файлы на несколько частей.

Когда это может быть полезным? Ну к примеру вам может потребоваться разделить большой лог-файл для того, чтобы было удобнее анализировать его на наличие ошибок. Второй вариант - разделить большой архив (что мне и потребовалось) для того, чтобы загрузить его частями на облако, в котором есть ограничения по размеру файлов...

Ниже будет представлено несколько вариантов использования этой утилиты, и начну я с самого распространенного.

Как разделить большой архив на несколько файлов по 15gb?

Самый простой способ:

split -b 15G ./archive.tar.gz

В результате вы получите файлы, начинающиеся с префикса "x":

# ls -lah x*
-rw-r--r-- 1 root root 15G янв 16 21:56 xaa
-rw-r--r-- 1 root root 15G янв 16 21:56 xab
-rw-r--r-- 1 root root 15G янв 16 21:56 xac

А как сделать тоже самое, только с нормальным именем?

В этой ситуации достаточно добавить желаемую маску, указав ее в кавычках после выбранного файла:

split -b 15G ./archive.tar.gz "archive.tar.gz."

В результате архив будет разделен на эти файлы:

# ls -lah archive.tar.gz*
-rw-r--r-- 1 root root 15G янв 16 22:05 archive.tar.gz.aa
-rw-r--r-- 1 root root 15G янв 16 22:05 archive.tar.gz.ab
-rw-r--r-- 1 root root 15G янв 16 22:05 archive.tar.gz.ac

Как заменить эти aa ab на цифры?

Вместо "буквенного" суффикса есть и "цифровой". Чтобы им воспользоваться достаточно использовать ключ -d:

split archive.tar.gz -b 15G -d "archive.tar.gz."

Результат будет такой:

# ls -lah archive.tar.gz.*
-rw-r--r-- 1 root root 15G янв 16 22:55 archive.tar.gz.00
-rw-r--r-- 1 root root 15G янв 16 22:55 archive.tar.gz.01
-rw-r--r-- 1 root root 15G янв 16 22:55 archive.tar.gz.02
-rw-r--r-- 1 root root 15G янв 16 22:55 archive.tar.gz.03
-rw-r--r-- 1 root root 15G янв 16 22:55 archive.tar.gz.04
-rw-r--r-- 1 root root 15G янв 16 22:55 archive.tar.gz.05

Что еще можно сделать с суффиксом?

Можно увеличить его длину (по умолчанию длина суффикса - 2). Сделать это можно, например до 4, с помощью ключа "-a 4":

split -b 15M ./archive.tar.gz "archive.tar.gz." -a 4

Результат:

# ls -lah archive.tar.gz*
-rw-r--r-- 1 root root 15M янв 16 23:15 archive.tar.gz.aaaa
-rw-r--r-- 1 root root 15M янв 16 23:15 archive.tar.gz.aaab
-rw-r--r-- 1 root root 15M янв 16 23:15 archive.tar.gz.aaac
-rw-r--r-- 1 root root 15M янв 16 23:15 archive.tar.gz.aaad
-rw-r--r-- 1 root root 15M янв 16 23:15 archive.tar.gz.aaae
-rw-r--r-- 1 root root 15M янв 16 23:15 archive.tar.gz.aaaf
-rw-r--r-- 1 root root 15M янв 16 23:15 archive.tar.gz.aaag
-rw-r--r-- 1 root root 15M янв 16 23:15 archive.tar.gz.aaah
-rw-r--r-- 1 root root 15M янв 16 23:15 archive.tar.gz.aaai
-rw-r--r-- 1 root root 15M янв 16 23:15 archive.tar.gz.aaaj
-rw-r--r-- 1 root root 15M янв 16 23:15 archive.tar.gz.aaak
-rw-r--r-- 1 root root 15M янв 16 23:15 archive.tar.gz.aaal
-rw-r--r-- 1 root root 15M янв 16 23:15 archive.tar.gz.aaam
-rw-r--r-- 1 root root 15M янв 16 23:15 archive.tar.gz.aaan
-rw-r--r-- 1 root root 11M янв 16 23:15 archive.tar.gz.aaao

Еще можно использовать шестнадцатеричный суффикс, воспользовавшись ключом "-x". Но на нем я не буду останавливаться.

Как разделить архив на два файла?

Тут нам поможет ключ -n:

split archive.tar.gz archive.tar.gz_ -n2

В результате мы получим два файла, разделенные "пополам" как и хотели:

ls -lah archive.tar.gz*
-rw-r--r-- 1 root root 111M янв 16 22:20 archive.tar.gz_aa
-rw-r--r-- 1 root root 111M янв 16 22:20 archive.tar.gz_ab

А как теперь собрать все части в один архив?

Это нельзя сделать с помощью split, но можно с помощью cat. Ниже пример того, как я собрал все части в один архив и сверил размер и чексум оригинального файла и "воссозданного":

# воссоздаем архив:
cat archive.tar.gz_* > full_archive.tar.gz

# сверяем размер с оригинальным:
du -sh original.tar.gz 
221M    original.tar.gz
du -sh full_archive.tar.gz 
221M    full_archive.tar.gz

# сверяем md5sum
md5sum original.tar.gz
cc157ca6139157a8a9f816e8fbe4390b  original.tar.gz
md5sum full_archive.tar.gz
cc157ca6139157a8a9f816e8fbe4390b  full_archive.tar.gz

Как мы видим, архив "воссоздан" и готов к распаковке.

Как понять, что делает эта утилита?

На помощь приходит ключ --verbose:

# split archive.tar.gz archive.tar.gz_ -n2 --verbose
creating file 'archive.tar.gz_aa'
creating file 'archive.tar.gz_ab'
# ls -lah archive.tar.gz*
-rw-r--r-- 1 root root 111M янв 16 22:24 archive.tar.gz_aa
-rw-r--r-- 1 root root 111M янв 16 22:24 archive.tar.gz_ab

Как split работает с текстовыми файлами?

По умолчанию эта утилита делит файл создавая новый файл, который содержит 1000 строк. К примеру, у меня есть файл который содержит 11266 строк. Вот на сколько файлов/и как он будет разделен:

# split logfile.log logfile.log_
# wc -l ./logfile.log_*
  1000 ./logfile.log_aa
  1000 ./logfile.log_ab
  1000 ./logfile.log_ac
  1000 ./logfile.log_ad
  1000 ./logfile.log_ae
  1000 ./logfile.log_af
  1000 ./logfile.log_ag
  1000 ./logfile.log_ah
  1000 ./logfile.log_ai
  1000 ./logfile.log_aj
  1000 ./logfile.log_ak
   266 ./logfile.log_al
 11266 total

Как мне разделить файл на несколько файлов по 3000 строк?

Тут нам поможет ключ -l 3000:

# split logfile.log logfile.log_ -l 3000 
# wc -l ./logfile.log_*
  3000 ./logfile.log_aa
  3000 ./logfile.log_ab
  3000 ./logfile.log_ac
  2266 ./logfile.log_ad
 11266 total

Как разделить текстовый файл по 300кб не ломая структуру?

При разделении текстового файла по размеру, используя ключ -b файлы делятся на части не сохраняя структуру, из-за чего начало строки может быть в одном файле, а ее конец - в другом. Решить эту проблему можно указав ключ "-C 300KB" (указываем максимальный размер), который разделит файл на части сохраняя структуру.

split -C 300KB ./logfile.log "logfile.log_"

Результат:

# ls -lah logfile.log_*
-rw-r--r-- 1 root root 293K янв 16 23:30 logfile.log_aa
-rw-r--r-- 1 root root 293K янв 16 23:30 logfile.log_ab
-rw-r--r-- 1 root root  95K янв 16 23:30 logfile.log_ac

Как разделить файл на основе определенного контента?

В этом утилита split нам не поможет, но поможет csplit. Возможно о ней будет написана отдельная статья.

Источники, которые я использовал:

https://www.gnu.org/software/coreutils/manual/html_node/split-invocation.html
https://www.linux.com/training-tutorials/split-and-join-targz-file-linux
https://andreyex.ru/linux/komandy-linux-i-komandy-shell/9-poleznyh-primerov-komandy-split-v-linux