Print a character repeatedly in bash

BashShell

Bash Problem Overview


Is there a way to print same character repeatedly in bash, just like you can use this construct to do this in python:

print('%' * 3)

gives

%%%

Bash Solutions


Solution 1 - Bash

There's actually a one-liner that can do this:

    printf "%0.s-" {1..10}

prints

    ----------

Here's the breakdown of the arguments passed to printf:

  • %s - This specifies a string of any length
  • %0s - This specifies a string of zero length, but if the argument is longer it will print the whole thing
  • %0.s - This is the same as above, but the period tells printf to truncate the string if it's longer than the specified length, which is zero
  • {1..10} - This is a brace expansion that actually passes the arguments "1 2 3 4 5 6 7 8 9 10"
  • "-" - This is an extra character provided to printf, it could be anything (for a "%" you must escape it with another "%" first, i.e. "%%")
  • Lastly, The default behavior for printf if you give it more arguments than there are specified in the format string is to loop back to the beginning of the format string and run it again.

The end result of what's going on here then is that you're telling printf that you want it to print a zero-length string with no extra characters if the string provided is longer than zero. Then after this zero-length string print a "-" (or any other set of characters). Then you provide it 10 arguments, so it prints 10 zero-length strings following each with a "-".

It's a one-liner that prints any number of repeating characters!

Edit:

Coincidentally, if you want to print $variable characters you just have to change the argument slightly to use seq rather than brace expansion as follows:

    printf '%0.s-' $(seq 1 $variable)

This will instead pass arguments "1 2 3 4 ... $variable" to printf, printing precisely $variable instances of "-"

Solution 2 - Bash

sure, just use printf and a bit of bash string manipulation

$ s=$(printf "%-30s" "*")
$ echo "${s// /*}"
******************************

There should be a shorter way, but currently that's how i would do it. You can make this into a function which you can store in a library for future use

printf_new() {
 str=$1
 num=$2
 v=$(printf "%-${num}s" "$str")
 echo "${v// /*}"
}

Test run:

$ printf_new "*" 20
********************
$ printf_new "*" 10
**********
$ printf_new "%" 10
%%%%%%%%%%

Solution 3 - Bash

The current accepted answer for this question (by ghostdog74) provides a method that executes extremely slowly for even a moderately high number of characters. The top-voted answer (by CaffeineConnoisseur) is better, but is still quite slow.

Here is what, in my tests, has executed fastest of all (even faster than the python version):

perl -E "print '*' x 1000"

In second place was the python command:

python -c "print('*' * 1000)"

If neither perl nor python are available, then this is third-best:

head -c 1000 /dev/zero | tr '\0' '*'

And in fourth place is the one using the bash printf built-in along with tr:

printf '%*s' 1000 | tr ' ' '*'

And here's one (from CaffeineConnoisseur's answer) that's in fifth place in speed for large numbers of repeated characters, but might be faster for small numbers (due to using only a bash built-in, and not spawning an external process):

printf '%.s*' {1..1000}

Solution 4 - Bash

I like this:

echo $(yes % | head -n3)

You may not like this:

for ((i=0; i<3; i++)){
   echo -ne "%"
}

You might like this:

s=$( printf "%3s" ); echo " ${s// /%}"

Source: http://dbaspot.com/shell/357767-bash-fast-way-repeat-string.html

There is also this form, but not very useful:

echo %{,,}

Solution 5 - Bash

It's ugly, but you can do it like this:

$ for a in `seq 5`; do echo -n %; done
%%%%%

Of course, seq is an external program (which you probably have).

Solution 6 - Bash

  1. It is possible to obtain any number of zero (\0) character from /dev/zero. The only thing left to do it is

     head -c 20 /dev/zero |tr '\0' '+'
    

Note that head and tr are external commands. So that it would be invoked in separate process.

  1. It is possible to "optimize" this solution with string caching.

     CACHE="$(head -c 1000 /dev/zero |tr '\0' '+')"
     echo "${CACHE:0:10}"
     echo "${CACHE:0:100}"
     echo "${CACHE:0:300}"
    

There are only bash built-ins in the echo statement. So, we can use it in cycle.

Solution 7 - Bash

Another one:

char='%'
count=5
result=$( printf "%${count}s" ' ' )
echo -e ${result// /$char}

Solution 8 - Bash

#!/usr/bin/awk -f
BEGIN {
  while (c++ < 3) printf "%"
}

Result

%%%

Solution 9 - Bash

Here is the most simple way to do that

seq -s % 4|tr -d '[:digit:]'

Note there will be only 3 '%' in created sequence.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAnkur AgarwalView Question on Stackoverflow
Solution 1 - BashCaffeineConnoisseurView Answer on Stackoverflow
Solution 2 - Bashghostdog74View Answer on Stackoverflow
Solution 3 - BashDeadcodeView Answer on Stackoverflow
Solution 4 - BashmanojldsView Answer on Stackoverflow
Solution 5 - BashGreg HewgillView Answer on Stackoverflow
Solution 6 - BashssvdaView Answer on Stackoverflow
Solution 7 - BashFritz G. MehnerView Answer on Stackoverflow
Solution 8 - BashZomboView Answer on Stackoverflow
Solution 9 - BashHovoKView Answer on Stackoverflow