Вопрос или проблема
В моем постоянном стремлении разумно подвести файлы .po под контроль версий git, я написал этот скрипт для использования в diff и filter-clean:
msgcat --no-location --no-wrap --sort-output - | msgattrib --no-obsolete - | grep -Ev '^"POT-Creation-Date|^"PO-Revision-Date|^"Last-Translator|^"X-Generator'
Каждый из шагов выполняет одну важную функцию:
- Рефакторинг и не относящиеся к делу изменения кода бесконечно меняют местоположение исходного кода и порядок записи. Этот вызов msgcat нормализует их, так что файлы commit-tet не содержат этих изменений.
- Устаревшие записи удваивают размер наборов изменений каждый раз, когда изменяется msgid. У нас есть контроль версий -> этот вызов msgattrib удаляет их.
- Эти поля в записи метаданных файла .po изменяются каждый раз, когда кто-то редактирует его с помощью специализированного инструмента – у нас есть контроль версий -> этот вызов grep удаляет их.
Теперь возникло еще одно препятствие. Обратите внимание на --no-wrap
спереди? Это не работает.
Более того, обертка нестабильна: в каждую нечетную фиксацию кто-то получает слово, перевернутое между строками без человеческих изменений.
Кроме того, связанный инструмент Poedit тоже имеет настройку “Wrap at”, отключение которой тоже не работает. (Потому что он делегирует это инструментам gettext, в этом нет сюрпризов. Но это означает, что у меня нет способа нормализовать файлы “только в этот раз” и покончить с этим. – Поэтому я использую git filter в первую очередь.)
Очень хорошо, я подумал и протестировал этот вызов для их удаления: sed -z -e 's/\"\n\"//'
.
Это для объединения любых обернутых строк в ‘msgid’ и ‘msgstr’, таким образом инструменты могут оборачивать их, как хотят, каждый день по-разному, мне все равно.
- Это работает отдельно:
sed -z -e 's/\"\n\"//' test.po
выводит ожидаемый результат. - Это работает, когда передается через cat:
cat test.po | sed -z -e 's/\"\n\"//'
выводит ожидаемый результат. - Когда добавляется в существующий скрипт, однако, шаг sed не имеет эффекта.
Похоже, что он получает ввод построчно. Я пытался поставить это перед grep без улучшения, и я не могу переместить это перед двумя другими, поскольку msgcat и msgattrib имеют свою проблему “Мне нравится, чтобы мои обертки были случайными”, которая подтолкнула ко всей этой проблеме с самого начала.
Могу ли я потоково передавать вывод grep, или более общим образом вывод на основе строкового конвейера, чтобы мой потоковый редактор мог выполнять свои задачи?
(Примечание: на этом сайте есть много ответов, которые говорят “sed не может этого сделать” – но sed специально разработан так, чтобы не заботиться о разрывax строк, так что это звучит как дезинформация. Из мануала:
Sed это редактор потока. Редактор потока используется для выполнения базовых текстовых преобразований на входном потоке (файле или входе из конвейера). […] sed работает, делая только один проход по входным данным[.]
выделение мое
Проблема, очевидно, в том, что существует более одного ввода, самой строки, которую я хочу заменить, разделенной между ними.)
Конвейеры всегда представляют собой непрерывные потоки – читатель, как правило, не может различить границы записи. (Исходная программа может решить буферизовать свой вывод и сбрасывать его построчно или блоками, но это редко различимо.)
Похоже, что у вас противоположная проблема, т.е. -z
фактически говорит ‘sed’ рассматривать весь его ввод как одну очень длинную “строку”, и по умолчанию его операция s//
заменяет только первое совпадение в этой “строке”.
Добавьте параметр /g
, чтобы изменить это:
msgattrib | grep | sed -z -e 's/\"\n\"//g'
Ответ или решение
Чтобы превратить линейные данные из пайпа в непрерывный поток, вам необходимо использовать подход, позволяющий обеспечить целостную обработку текста, который может быть разбит на несколько строк. Давайте разберёмся, как это реализовать, учитывая предоставленный контекст и ваш сценарий.
Понимание проблемы
Ваша ситуация заключается в необходимости обрабатывать .po файлы так, чтобы они были корректно нормализованы для git, с учётом того, что различные инструменты могут изменять форматирование текста. Вы сталкиваетесь с тем, что команды sed -z -e 's/\"\n\"//'
работают в изоляции, но не эффективно функционируют в цепочке команд из-за особенностей буферизации и обработки строк.
Потоковая обработка с sed
Как вы правильно заметили, sed
в режиме -z
рассматривает весь ввод как единичную строку. Однако по умолчанию замена производится только для первого найденного совпадения. Чтобы обеспечить замену для всех совпадений в этом единичном "потоке", нужно использовать флаг /g
, который указывает на необходимость глобальной замены.
Пример команды
Вот как ваша команда будет выглядеть с применением флага /g
:
msgcat --no-location --no-wrap --sort-output - | msgattrib --no-obsolete - | grep -Ev '^"POT-Creation-Date|^"PO-Revision-Date|^"Last-Translator|^"X-Generator' | sed -z -e 's/\"\n\"//g'
Объяснение этапов
- msgcat — нормализует порядок строк и убирает ненужные местоположения, чтобы изменения не сказывались на вашем git-репозитории.
- msgattrib — удаляет устаревшие записи, что позволяет сократить размер изменений при редактировании.
- grep — устраняет строки метаданных, которые не имеют отношения к содержимому переводов.
- sed — объединяет строки, которые были разделены, чтобы обеспечить непрерывный поток текста для дальнейшей обработки.
Практические рекомендации
- Убедитесь, что ваши команды правильно обрабатывают вывод. Попробуйте тестировать каждую команду по отдельности, чтобы убедиться в её работе, и затем объединяйте.
- Следите за кодировкой файлов и верными символами конца строки, которые могут влиять на результат.
Заключение
В результате последовательного применения вышеупомянутых команд вы можете успешно обрабатывать .po файлы, избегая проблем с переносом строк при трансформации текста. Этот подход не только решает вашу текущую задачу, но и создает основу для устойчивого процесса управления версиями с использованием git.
Используя описанный метод, вы сможете улучшить свою работу с .po файлами, что впоследствии повысит гибкость и стабильность вашего проекта. Будьте уверены, что дальнейшие изменения, сделанные в будущем, не повлияют на структуру ваших файлов, что является важным аспектом эффективного управления версиями.