Réponse mise à jour pour être une solution plus générale. voir aussi ma autre réponse ci-dessous en utilisant uniquement l'expansion de l'accolade shell et pritnf
.
$ str='Hello World!'
$ sed -r ':loop; s/ (=*):$/\1=:/; t loop' <<< "$(printf '%-20s:\n' "$str" )"
Hello World!========:
Comment ça fonctionne?
cela (=*):$/
capture un espace, un ou plusieurs =
qui a suivi par deux points :
à la fin de son entrée; nous faisons l'ensemble de =
comme match de groupe et \1
serons sa référence arrière.
Avec, :loop
nous avons défini une étiquette nommée loop
et avec t loop
elle, nous passerons à cette étiquette lorsque a s/ (=*):$/\1=:/
a réussi la substitution;
En pièce de rechange avec \1=:
, il incrémentera toujours le nombre de =
s et remettra les deux points à la fin de la chaîne.
Donne
${#string}
est la longueur de la valeur$string
et${filler:${#string}}
est la sous-chaîne de à$filler
partir du décalage${#string}
.La largeur totale de la sortie sera celle de la largeur maximale de
$filler
ou$string
.La chaîne de remplissage peut, sur les systèmes existants
jot
, être créée dynamiquement à l'aide de(pour 16
=
en ligne). Les systèmes GNU peuvent utiliserseq
:D'autres systèmes peuvent utiliser Perl ou un autre moyen plus rapide de créer dynamiquement la chaîne.
la source
printf
pour générer le filtre qui est presque disponible dans tous les systèmes et l'expansion de l'entretoise avec les coques commebash/szh
?printf
extension + brace enbash
?où
%.20s
est le format de chaîne tronquéela source
Une façon de le faire:
la source
====================\rhello world
, ce qui pourrait être un problème si l'OP doit le stocker et pas seulement l'imprimer à l'écran.echo -e '=================\rHello World!!'
, mais a le même problème que @terdon l'a souligné.echo
supports-e
.printf
est presque toujours mieux queecho
, pour de nombreuses raisons.Une approche Perl:
Ou mieux, @SatoKatsura a souligné dans les commentaires:
Si vous devez prendre en charge les caractères multi-octets UTF, utilisez:
Même idée dans le shell:
la source
perl -le '$k = "hello world!!"; print $k, "=" x (20-length $k), "\n"'
. Cependant, cela (et toutes les autres solutions publiées jusqu'à présent) s'arrête si des caractères multi-octets sont impliqués.perl6
pourrait avoir un moyen de le faire correctement, même avec des caractères multi-octets. Mais d'un autre côté,perl6
c'est ennuyeux à bien des égards.PERL_UNICODE='AS'
. Par exemple:printf '%s' nóóös | perl -nle 'print length($_)'
imprime 8 ("faux") tandis queprintf '%s' nóóös | PERL_UNICODE='AS' perl -nle 'print length($_)'
imprime 5 ("correct").Une autre façon consiste à utiliser uniquement la
printf
commande et à générer d'abord le motif de remplissage des caractères parShell Brace Expansion
(vous pouvez mettre fin avec un nombre ≥ zone de formatage dans laquelle vous souhaitez imprimer{1..end}
) et à n'en obtenir que chaque premier caractère,%.1s
qui est=
s, puis à n'imprimer que les 20 premiers caractères domaine de cela%.20s
. C'est en quelque sorte une meilleure façon d'avoir des caractères / mots répétés au lieu de les dupliquer.Explications:
Normalement, en tant qu'expansion Brace , le shell se développe
{1..20}
comme suit si nous les imprimons.Ainsi, en y ajoutant un signe égal
={1..20}
, le shell se développera comme suit.Et
printf '%.1s'
ce qui signifie en faitprintf '%WIDE.LENGTH'
, nous n'imprimons qu'une seule LONGUEUR de ceux ci-dessus avec1
WIDE par défaut . il en résultera=
seulement s et 20 fois répété.Maintenant, avec
printf '%.20s:\n'
nous n'imprimons que la longueur de 20$str
et si la longueur est$str
<20, le reste prendra des=
s générés à remplir au lieu d'espaces.la source