Chciałbym wydrukować hello world
ponad 20 znaków.
printf "%-20s :\n\n" 'hello world!!'
# Actual output
hello world!! :
# Wanted output
hello world!!========:
Nie chcę jednak uzupełniać spacjami, ale zamiast „ = ”. Jak mogę to zrobić?
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.
Daje
${#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(za 16
=
w linii). Systemy GNU mogą wykorzystywaćseq
:Inne systemy mogą używać Perla lub innego szybszego sposobu dynamicznego tworzenia łańcucha.
źródło
printf
do wygenerowania filtra, który jest prawie dostępny we wszystkich systemach i rozszerzenia nawiasów klamrowych jakbash/szh
?printf
rozszerzeniem nawiasów klamrowych wbash
?gdzie
%.20s
jest format obcinania łańcuchaźródło
Jednym ze sposobów na to:
źródło
====================\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:
Lub, lepiej, @SatoKatsura wskazał w komentarzach:
Jeśli chcesz obsługiwać znaki wielobajtowe UTF, użyj:
Ten sam pomysł w powłoce:
źródło
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 stronyperl6
jest denerwujące na wiele sposobów.PERL_UNICODE='AS'
. Na przykład:printf '%s' nóóös | perl -nle 'print length($_)'
drukuje 8 („źle”), aprintf '%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 przezShell 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.Objaśnienia:
Zwykle jako Brace Expansion , powłoka rozwija się
{1..20}
w następujący sposób, jeśli je wydrukujemy.Po dodaniu do niej znaku równości
={1..20}
powłoka rozwija się w następujący sposób.I
printf '%.1s'
co to właściwie oznaczaprintf '%WIDE.LENGTH'
, drukujemy tylko jedną DŁUGOŚĆ z powyższych z domyślnym1
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.źródło