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 \1będzie jego odniesieniem wstecznym.
Z :loopzdefiniowaliśmy etykietę o nazwie, loopa wraz z t loopnią 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 $stringi ${filler:${#string}}stanowi podciąg $fillerod przesunięcia w ${#string}górę.
Całkowita szerokość wyniku będzie równa maksymalnej szerokości $fillerlub $string.
Łańcuch wypełniający może być w systemach, które jotzostał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.
printfdo wygenerowania filtra, który jest prawie dostępny we wszystkich systemach i rozszerzenia nawiasów klamrowych jak bash/szh?
printfrozszerzeniem nawiasów klamrowych w bash?
printf "%.20s:\n\n" "$str========================="
gdzie %.20sjest 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.
echoobsługuje -e. printfjest prawie zawsze lepszy niż echoz 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.
perl6może to zrobić poprawnie, nawet przy znakach wielobajtowych. Ale z drugiej strony perl6jest 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 printfpolecenia 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, %.1sktó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, $stra jeśli długość $str<20, reszta zajmie od wygenerowanych =s do wypełnienia zamiast spacjami.