Чужая душа потёмки, особенно если повернуться к ней задом (Авессалом Подводный).

csplit: лучший способ разделения файла в Linux на основе его содержимого

1 Звезда2 Звезды3 Звезды4 Звезды5 Звезд (1 оценок, среднее: 5,00 из 5)
Загрузка...
23 августа 2018
csplit - лучший способ разделения файла в Linux на основе его содержимого

Просмотров: 31

Когда дело доходит до разделения текстового файла на несколько файлов в Linux, большинство людей используют команду split. В команде split нет ничего плохого, за исключением того, что он использует размер байта или размер строки для разделения файлов.

Это не удобно в ситуациях, когда вам нужно разделить файлы на основе его содержимого, а не на основе размера. Позвольте привести пример.

Мы управляем своими запланированными твитами, используя файлы YAML. Типичный файл твитов содержит несколько твитов, разделенных четырьмя тире:

 

При импорте их в свою систему нам нужно написать каждый твит в свой собственный файл. Мы делаем это, чтобы не регистрировать повторяющиеся твиты.

Но как разбить файл на несколько частей на основе его содержимого? Вероятно, вы можете получить что-то убедительное, используя команду awk :

 

Однако, несмотря на относительную простоту, такое решение не очень надежное: например, мы не правильно закрыли различные выходные файлы, поэтому это может очень сильно превысить ограничение на открытые файлы. Или что, если мы забыли разделитель перед самым первым твитом файла? Конечно, все, что можно обработать и зафиксировать в сценарии AWK, за счет усложнения его работы. Но зачем беспокоиться об этом, когда у нас есть инструмент csplit для выполнения этой задачи?

Использование csplit для разделения файлов в Linux

csplit - лучший способ разделения файла в Linux на основе его содержимого

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

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

Так, например, если мы хотим разбить файл твита на основе разделителя ----, то могли бы написать:

 

Возможно, вы догадались, что инструмент csplit использовал регулярное выражение, предоставленное в командной строке, для идентификации разделителя. И каковы могут быть результаты 0и 10983 отображаемые на стандартном выходе? Ну, это размер в байтах каждого созданного фрагмента данных.

 

Подожди минуту! Откуда берутся те имена файлов xx00и xx01 ? И зачем csplit разбивать файл на две части ? И почему первый кусок данных имеет длину ноль байтов ?

Ответ на первый вопрос прост: xxNN(или более формально xx%02d) является стандартным форматом имени файла, используемым csplit. Но вы можете изменить это, используя параметры --suffix-format и --prefix. Например, мы могли бы изменить формат на что-то более значимое для наших нужд:

 

Префикс является обычной строкой, но суффикс является строкой формата, как та, которая используется в стандартной библиотеке C функцией printf. Большинство символов формата будут использоваться дословно, за исключением спецификаций преобразования, которые вводятся знаком процента (%) и заканчивается спецификатором преобразования (здесь d). Между ними формат может также содержать различные флаги и опции. В нашем примере %03d спецификация преобразования означает:

  • отобразить номер фрагмента как десятичное целое (d),
  • в поле ширины трех символов (3),
  • в конце с левой стороны с нулями (0).

Но это не касается других запросов, которые у нас были выше: так почему у нас есть только два куска, один из которых содержит нулевые байты? Возможно, вы уже нашли ответ на этот последний вопрос самостоятельно: наш файл данных начинается с ---- самой первой строки. Таким образом, csplit он считается разделителем, и поскольку перед этой строкой не было данных, он создал пустой первый кусок. Мы можем отключить создание файлов с нулевыми байтами с помощью опции --elide-empty-files:

 

Ок: больше нет пустых файлов. Но в некотором смысле это результат худший, так как csplit разделяет файл всего на один кусок. Мы едва можем назвать это «разделение» файла, не так ли?

Объяснение этого удивительного результата csplit вовсе не предполагает, что каждый файл должен быть разделен на основе того же разделителя. Фактически, csplit требуется предоставить каждый используемый разделитель. Даже если это несколько раз то же самое:

 

Мы поместили три (одинаковых) разделителя в командной строке. Итак, csplit определил конец первого фрагмента на основе первого разделителя. Это приводит к тому, что фрагмент длины с нулевым байтом будет удален. Второй фрагмент был разделен следующим совпадением строк./----/. Превращение в кусок на 170 байт. Наконец, третий фрагмент длиной 250 байтов был идентифицирован на основе третьего разделителя. Остальные данные, 10426 байт, были помещены в последний кусок.

 

Очевидно, что это было бы нецелесообразно, если бы нам пришлось предоставить столько разделителей в командной строке, сколько в файле данных кусков. Тем более, что это точное число обычно заранее неизвестно. К счастью, csplit имеет специальный шаблон, означающий «повторить предыдущий шаблон как можно больше раз». Несмотря на свой синтаксис, напоминающий звездный квантификатор в регулярном выражении, это ближе к концепции Kleene plus, поскольку он используется для повторения разделителя, который уже встречался один раз:

 

И на этот раз, наконец, мы разделили свою коллекцию на отдельные части. Однако есть ли в csplip какие-то другие «специальные» шаблоны? Ну, мы не знаем, можем ли мы назвать их «особенными».

Больше шаблонов csplit

Мы только что видели в предыдущем разделе, как использовать квантор ‘{*}’ для несвязанных повторений. Однако, заменив звезду на число, вы можете запросить точное количество повторений:

 

Это приводит к интересному угловому случаю. Что будет добавлено, если количество повторений превысит количество фактических разделителей в файле данных? Давайте посмотрим на примере:

 

Интересно, что csplit не только сообщила об ошибке, но и удалила все файлы chunk, созданные во время процесса. Обратите особое внимание на нашу формулировку: она удалила их. Это означает, что файлы были созданы, а затем, csplit столкнувшись с ошибкой, удалила их. Другими словами, если у вас уже есть файл, имя которого выглядит как файл chunk, он будет удален:

 

В приведенном выше примере файл tweet.002.yaml, который мы создали вручную, был перезаписан, а затем удален csplit.

Вы можете изменить это поведение с помощью опции --keep-files. Как следует из названия, оно не будет удалять куски csplit, созданные после обнаружения ошибки:

 

Обратите внимание, что в этом случае, несмотря на ошибку, csplit не отбрасывает данные:

 

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

Пропуск данных в csplit

При использовании символа процента ( %) в качестве разделителя регулярных выражений вместо косой черты ( /csplit будет пропускаться данные до (но не включая) первой строки, соответствующей регулярному выражению. Это может быть полезно при игнорировании некоторых записей, особенно в начале или в конце входного файла:

 

 

 

Использование смещений при расщеплении файлов с помощью csplit

При использовании регулярных выражений ( /…​/ или %…​%) вы можете указать положительное (+N) или отрицательное (-N) смещение в конце шаблона, так чтобы csplit разделил файл на N строк после или до соответствующей строки. Помните, что во всех случаях шаблон указывает конец фрагмента:

 

Разделить по номеру строки

Мы уже видели, как мы можем использовать регулярное выражение для разделения файлов. В этом случае csplit разделит файл в первой строке, соответствующей этому регулярному выражению. Но вы также можете определить разделительную линию по номеру строки, как мы ее увидим сейчас.

Прежде чем переключиться на YAML, мы использовали для хранения запланированных твитов в плоском файле.

В этом файле твит был сделан из двух строк. Один из них содержит необязательное повторение, а второй содержит текст твита, причем новые строки заменены на \n. Еще раз, что образец файла доступен в Интернете.

С этим форматом «фиксированного размера» тоже можно было использовать, csplit чтобы поместить каждый отдельный твит в свой собственный файл:

 

Приведенный выше пример кажется легко понятным, но здесь есть две подводные камни. Во- первых, 2 дано в качестве аргумента csplit является строка номер, не линия подсчета. Однако при использовании повторения, как мы сделали, после первого совпадения csplit будет использовать это число в качестве счетчика строк. Если это не ясно, мы позволим вам сравнить выходные данные трех следующих команд:

 

 

 

Мы упомянули о второй ловушке, несколько связанной с первой. Возможно, вы заметили пустую строку в самой верхней части файла tweets.txt? Это приводит к тому фрагменту tweet.000.txt, который содержит только символ новой строки. К сожалению, это требовалось в этом примере из-за повторения: помните, что мне нужны две строки. Таким образом, 2 это обязательное условие перед повторением. Но это также означает, что первый фрагмент будет разбит, но не включает в себя вторую строку. Другими словами, первый фрагмент содержит одну строку. Все остальные будут содержать 2 строки. Возможно, вы могли бы поделиться своим мнением в разделе комментариев, но, по моему мнению, это был неудачный выбор дизайна.

Вы можете уменьшить эту проблему, перейдя непосредственно к первой непустой строке:

 

Чтение из stdin

Конечно, как и большинство инструментов командной строки, csplit можно считывать входные данные со своего стандартного ввода. В этом случае вы должны указать - в качестве входного имени файла:

 

И это все, что мы хотели показать вам сегодня. Надеюсь, в будущем вы будете использовать csplit для разделения файлов в Linux. Если вам понравилась эта статья и не забывайте делиться ею в своей любимой социальной сети!

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.

Если статья понравилась, то поделитесь ей в социальных сетях:

Добавить комментарий

Войти с помощью: 

Ваш e-mail не будет опубликован. Обязательные поля помечены *

ПОИГРАЙ, РАССЛАБЬСЯ

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам:

Заполните форму и наш менеджер перезвонит Вам в самое ближайшее время!

badge
Обратный звонок 1
Отправить
galka

Спасибо! Ваша заявка принята

close
galka

Спасибо! Ваша заявка принята

close