← На главную

INDEXER.SED v1.2 прекращает работу с писком, если в данных пропал `;`

23.07.2026 04:25 · hackernews

Эрик Пемент, работавший с книжной вёрсткой, поделился способом собирать предметный указатель с помощью sed. Исходные данные выглядели как список «термин; номер страницы», причём страницы шли в порядке обработки глав. Сначала файл сортировали утилитой GNU sort с ключами -t";" +0f -1 +1n, чтобы строки сгруппировались по алфавиту без учёта регистра, а номера страниц выстроились в числовом порядке.

Затем требовалось склеить строки с одинаковым термином в одну, заменив точку с запятой на запятую, а номера страниц перечислить через запятую. Пемент написал sed-скрипт INDEXER.SED v1.0. Его логика: в цикле на каждой итерации командой N подтягивается следующая строка, и если она начинается с того же названия, что и предыдущая, то перевод строки и дублирующийся термин удаляются, а номер страницы добавляется к первой строке через запятую. Команда t loop зацикливает склеивание, пока встречаются повторы. Когда название меняется, оставшаяся точка с запятой заменяется на запятую, и первая строка выводится на печать.

Скрипт отлично работал на идеально отформатированных данных. Но если в любой строке пропадала точка с запятой, ломалась обработка всего остального файла — все последующие строки просто выводились без склейки. Причина крылась в команде s/;/,/ внутри основного тела: при попадании «плохой» строки (без ;) на первую позицию в буфере, а следующей — «хорошей» — на вторую, замена удаляла точку с запятой именно из второй строки. После этого механизм склейки переставал узнавать повторы, и скрипт портил весь вывод.

Пемент предложил два исправления. Первое — добавить в начало скрипта жёсткую проверку входных данных: если строка не содержит ;, вывести сообщение об ошибке, указать номер строки командой = и завершить работу через q. Для звукового оповещения в сообщение вставляется настоящий символ Ctrl-G, заставляющий компьютер пищать. Также проверяется наличие двух точек с запятой подряд — это тоже ломает результат. Второй путь — усложнить регулярку в s/;/,/, чтобы она срабатывала только на первой половине буфера, и продолжать обработку, пропуская битые строки. Автор предпочёл первый вариант, останавливающий скрипт при любой ошибке, и привёл итоговый INDEXER.SED v1.2 с соответствующей защитой.

Читать оригинал →