Padding trailing whitespaces in a string with another character

6,083

Solution 1

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.

Solution 2

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

printf '%s\n' "$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.

Solution 3

printf "%.20s:\n\n" "$str========================="

where %.20s is the string truncating format

Solution 4

One way to do it:

printf "====================:\r%s\n\n" 'hello world!!'

Solution 5

A Perl approach:

$ perl -le '$k="hello world!!"; while(length($k)<20){$k.="=";} print "$k\n"'
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 '%s\n\n' "$v"
Share:
6,083

Related videos on Youtube

smarber
Author by

smarber

Updated on September 18, 2022

Comments

  • smarber
    smarber over 1 year

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

    printf "%-20s :\n\n" '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?

  • terdon
    terdon over 6 years
    Ha! That's a clever trick! However, it will actually print ====================\rhello world, which might be an issue if the OP needs to store this and not just print it to screen.
  • Satō Katsura
    Satō Katsura over 6 years
    You don't need a loop: perl -le '$k = "hello world!!"; print $k, "=" x (20-length $k), "\n"'. However, this (and all other solutions posted so far) breaks if multi-byte characters are involved.
  • terdon
    terdon over 6 years
    @SatōKatsura ooh, yes, that's neat! Should have thought of that, thanks. And yes, I was thinking of adding a disclaimer for possible failure on UTF multi-byte characters, but figured it would be a needless complication in this context.
  • Satō Katsura
    Satō Katsura over 6 years
    I think perl6 might have a way to do it correctly even with multi-byte characters. But on the other hand perl6 is annoying in so many ways.
  • terdon
    terdon over 6 years
    @SatōKatsura well, for this sort of simple thing, it should be enough to just set PERL_UNICODE='AS'. For example: printf '%s' nóóös | perl -nle 'print length($_)' prints 8 ("wrong") while printf '%s' nóóös | PERL_UNICODE='AS' perl -nle 'print length($_)' prints 5 ("correct").
  • Kusalananda
    Kusalananda over 6 years
    This is IMHO, a better solution than mine. It only needs a short explanation of the format string.
  • user1686
    user1686 over 6 years
    so you have to adjust the flag depending on how many words the input has?
  • αғsнιη
    αғsнιη over 6 years
    also echo -e '=================\rHello World!!', but has same issue as @terdon pointed that.
  • Satō Katsura
    Satō Katsura over 6 years
    @αғsнιη Only if echo supports -e. printf is almost always better than echo, for many reasons.
  • αғsнιη
    αғsнιη over 5 years
    @grawity I have updated my answer to general solution now.
  • Kusalananda
    Kusalananda over 5 years
    @sddgob How would you do it with printf + brace expansion in bash?