Odpowiedzi:
Zaktualizowana odpowiedź, aby być bardziej ogólnym rozwiązaniem. zobacz także moją inną odpowiedź poniżej, używając tylko rozszerzenia nawiasów klamrowych i pritnf
.
$ str='Hello World!'
$ sed -r ':loop; s/ (=*):$/\1=:/; t loop' <<< "$(printf '%-20s:\n' "$str" )"
Hello World!========:
Jak to działa?
to (=*):$/
przechwytuje jedną spację, jedną lub więcej =
, po której następuje dwukropek :
na końcu wejścia; robimy zestaw =
jako dopasowanie grupowe i \1
będzie jego odniesieniem wstecznym.
Z :loop
zdefiniowaliśmy etykietę o nazwie, loop
a wraz z t loop
nią przeskoczy do tej etykiety, gdy s/ (=*):$/\1=:/
zakończy się powodzeniem;
W części zastępującej \1=:
zawsze będzie zwiększać liczbę =
si cofać dwukropek do końca łańcucha.
filler='===================='
string='foo'
printf '%s\n' "$string${filler:${#string}}"
Daje
foo=================
${#string}
jest długością wartości $string
i ${filler:${#string}}
stanowi podciąg $filler
od przesunięcia w ${#string}
górę.
Całkowita szerokość wyniku będzie równa maksymalnej szerokości $filler
lub $string
.
Łańcuch wypełniający może być w systemach, które jot
zostały utworzone dynamicznie przy użyciu
filler=$( jot -s '' -c 16 '=' '=' )
(za 16 =
w linii). Systemy GNU mogą wykorzystywać seq
:
filler=$( seq -s '=' 1 16 | tr -dc '=' )
Inne systemy mogą używać Perla lub innego szybszego sposobu dynamicznego tworzenia łańcucha.
printf
do wygenerowania filtra, który jest prawie dostępny we wszystkich systemach i rozszerzenia nawiasów klamrowych jak bash/szh
?
printf
rozszerzeniem nawiasów klamrowych w bash
?
printf "%.20s:\n\n" "$str========================="
gdzie %.20s
jest format obcinania łańcucha
Jednym ze sposobów na to:
printf "====================:\r%s\n\n" 'hello world!!'
====================\rhello world
, co może być problemem, jeśli OP musi to zapisać, a nie tylko wydrukować na ekranie.
echo -e '=================\rHello World!!'
, ale ma ten sam problem, co @terdon.
echo
obsługuje -e
. printf
jest prawie zawsze lepszy niż echo
z wielu powodów.
Podejście Perla:
$ perl -le '$k="hello world!!"; while(length($k)<20){$k.="=";} print "$k\n"'
hello world!!=======
Lub, lepiej, @SatoKatsura wskazał w komentarzach:
perl -le '$k = "hello world!!"; print $k, "=" x (20-length $k), "\n"'
Jeśli chcesz obsługiwać znaki wielobajtowe UTF, użyj:
PERL_UNICODE='AS' perl -le '$k = "hello world!!"; print $k, "=" x (20-length $k), "\n"'
Ten sam pomysł w powłoce:
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"'
. Jednak to (i wszystkie inne dotychczas opublikowane rozwiązania) psuje się, jeśli w grę wchodzą znaki wielobajtowe.
perl6
może to zrobić poprawnie, nawet przy znakach wielobajtowych. Ale z drugiej strony perl6
jest denerwujące na wiele sposobów.
PERL_UNICODE='AS'
. Na przykład: printf '%s' nóóös | perl -nle 'print length($_)'
drukuje 8 („źle”), a printf '%s' nóóös | PERL_UNICODE='AS' perl -nle 'print length($_)'
drukuje 5 („poprawnie”).
Innym sposobem jest użycie tylko printf
polecenia i wygenerowanie wzoru wypełniania znaków najpierw przez Shell Brace Expansion
(Możesz zakończyć z obszarem formatowania liczby ≥, w którym chcesz wydrukować {1..end}
) i uzyskać tylko każdy jego pierwszy znak, %.1s
który jest =
s, a następnie wydrukować tylko pierwsze 20 znaków długości obszar tego %.20s
. Jest to rodzaj lepszego sposobu na powtarzanie znaków / słów zamiast ich powielania.
printf '%.20s:\n' "$str$(printf '%.1s' ={1..20})"
Hello World!!=======:
Objaśnienia:
Zwykle jako Brace Expansion , powłoka rozwija się {1..20}
w następujący sposób, jeśli je wydrukujemy.
printf '%s ' {1..20}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Po dodaniu do niej znaku równości ={1..20}
powłoka rozwija się w następujący sposób.
printf '%s ' ={1..20}
=1 =2 =3 =4 =5 =6 =7 =8 =9 =10 =11 =12 =13 =14 =15 =16 =17 =18 =19 =20
I printf '%.1s'
co to właściwie oznacza printf '%WIDE.LENGTH'
, drukujemy tylko jedną DŁUGOŚĆ z powyższych z domyślnym 1
SZEROKIM . spowoduje =
to tylko s i powtórzy się 20 razy.
Teraz printf '%.20s:\n'
drukujemy tylko 20 długości, $str
a jeśli długość $str
<20, reszta zajmie od wygenerowanych =
s do wypełnienia zamiast spacjami.