76
27
Is there any built-in Linux command that allows to output a string that is n times an input string??
76
27
Is there any built-in Linux command that allows to output a string that is n times an input string??
81
adrian@Fourier:~$ printf 'HelloWorld\n%.0s' {1..5}
HelloWorld
HelloWorld
HelloWorld
HelloWorld
HelloWorld
adrian@Fourier:~$
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}
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}
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.
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
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.
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 :)
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.
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";
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
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
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!
2
No magic here:
seq 5 | awk '{print "Hello World"}'
2
line="==========================="
line=${line:0:10}
${line//"="/"ten "}
outputs
ten ten ten ten ten ten ten ten ten ten
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.
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'
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):
1
Related on [SO]: http://stackoverflow.com/q/3211891/2157640
– Palec – 2014-11-16T14:33:08.9301By "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