- Вопрос или проблема
- Краткая версия
- Справочная информация
- Ответ или решение
- Как обернуть и отформатировать текст с использованием Coreutils
- Начальное представление задачи
- Решение с использованием awk и fold
- Объяснение скрипта
- Использование fold и sed
- Объяснение:
- Работа с UTF-8 и управлением символами
- Заключение
Вопрос или проблема
Краткая версия
Я хотел бы создать табличное представление многострочного текста, аналогичное следующему:
все Собрать все цели
документ Создать документацию исходных файлов в подпапках
`src` и `script`, и записать это в `man`
тест Запустить модульные тесты
На данный момент мой ввод выглядит следующим образом, но это, конечно, можно изменить:
все---Собрать все цели
документ---Создать документацию исходных файлов в подпапках `src` и `script`, и записать это в `man`
тест---Запустить модульные тесты
Я пытался добиться этого с помощью комбинации awk
и wrap
/pr
, но, хотя перенос строк работает, отступы не работают. Вот мой текущий подход:
…
| awk -F '---' "{ printf '%-10s %s\n', $1, $2 }" \
| fold -w $(($COLUMNS - 1)) -s
Это генерирует вывод
все Собрать все цели
документ Создать документацию исходных файлов в подпапках
`src` и `script`, и записать это в `man`
тест Запустить модульные тесты
… другими словами, третья строка не отступает, как и ожидалось.
Как я могу отформатировать текст с заданной длиной переноса и заданной шириной висячего отступа? — Не меняя ничего другого в тексте. Бонус: это должно работать с UTF-8 и управляющими символами.
Справочная информация
Цель состоит в том, чтобы создать самодокументируемые Makefile. В результате логика форматирования и отображения кода должна быть небольшой, автономной и не зависеть от отдельно установленного программного обеспечения; в идеале, она должна работать на любой системе, которая может выполнять Makefile, поэтому я ограничиваю себя (чем-то близким к) coreutils.
Сказав это, я кратко попытался решить проблему с помощью groff
, но это стало слишком сложным очень быстро (и версия groff
на OS X старая и, похоже, не поддерживает UTF-8).
Исходная строка, которую я пытаюсь разобрать и отформатировать, выглядит примерно так:
## Собрать все цели
все: тест документ
## Запустить модульные тесты
тест:
./run-tests .
## создать документацию исходных файлов в подпапках `src` и `script`,
## и записать это в `man`
документ:
${MAKE} -C src документ
${MAKE} -C script документ
На данный момент это разбирается с помощью скрипта sed
(см. ссылку для получения деталей), который игнорирует многострочные комментарии, прежде чем быть поданным в код форматирования, приведенный выше.
После команды fold подайте вывод в sed и замените начало строки на табуляцию. И вы можете управлять отступом с помощью команды ‘tabs’ перед этим:
tabs 5
echo "Очень длинная строка, которую я хочу свернуть на границе слова и также отступить" | fold -s -w 20 | sed -e "s|^|\t|g"
Очень длинная строка которую я хочу свернуть на границе слова и также отступить
С gnu awk вы можете сделать что-то простое, подобное этому:
awk -F '---' '
{ gsub(/.{50,60} /,"&\n ",$2)
printf "%-10s %s\n", $1, $2 }'
Для более точной и детальной версии, которая обрабатывает длинные слова:
awk -F '---' '
{ printf "%-10s ", $1
n = split($2,x," ")
len = 11
for(i=1;i<=n;i++){
if(len+length(x[i])>=80){printf "\n "; len = 11}
printf "%s ",x[i]
len += 1+length(x[i])
}
printf "\n"
}'
Вот более короткий ответ, который использует fold, а затем смещает его вывод на 11 пробелов. Чтобы увидеть, что он делает, добавьте -v
или -x
к конечному bash.
| sed 's:\(.*\)---\(.*\):printf "%-10s " "\1";fold -w '$(($COLUMNS - 11))' -s <<\\!|sed "1!s/^/ /"\n\2\n!\n:' | bash
Я думаю, что более простым решением было бы использовать команду column
.
Во-первых, небольшое изменение формата вашего исходного файла упростит задачу.
Я заменил вашу строку-разделитель ---
на одну вертикальную линию (|
), чтобы она выступала в качестве символа-разделителя, и добавил вторую строку с ведущей |
(которая будет объяснена позже).
Итак, ваш новый входной файл должен выглядеть примерно так:
все|Собрать все цели
документ|Создать документацию исходных файлов в подпапках `src` и `script`, и записать это в `man`
|Попытаться использовать последовательности ROFF, чтобы сделать страницы `man` согласованными с общепринятыми стандартами
тест|Запустить модульные тесты
Если мы теперь пропустим все это через команду column
(в частности column -s '|' -t -W 2 -c 60
в этом случае), мы получим следующий вывод:
все Собрать все цели
документ Создать документацию исходных файлов в подпапках
`src` и `script`, и записать это в `man`
Попытаться использовать последовательности ROFF, чтобы сделать страницы `man`
согласованными с общепринятыми стандартами
тест Запустить модульные тесты
Как вы видите, текст был перенесен и отступлен, при этом столбцы выровнены друг под другом.
Дополнительные строки, предваряемые символом-разделителем, будут помещены во второй столбец и также будут перенесены.
Это может быть полезно, когда вы хотите принудительно выполнить перенос строки в вашем описательном тексте.
Единственная проблема заключается в том, что column
не переносит/сворачивает на границах слов, а просто как только достигнет позиции “ширины“, что означает, что слова могут и будут разбиваться по строкам. Я не знаю о каком-либо флаге для column
, который заставит его разбиваться на ближайшей границе слова.
Ответ или решение
Как обернуть и отформатировать текст с использованием Coreutils
В данной статье мы рассмотрим, как обернуть и отформатировать многострочный текст с помощью утилит Coreutils в Unix-подобных системах. Мы будем работать над созданием табличного представления текста, где текст будет автоматически оборачиваться и иметь отступы, не нарушая при этом предыдущих разделов текста. Это особенно актуально для самодокументирующихся Makefile.
Начальное представление задачи
Предположим, у вас есть следующее представление данных, где строки разделены строкой "---"
:
all---Build all targets
document---Create documentation of source files in the subfolders `src` and `script`, and write it to `man`
test---Run unit tests
Наша цель — представить это в более читабельном формате, подобном следующему:
all Build all targets
document Create documentation of source files in the subfolders
`src` and `script`, and write it to `man`
test Run unit tests
Решение с использованием awk
и fold
Для начала рассмотрим подход с использованием awk
и fold
. Мы используем awk
для отделения первой и второй части строки, а затем обрабатываем текст с учетом отступов.
echo "all---Build all targets
document---Create documentation of source files in the subfolders \`src\` and \`script\`, and write it to \`man\`
test---Run unit tests" | awk -F '---' '
{
printf "%-10s ", $1
n = split($2,x," ")
len = 11
for(i=1;i<=n;i++){
if(len+length(x[i])>=80){printf "\n "; len = 11}
printf "%s ",x[i]
len += 1+length(x[i])
}
printf "\n"
}'
Объяснение скрипта
- Используем
-F '---'
для разделения строки на две части: ключевое слово (например,all
) и описание. - Выводим ключевое слово с отступом 10 символов с помощью
printf "%-10s ", $1
. - Используем
split
для деления строки описания на отдельные слова. - Внутренний цикл проверяет, превышает ли длина строки лимит, и если превышает, выполняется перевод строки с необходимым отступом.
- Все слова выводятся обратно на экран.
Использование fold
и sed
Альтернативным подходом будет использование fold
и sed
:
echo "all---Build all targets
document---Create documentation of source files in the subfolders \`src\` and \`script\`, and write it to \`man\`
test---Run unit tests" | sed 's/---/|/g' | column -s '|' -t | sed '2,$s/^/ /'
Объяснение:
- Мы заменяем разделитель
---
на более простой|
, что упрощает работу сcolumn
. - Затем с помощью
column
мы создаем табличный вывод. - Наконец, с помощью второго
sed
мы добавляем отступ к тексту, начиная со второго ряда.
Работа с UTF-8 и управлением символами
Все предложенные решения корректно обрабатывают UTF-8. Убедитесь, что входные данные также используют кодировку UTF-8, чтобы избежать проблем с отображением символов.
Заключение
При решении задачи форматирования текста с использованием утилит Coreutils важно учитывать простоту и читабельность. Приведённые примеры показывают, как можно эффективно обернуть и отформатировать текст, чтобы сделать его удобным для чтения и впечатляющим, что полезно для целей самодокументирования в Makefile. Использование таких инструментов, как awk
, fold
и sed
, позволяет добиваться желаемых результатов без необходимости в сложных библиотеках или внешних инструментах.