Форматирование вывода с помощью printf: усечение или заполнение
Я хотел бы произвести следующий вывод:
> Avril Stewart 99 54
> Sally Kinghorn 170 60
> John Young 195 120
> Yutte Schim... 250 40
Как видите, имена короче 14 символов дополняются пробелами. Имена длиннее 15 символов усекаются: "Yutte Schimmelpenninck" усекается до "Yutte Schim...".
Вот то, что я пытался добиться этого (переменные $name
, $height
, а также $weight
извлекаются из файлов, и цикл запускает printf
команда на каждый файл данных):
printf '%-14s -%3s -%3s\n' "$name" "$height" "$weight"
> Avril Stewart 99 54
> Sally Kinghorn 170 60
> John Young 195 120
> Yutte Schimmelpenninck 250 40
printf
Однострочник - желаемое решение.
Какой код выдаст первый блок вывода?
3 ответа
Перед вашим printf
Команда, вы хотите проверить, если имя длиннее 14 символов, и если да, обрежьте его и замените последние три символа точками. Эта команда делает это:
(( ${#name} > 14 )) && name="${name:0:11}..."
Заменяет name
с его первыми одиннадцатью символами и дополнениями ...
,
Вы также должны исправить printf
строка формата: вместо
'%-14s -%3s -%3s\n'
должно быть
'%-14s %-3s -%-3s\n'
или вы получите такие результаты, как
Avril Stewart - 99 - 54
Возможно, это была просто опечатка, поскольку в выходных данных вашего примера не было дефисов.
В общем:
$ name='Avril Stewart'; weight=99; height=54
$ (( ${#name} > 14 )) && name="${name:0:11}..."
$ printf '%-14s %-3s %-3s\n' "$name" $weight $height
Avril Stewart 99 54
$ name='Sally Kinghorn'; weight=170; height=60
$ (( ${#name} > 14 )) && name="${name:0:11}..."
$ printf '%-14s %-3s %-3s\n' "$name" $weight $height
Sally Kinghorn 170 60
$ name='Yutte Schimmelpeninck'; weight=250; height=40
$ (( ${#name} > 14 )) && name="${name:0:11}..."
$ printf '%-14s %-3s %-3s\n' "$name" $weight $height
Yutte Schim... 250 40
Так что, если вы прочитаете это из файла, например, через запятую, вы получите цикл вроде этого:
while IFS=, read -r name weight height; do
(( ${#name} > 14 )) && name="${name:0:11}..."
printf '%-14s %-3s %-3s\n' "$name" $weight $height
done < inputFile
в результате чего
Avril Stewart 99 54
Sally Kinghorn 170 60
John Young 195 120
Yutte Schim... 250 40
Я не думаю, что это возможно в одной строке. Я экспериментировал с троичным оператором и пробовал что-то вроде
printf '%s\n' $(( ${#name} > 14 ? "${name:0:11}..." : "$name" ))
но проблема здесь в том, что он работает только для целых чисел, а строки расширяются до нуля в арифметическом контексте.
Более идиоматичный awk
версия будет
$ awk '{v=$1 FS $2}
length(v)>14{v=substr(v,1,11)"..."}
{printf "%-15s %-3d %-3d\n",v,$3,$4}' file
Avril Stewart 99 54
Sally Kinghorn 170 60
John Young 195 120
Yutte Schim... 250 40
если вы удалите -
войдите в%-3d, числа будут выровнены по правому краю, как обычно, однако это тот формат, который вы просили.
Это частичный ответ - игнорирование финального "...":
awk '{printf "%-14.14s %-3d %-3d\n",$1 FS $2,$3,$4}'
где %-14.14s
выполняет заполнение + усечение форматирования имени