Padding trailing whitespaces in a string with another character

I’d like to output hello world over 20 characters.

printf "%-20s :nn" 'hello world!!'

# Actual output
hello world!!        :

# Wanted output
hello world!!========:

However, I don’t want to complete with spaces but with “=” instead.
How do I do that?

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

filler='===================='
string='foo'

printf '%sn' "$string${filler:${#string}}"

Gives

foo=================

${#string} is the length of the value $string, and ${filler:${#string}} is the substring of $filler from offset ${#string} onwards.

The total width of the output will be that of the maximum width of $filler or $string.

The filler string can, on systems that has jot, be created dynamically using

filler=$( jot -s '' -c 16 '=' '=' )

(for 16 = in a line). GNU systems may use seq:

filler=$( seq -s '=' 1 16 | tr -dc '=' )

Other systems may use Perl or some other faster way of creating the string dynamically.

Method 2

printf "%.20s:nn" "$str========================="

where %.20s is the string truncating format

Method 3

One way to do it:

printf "====================:r%snn" 'hello world!!'

Method 4

Updated answer to be more general solution. see also my another answer below using only shell brace expansion and printf.

$ str='Hello World!'
$ sed -r ':loop; s/ (=*):$/1=:/; t loop' <<< "$(printf '%-20s:n' "$str" )"
Hello World!========:

How it works?

this (=*):$/ captures one space, one-or-more = that followed by a colon : in the end of its input; we make the set of = as a group match and 1 will be its back-reference.

With :loop we defined a label named loop and with t loop it will jump to that label when a s/ (=*):$/1=:/ has done successful substitution;

In replacement part with 1=:, it will always increment the number of =s and back the colon itself to the end of string.

Method 5

A Perl approach:

$ perl -le '$k="hello world!!"; while(length($k)<20){$k.="=";} print "$kn"'
hello world!!=======

Or, better, @SatoKatsura pointed out in the comments:

perl -le '$k = "hello world!!"; print $k, "=" x (20-length $k), "n"'

If you need to support UTF multi-byte characters, use:

PERL_UNICODE='AS' perl -le '$k = "hello world!!"; print $k, "=" x (20-length $k), "n"'

Same idea in the shell:

v='hello world!!'; while [ ${#v} -lt 20 ]; do v="$v""="; done; printf '%snn' "$v"

Method 6

Another way is using only printf command and generate the character padding pattern first by Shell Brace Expansion (You can put end with a number ≥ formatting area you want to print in {1..end}) and get only every first character of it %.1s which is =s and then print only first 20 characters length area of that %.20s. This is kind of better way to having repeated characters/word instead of duplicating them.

printf '%.20s:n' "$str$(printf '%.1s' ={1..20})"
Hello World!!=======:

Explanations:

Normally as Brace Expansion, shell expanding {1..20} as following if we print those.

printf '%s ' {1..20}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

So with adding an equal sign to it ={1..20}, shell will expand as following.

printf '%s ' ={1..20}
=1 =2 =3 =4 =5 =6 =7 =8 =9 =10 =11 =12 =13 =14 =15 =16 =17 =18 =19 =20

And with printf '%.1s' which is actually means printf '%WIDE.LENGTH', we are printing only one LENGTH of those at above with default 1 WIDE. so will result =s only and 20 times repeated itself.

Now with printf '%.20s:n' we are printing only the 20 length of $str and if length of $str<20, the rest will take from generated =s to fill with instead of spaces.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x