Linux command to repeat a string n times

76

27

Is there any built-in Linux command that allows to output a string that is n times an input string??

GetFree

Posted 2009-12-22T03:02:54.930

Reputation: 2 394

1

Related on [SO]: http://stackoverflow.com/q/3211891/2157640

– Palec – 2014-11-16T14:33:08.930

1By "built-in linux command" I assume you mean shell command, and since you don't mention which shell you're using, I assume it's bash. You can check this by typing "echo $SHELL" at the command line and you should get something similar to "/bin/bash" back. If you don't, you should edit your answer to specify what it does show. Cheers :) – Adrian Petrescu – 2009-12-22T03:12:54.150

7I tagged the question with "bash". I thought that would've been enough. – GetFree – 2009-12-22T03:27:39.937

Answers

81

adrian@Fourier:~$ printf 'HelloWorld\n%.0s' {1..5}
HelloWorld
HelloWorld
HelloWorld
HelloWorld
HelloWorld
adrian@Fourier:~$

Adrian Petrescu

Posted 2009-12-22T03:02:54.930

Reputation: 2 728

1What is specific to printf is that it will repeatedly apply excess arguments to the format string, "looping" for free. By "excess", I mean that there are more arguments than % placeholders. – Paused until further notice. – 2012-05-08T20:38:08.467

Uggh. Why bash (POSIX?) chose to do this is totally beyond me. I've been bitten by this when messing with my GRUB2 configuration. – new123456 – 2012-05-08T21:20:10.247

This doesn't work if we want to repeat 0 time. – icando – 2012-06-16T04:51:08.937

4Could you explain how this works? I understand the printf command since it's the same as the one in C/C++. But I dont understand how the {1..5} is expanded and how that works in conjunction with the "%.0s" part. – GetFree – 2009-12-22T03:24:48.867

4It's a bit of a hack :) Try running "printf 'HelloWorld %d\n' 1 2 3 4 5" and it'll probably click for you. The %.0s flag is meant to do nothing, just be there to pick up arguments. Then, if bash gets more arguments than it has format specifiers, it will simply print out multiple copies, grabbing as many as it needs. So you get the effect. The output of "printf 'HelloWorld %d%d\n' 1 2 3 4 5 6" probably makes it even clearer. Hope this helps! – Adrian Petrescu – 2009-12-22T03:44:55.393

I see. It's the particular behavior of printf what allows the repetition – GetFree – 2009-12-22T03:53:28.433

1(I should note that, from a purely theoretical standpoint, this is probably the fastest solution since it uses a single shell primitive -- not any external processes. In reality though, let's face it, performance of bash scripts doesn't really matter :) – Adrian Petrescu – 2009-12-22T03:53:46.733

NB: The expansion of {x..y} is not specific to printf. This is a bash syntax that expands to a sequence of numbers x, x+1, ..., y. For example, try "echo {1..10}". This is in the "Brace Expansion" section of the bash man page (and is called a "sequence expression"). – larsks – 2009-12-22T14:25:35.043

73

Here's an old-fashioned way that's pretty portable:

yes "HelloWorld" | head -n 10

This is a more conventional version of Adrian Petrescu's answer using brace expansion:

for i in {1..5}
do
    echo "HelloWorld"
done

That's equivalent to:

for i in 1 2 3 4 5

This is a little more concise and dynamic version of pike's answer:

printf -v spaces '%*s' 10 ''; printf '%s\n' ${spaces// /ten}

Paused until further notice.

Posted 2009-12-22T03:02:54.930

Reputation: 86 075

4The yes solution is pretty neat – piggybox – 2015-06-26T20:04:13.817

The yes solution was exactly what I needed, since I wanted to duplicate a command (whose output fluctuates). Thus: yes "$(my-command)" | head -n 2 – arnsholt – 2016-08-02T14:47:26.977

@arnsholt: I'm not sure what you mean by fluctuate. The command substitution only gets run once and yes outputs the same thing (the single output of the command substitution) multiple times. For example, compare yes "$(date +%N; sleep 1)" | head -n 4 and for i in {1..4}; do date +%N; sleep 1; done – Paused until further notice. – 2016-08-02T22:35:13.450

The output is based on a random sampling, so running the command twice yields somewhat different results each time. I actually wanted the exact same string twice (because the output was going into a script that generates a table, and that particular row was supposed to be the same number twice [where other rows varied, obviously]). – arnsholt – 2016-08-03T19:02:53.373

1@arnsholt: OK, I would use a for loop instead of spawning an external executable (yes). Or capture it once and output it twice like: out=$(my-command); printf '%s\n' "$out" "$out" (printf will apply excess arguments sequentially) or other similar techniques. – Paused until further notice. – 2016-08-03T19:15:11.703

How do you get rid of the new lines when using the yes command? – GetFree – 2009-12-22T04:16:47.937

3One way is to pipe it through sed -n 'H;${x;s/\n//gp}' or sed -n ':t;${s/\n//gp};N;bt' another is to do echo $(yes "HelloWorld" | head -n 10) which adds a space between each copy of the string. Yet another way is to pipe it through tr -d '\n' which also eliminates the final newline. – Paused until further notice. – 2009-12-22T09:08:42.417

2It's like Haskell in a bash shell: Hashell? – wchargin – 2014-01-15T05:20:26.230

14

This can be parameterized and doesn't require a temp variable, FWIW:

printf "%${N}s" | sed 's/ /blah/g'

Or, if $N is the size of a bash array:

echo ${ARR[@]/*/blah}

twifkak

Posted 2009-12-22T03:02:54.930

Reputation: 149

You shouldn't mix data into printf's format specifier. What if the data contains format strings? This is the correct way to dynamically specify the "precision" (length): printf '%*s' "$N" - make it a habit to enclose the format string in single quotes to prevent variable expansion there. – Paused until further notice. – 2019-01-05T14:22:44.040

3

This is the shortest POSIX 7 solution I have seen so far since seq, yes and {1..5} are not POSIX 7.

– Ciro Santilli 新疆改造中心法轮功六四事件 – 2014-04-10T11:27:05.310

14

Quite a few good ways already mentioned. Can't forget about good old seq though:

[john@awesome]$for i in `seq 5`; do echo "Hi";done
Hi
Hi
Hi
Hi
Hi

John T

Posted 2009-12-22T03:02:54.930

Reputation: 149 037

This one actually respects a zero, treating it as zero! (The {i..j} trick never returns an empty range.) – JellicleCat – 2016-10-15T02:48:05.557

11

You can use a trick. Echoing an empty variable does not print anything. So you can write:

echo word$wojek{1..100}

If $wojek1 $wojek2 ... $wojek100 are non-existing variables you will get your word repeated 100 times without anything else.

Wojtek Waga

Posted 2009-12-22T03:02:54.930

Reputation: 119

1It's an ugly ugly hack, and yet I can't help but love it and use it. – 16807 – 2017-07-14T17:38:38.750

1Love it! Maybe using $_ instead of $wojek makes the intent clearer. – Mihai Todor – 2019-09-04T14:13:11.000

10

Perhaps another way that is more general and useful for you:

adrian@Fourier:~$ n=5
adrian@Fourier:~$ for (( c=1; c<=n; c++)) ; do echo "HelloWorld" ; done
HelloWorld
HelloWorld
HelloWorld
HelloWorld
HelloWorld
adrian@Fourier:~$ 

The bash shell is more powerful than most people think :)

Adrian Petrescu

Posted 2009-12-22T03:02:54.930

Reputation: 2 728

This is the only one so far (yes, printf, for i in {1..5}) that if the n is zero, it returns empty string without exist status of 1. Also due to the mathematical notation for comparison, it is easy to have offset by 1 (e.g by changing the <= to <) – Mehrad Mahmoudian – 2019-06-19T08:54:42.660

2What forking are you referring to? The original answer requires none. The output of 'type printf' is 'printf is a shell builtin' and therefore runs within the original bash process. – CodeGnome – 2012-04-17T20:17:15.667

This gets my vote, as it's entirely shell-internal; no forking required. – esm – 2009-12-23T18:08:03.220

7

Repeat n times, just put n-1 commas between {}:

$ echo 'helloworld'{,,}
helloworld helloworld helloworld

Repeats 'helloworld' twice after the first echo.

kev

Posted 2009-12-22T03:02:54.930

Reputation: 9 972

1it add an extra space after each 'helloworld' – PADYMKO – 2017-03-07T11:28:42.160

this doesn't seem to let you put newlines in the string either (ie getting helloworld on their own lines) – TankorSmash – 2019-02-01T16:54:01.210

5Nice, but what if I want to get n from a variable? – GetFree – 2012-06-28T07:32:31.347

6

POSIX AWK:

#!/usr/bin/awk -f
function str_repeat(s1, n1) {
   s2 = ""
   for (n2 = 1; n2 <= n1; n2++) {
      s2 = s2 s1
   }
   return s2
}
BEGIN {
   s3 = str_repeat("Sun", 5)
   print s3
}

Or PHP:

<?php
$s3 = str_repeat('Sun', 5);
echo $s3, "\n";

Steven Penny

Posted 2009-12-22T03:02:54.930

Reputation: 7 294

Use this without the awk:
while (( c++ < 5 )); do printf 'hello'; done
– emf – 2017-02-21T08:33:16.013

POSIXly portable. I like this answer – Sergiy Kolodyazhnyy – 2020-01-13T08:15:19.057

4

I've experienced broken pipe warnings with the yes solution, so here's another good alternative:

$ seq 4 | sed "c foo"
foo
foo
foo
foo

n.caillou

Posted 2009-12-22T03:02:54.930

Reputation: 141

3

If you're on BSD, you can just use seq.

$ seq -f "Hello, world" 5
Hello, world
Hello, world
Hello, world
Hello, world
Hello, world

Qix - MONICA WAS MISTREATED

Posted 2009-12-22T03:02:54.930

Reputation: 321

2In seq (GNU coreutils) 8.25, this gives seq: format 'Hello, world' has no % directive, forcing a formatting directive to be present. GNU coreutils are used e.g. n many Linux distributions and Cygwin. Including the info here for those missing the info that it works only in BSD seq. – Palec – 2017-06-19T10:08:17.590

3

based on what @pike was hinting at

for every character in string echo string

echo ${target//?/$replace}

An example of a heading underlined with = characters

export heading='ABCDEF'; 
export replace='='; 
echo -e "${heading}\n${heading//?/$replace}"

will output

ABCDEF
======

This seems to port between linux and OS X and that makes me happy.

nJoy!

nickl-

Posted 2009-12-22T03:02:54.930

Reputation: 420

2

No magic here:

seq 5 | awk '{print "Hello World"}'

brablc

Posted 2009-12-22T03:02:54.930

Reputation: 1 102

2

line="==========================="
line=${line:0:10}
${line//"="/"ten "}

outputs

ten ten ten ten ten ten ten ten ten ten

commonpike

Posted 2009-12-22T03:02:54.930

Reputation: 293

Maybe a more verbose example: declare c='-----'; c=${c//${c:0:1}/$c}; echo $c # Prints "-" 25 times. – Stephen Niedzielski – 2013-01-02T23:02:48.593

2

Assuming you want something like Perl's x operator, where you don't automatically get a newline between repetitions:

x() {
  # usage: x string num
  for i in $(seq 1 $2); do printf "%s" "$1"; done
  # print a newline only if the string does not end in a newline
  [[ "$1" == "${1%$'\n'}" ]] && echo ""
}

x Hi 10  # ==> HiHiHiHiHiHiHiHiHiHi

x $'Hello World!\n' 3

I explicitly used a for loop because you can't write {1..$n} in bash: brace expansion is done before variable substitution.

glenn jackman

Posted 2009-12-22T03:02:54.930

Reputation: 18 546

2

Not exactly built in to linux, but if you have python installed..

python
>>>var = "string"
>>>var*n

Or in one line, as commenter suggested:

python -c 'print "This is a test.\n" * 10'

eqzx

Posted 2009-12-22T03:02:54.930

Reputation: 2 344

I like the readability of this solution, good reason enough for me. ;) – elias – 2015-08-16T20:28:13.080

4Not really that useful, since it can't be easily integrated into shell scripts, etc. And since there's about a billion ways to do this in the shell itself, I see little reason to bring out the big guns (i.e Python) for it. – Adrian Petrescu – 2009-12-22T03:18:07.057

7I agree with your second point but not the fist...it's easy to integrate into a shell script: python -c 'print "This is a test.\n" * 10' – larsks – 2009-12-22T14:26:40.533

1

Try this one:

echo $(for i in $(seq 1 100); do printf "-"; done)

Will create (a hundred dash):


Alle Aldine

Posted 2009-12-22T03:02:54.930

Reputation: 19