Если я выполню следующий простой скрипт:
#!/bin/bash
printf "%-20s %s\n" "Früchte und Gemüse" "foo"
printf "%-20s %s\n" "Milchprodukte" "bar"
printf "%-20s %s\n" "12345678901234567890" "baz"
Это печатает:
Früchte und Gemüse foo
Milchprodukte bar
12345678901234567890 baz
то есть текст с умлаутами (например, ü
) сокращается на один символ за умлаут.
Конечно, у меня где-то неправильные настройки, но я не могу понять, какой это может быть.
Это происходит, если кодировка файла UTF-8.
Если я изменю его кодировку на latin-1, выравнивание будет правильным, но умлауты будут отображаться неправильно:
Fr�chte und Gem�se foo
Milchprodukte bar
12345678901234567890 baz
echo Früchte und Gemüse | wc -c -m
разницу.printf
есть.Ответы:
POSIX требует
printf
,%-20s
чтобы эти 20 считались в байтах, а не в символах, хотя это не имеет особого смысла, какprintf
печать текста в формате (см. Обсуждение в Austin Group (POSIX) иbash
списки рассылки).Это
printf
встроеноbash
и большинство других оболочек POSIX.zsh
игнорирует это глупое требование (даже вsh
эмуляции), поэтомуprintf
работает так, как вы ожидаете. То же самое дляprintf
встроенногоfish
(не POSIX-подобная оболочка).Символ
ü
(U + 00FC) при кодировании в UTF-8 состоит из двух байтов (0xc3 и 0xbc), что объясняет расхождение.Эта строка состоит из 18 символов, имеет ширину 18 столбцов (
-L
являетсяwc
расширением GNU для сообщения о ширине отображения самой широкой строки во входных данных), но кодируется в 20 байтов.В
zsh
илиfish
текст будет выровнен правильно.Теперь есть также символы, которые имеют ширину 0 (например, комбинирующие символы, такие как U + 0308, объединяющий диарез) или имеют двойную ширину, как во многих азиатских сценариях (не говоря уже о управляющих символах, таких как Tab), и даже
zsh
не будут выравниваться те правильно.Пример, в
zsh
:В
bash
:ksh93
имеет%Ls
спецификацию формата для подсчета ширины с точки зрения ширины дисплея .Это по-прежнему не работает, если текст содержит управляющие символы, такие как TAB (как это может быть?
printf
Нужно знать, как далеко друг от друга расположены табуляционные табло в устройстве вывода и с какой позиции он начинает печатать). Он работает случайно с символами возврата (как вroff
выводе, гдеX
(жирныйX
) записывается какX\bX
), хотя иksh93
считает, что все управляющие символы имеют ширину-1
.Как и другие варианты, вы можете попробовать:
Это работает с некоторыми
expand
реализациями (но не с GNU).В системах GNU вы можете использовать GNU,
awk
чейprintf
счетчик в символах (не в байтах, не в значениях ширины экрана, поэтому все еще не в порядке для символов 0 или 2 ширины, но в порядке для вашего образца):Если вывод идет на терминал, вы также можете использовать escape-последовательности позиционирования курсора. Подобно:
источник
ü
может быть составлен какu
+¨
, что составляет 3 байта. В случае вопроса он закодирован как 2 символа, но не всеü
созданы одинаково.u\u308
- это два символа (wc -m
по крайней мере, в Unix / смысле) для одного глифа / графема / графем-кластера, и он уже упоминается и включен в этот ответ.printf(3)
(мало смысла после того требования C99, о котором вы упоминаете, спасибо за это), но не дляprintf(1)
утилиты, поскольку каждый оператор оболочки или другая текстовая утилита работают с символами (или были изменены, чтобы также работать с символами например,wc
который получил-m
(пока-c
остался байт ) илиcut
получил-b
после,-c
может означать нечто иное, чем байты).На самом деле, нет, но ваш терминал не говорит по-латыни, и поэтому вы получаете мусор, а не умлаутс.
Вы можете исправить это, используя iconv:
(или просто запустите весь сценарий оболочки по иконке)
источник