Risposte:
Risposta aggiornata per essere una soluzione più generale. vedi anche la mia altra risposta di seguito usando solo l'espansione delle parentesi graffe e pritnf
.
$ str='Hello World!'
$ sed -r ':loop; s/ (=*):$/\1=:/; t loop' <<< "$(printf '%-20s:\n' "$str" )"
Hello World!========:
Come funziona?
questo (=*):$/
cattura uno spazio, uno o più =
che è seguito da due punti :
alla fine del suo input; facciamo l'insieme di =
come una partita di gruppo e \1
sarà il suo riferimento indietro.
Con :loop
abbiamo definito un'etichetta denominata loop
e con t loop
essa salterà a quell'etichetta quando una s/ (=*):$/\1=:/
sostituzione ha avuto esito positivo;
Nella parte di ricambio con \1=:
, incrementa sempre il numero di se =
riporta i due punti alla fine della stringa.
filler='===================='
string='foo'
printf '%s\n' "$string${filler:${#string}}"
dà
foo=================
${#string}
è la lunghezza del valore $string
ed ${filler:${#string}}
è la sottostringa $filler
dell'offset in ${#string}
avanti.
La larghezza totale dell'output sarà quella della larghezza massima di $filler
o $string
.
La stringa di riempimento può, sui sistemi che ha jot
, essere creata in modo dinamico utilizzando
filler=$( jot -s '' -c 16 '=' '=' )
(per 16 =
in una riga). I sistemi GNU possono usare seq
:
filler=$( seq -s '=' 1 16 | tr -dc '=' )
Altri sistemi possono usare il Perl o qualche altro modo più veloce per creare dinamicamente la stringa.
printf
per generare il filtro che è quasi disponibile in tutti i sistemi e l'espansione del controvento con le shell come bash/szh
?
printf
espansione + parentesi graffa bash
?
printf "%.20s:\n\n" "$str========================="
dove %.20s
è il formato di troncamento della stringa
Un modo per farlo:
printf "====================:\r%s\n\n" 'hello world!!'
====================\rhello world
, il che potrebbe essere un problema se l'OP deve memorizzarlo e non stamparlo solo sullo schermo.
echo -e '=================\rHello World!!'
, ma ha lo stesso problema che ha sottolineato @terdon.
echo
supporta -e
. printf
è quasi sempre meglio di echo
, per molte ragioni.
Un approccio Perl:
$ perl -le '$k="hello world!!"; while(length($k)<20){$k.="=";} print "$k\n"'
hello world!!=======
O meglio, @SatoKatsura ha sottolineato nei commenti:
perl -le '$k = "hello world!!"; print $k, "=" x (20-length $k), "\n"'
Se è necessario supportare caratteri multi-byte UTF, utilizzare:
PERL_UNICODE='AS' perl -le '$k = "hello world!!"; print $k, "=" x (20-length $k), "\n"'
Stessa idea nella shell:
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"'
. Tuttavia, questa (e tutte le altre soluzioni pubblicate finora) si interrompe se sono coinvolti caratteri multibyte.
perl6
potrebbe avere un modo per farlo correttamente anche con caratteri multi-byte. Ma d'altra parte perl6
è fastidioso in molti modi.
PERL_UNICODE='AS'
. Ad esempio: printf '%s' nóóös | perl -nle 'print length($_)'
stampa 8 ("errato") mentre printf '%s' nóóös | PERL_UNICODE='AS' perl -nle 'print length($_)'
stampa 5 ("corretto").
Un altro modo è usare solo il printf
comando e generare prima il motivo di riempimento dei caratteri per Shell Brace Expansion
(È possibile terminare con un numero ≥ area di formattazione in cui si desidera stampare {1..end}
) e ottenere solo ogni primo carattere di esso %.1s
che è se =
quindi stampare solo i primi 20 caratteri di lunghezza area di quello %.20s
. Questo è un modo migliore per avere caratteri / parole ripetuti invece di duplicarli.
printf '%.20s:\n' "$str$(printf '%.1s' ={1..20})"
Hello World!!=======:
spiegazioni:
Normalmente come Brace Expansion , la shell si espande {1..20}
come segue se le stampiamo.
printf '%s ' {1..20}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Quindi con l'aggiunta di un segno uguale ad esso ={1..20}
, la shell si espanderà come segue.
printf '%s ' ={1..20}
=1 =2 =3 =4 =5 =6 =7 =8 =9 =10 =11 =12 =13 =14 =15 =16 =17 =18 =19 =20
E con ciò printf '%.1s'
che in realtà significa printf '%WIDE.LENGTH'
, stiamo stampando solo una LUNGHEZZA di quelle sopra con 1
WIDE predefinito . così risulterà =
solo e 20 volte ripetuto.
Ora con printf '%.20s:\n'
stiamo stampando solo la lunghezza di 20 $str
e se la lunghezza è $str
<20, il resto richiederà da =
s generati da riempire invece di spazi.