Прокладка пробільних пробілів у рядку з іншим символом


12

Я хотів би вивести hello worldбільше 20 символів.

printf "%-20s :\n\n" 'hello world!!'

# Actual output
hello world!!        :

# Wanted output
hello world!!========:

Однак я не хочу заповнювати пробіли, а замість " = ". Як це зробити?

Відповіді:


9

Оновлена ​​відповідь для більш загального рішення. дивіться також мою іншу відповідь нижче, використовуючи лише розширення дужки оболонки та pritnf.

$ str='Hello World!'
$ sed -r ':loop; s/ (=*):$/\1=:/; t loop' <<< "$(printf '%-20s:\n' "$str" )"
Hello World!========:

Як це працює?

це (=*):$/фіксує один пробіл, один або більше, =що слідує двокрапкою :в кінці введення; ми робимо набір =як груповий матч і \1будемо його зворотним відсиланням.

З , :loopми визначили ярлик з ім'ям loopі t loopвін буде стрибати на цю мітку , коли s/ (=*):$/\1=:/зробив успішну заміну;

Заміняючи частину на \1=:, вона завжди збільшуватиме кількість =s і повертає саму кишку до кінця рядка.


1
тож вам доведеться відрегулювати прапор залежно від того, скільки слів має вхід?
користувач1686

@grawity Зараз я оновив свою відповідь на загальне рішення.
αғsnιη

20
filler='===================='
string='foo'

printf '%s\n' "$string${filler:${#string}}"

Дає

foo=================

${#string}- довжина значення $stringі ${filler:${#string}}є підрядком $fillerвід заліку ${#string}вперед.

Загальна ширина виходу буде максимальною шириною $fillerабо $string.

Рядок наповнювача може jotбути створений в системах, що мають , динамічно, використовуючи

filler=$( jot -s '' -c 16 '=' '=' )

(для 16 =у рядку). Системи GNU можуть використовувати seq:

filler=$( seq -s '=' 1 16 | tr -dc '=' )

Інші системи можуть динамічно використовувати Perl або інший більш швидкий спосіб створення рядка.


чому б не використовувати printfдля створення фільтра, який є майже у всіх системах, і розширення дужок з оболонками bash/szh?
αғsnιη

@sddgob Як би ви це зробили з printf+ розширенням дужки bash?
Кусалаланда


17
printf "%.20s:\n\n" "$str========================="

де %.20sформат обрізання рядків


2
Це ІМХО, краще рішення, ніж моє. Потрібно лише коротке пояснення рядка формату.
Кусалаланда

12

Один із способів зробити це:

printf "====================:\r%s\n\n" 'hello world!!'

6
Га! Це розумний трюк! Однак він насправді надрукує ====================\rhello world, що може бути проблемою, якщо ОП потребує збереження цього, а не просто друку на екрані.
terdon

також echo -e '=================\rHello World!!', але має те саме питання, що і @terdon вказав на це.
αғsnιη

1
@ αғsnιη Тільки за echoпідтримки -e. printfмайже завжди краще, ніж echoз багатьох причин.
Satō Katsura

5

Підхід Perl:

$ perl -le '$k="hello world!!"; while(length($k)<20){$k.="=";} print "$k\n"'
hello world!!=======

Або, краще, @SatoKatsura зазначив у коментарях:

perl -le '$k = "hello world!!"; print $k, "=" x (20-length $k), "\n"'

Якщо вам потрібно підтримати багатобайтові символи UTF, використовуйте:

PERL_UNICODE='AS' perl -le '$k = "hello world!!"; print $k, "=" x (20-length $k), "\n"'

Та сама ідея в оболонці:

v='hello world!!'; while [ ${#v} -lt 20 ]; do v="$v""="; done; printf '%s\n\n' "$v"

Вам не потрібен цикл: perl -le '$k = "hello world!!"; print $k, "=" x (20-length $k), "\n"'. Однак це (і всі інші рішення, розміщені дотепер), порушується, якщо задіяні багатобайтові символи.
Satō Katsura

@ SatōKatsura ooh, так, це акуратно! Треба було подумати про це, дякую. І так, я думав додати відмову від можливих збоїв у багатобайтових символах UTF, але вважав, що це буде зайвим ускладненням у цьому контексті.
terdon

Я думаю, perl6може бути спосіб зробити це правильно навіть із багатобайтовими символами. Але з іншого боку perl6дратує так багато способів.
Satō Katsura

@ SatōKatsura добре, для такої простої речі, її слід досить просто встановити PERL_UNICODE='AS'. Наприклад: printf '%s' nóóös | perl -nle 'print length($_)'друкує 8 ("неправильно"), а printf '%s' nóóös | PERL_UNICODE='AS' perl -nle 'print length($_)'друкує 5 ("правильно").
тердон

5

Інший спосіб - це використовувати лише printfкоманду та сгенерувати спочатку візерунок накладки символів Shell Brace Expansion(Ви можете закінчити числом ≥ область форматування, яку ви хочете надрукувати {1..end}) та отримати лише кожен перший символ, %.1sякий є =s, а потім надрукувати лише першу довжину 20 символів область цього %.20s. Це дещо кращий спосіб повторити символи / слово, а не дублювати їх.

printf '%.20s:\n' "$str$(printf '%.1s' ={1..20})"
Hello World!!=======:

Пояснення:

Зазвичай як розширення Brace , оболонка розширюється {1..20}наступним чином, якщо ми друкуємо їх.

printf '%s ' {1..20}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 

Отже, додавши до нього знак рівності ={1..20}, оболонка буде розширюватися наступним чином.

printf '%s ' ={1..20}
=1 =2 =3 =4 =5 =6 =7 =8 =9 =10 =11 =12 =13 =14 =15 =16 =17 =18 =19 =20 

І printf '%.1s'що насправді означає printf '%WIDE.LENGTH', ми друкуємо лише одну ВЕЛИКУ з вищезгаданих за замовчуванням 1 WIDE . таким чином результат буде =лише 20 разів повторюватися.

Тепер printf '%.20s:\n'ми друкуємо лише 20 довжини, $strа якщо довжина $str<20, решта займе з генерованих =s, щоб заповнити замість пробілів.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.