52

I need to generate a string of dots (.characters) as a variable.

I.e., in my Bash script, for input 15 I need to generate this string of length 15: ...............

I need to do so variably. I tried using this as a base (from Unix.com):

for i in {1..100};do printf "%s" "#";done;printf "\n"

But how do I get the 100 to be a variable?

Palec
  • 12,743
  • 8
  • 69
  • 138
RubiCon10
  • 1,199
  • 2
  • 13
  • 15

9 Answers9

85

You can get as many NULL bytes as you want from /dev/zero. You can then turn these into other characters. The following prints 16 lowercase a's

head -c 16 < /dev/zero | tr '\0' '\141'
Electron
  • 1,390
  • 10
  • 8
42
len=100 ch='#'
printf '%*s' "$len" | tr ' ' "$ch"
Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
Chris Johnsen
  • 214,407
  • 26
  • 209
  • 186
27

Easiest and shortest way without a loop

VAR=15

Prints as many dots as VAR says (change the first dot to any other character if you like):

printf '.%.0s' {1..$VAR}

Saves the dotted line in a variable to be used later:

line=`printf '.%.0s' {1..$VAR}`
echo "Sign here $line"

-Blatantly stolen from dogbane's answer https://stackoverflow.com/a/5349842/3319298

Edit: Since I have now switched to fish shell, here is a function defined in config.fish that does this with convenience in that shell:

function line -a char -a length
  printf '%*s\n' $length "" | tr ' ' $char
end

Usage: line = 8 produces ========, line \" 8 produces """""""".

Community
  • 1
  • 1
Epigene
  • 3,634
  • 1
  • 26
  • 31
  • 1
    what an interesting way to exploit printf's shell feature that repeatibly consumes arguments until satisfied in combination with a zero-field width, forcing just the string before the % to be printed. This could be used as a trick to divide the count as well (adding the %.0s twice to force it to consume 2 arguments per pass) – osirisgothra Jun 22 '14 at 18:42
  • oh yeah and I forgot something important, since printf processes %s with a null if no args are given, a value of zero would be a problem, for that you would have to add an if statement – osirisgothra Jun 22 '14 at 21:02
  • 3
    This only works for me in my shell (bash) if I use eval: `VAR=15 ; eval printf '=%.0s' {1..$VAR}` – 6EQUJ5 Sep 27 '14 at 06:42
  • Only works for me with eval too. Replacing $VAR with $COLUMNS is very useful for making a horizontal ruler. If needed from inside a script: `hr () { eval printf '=%.0s' {1..$(tput cols)}; echo; }` –  Nov 28 '14 at 09:37
  • Your answer is fine, using *POSIX shell*, but using [tag:bash] , you could avoid one fork by using `-v` arg to `printf -v line '.%.0s' {1..$VAR}` – F. Hauri - Give Up GitHub Mar 20 '17 at 07:41
  • 6
    @6EQUJ5 In `bash`, you can't use variables in a brace expansion. Instead, you can use `$(seq 1 $VAR)` in place of `{1..$VAR}` – wisbucky Dec 08 '17 at 23:56
  • @wisbucky actually it does... tested exactly what I quoted above just now using bash version 4.3.30(1)-release on Debian 8 - maybe you have a different shell ```~$ VAR=15 ; eval printf '=%.0s' {1..$VAR}``` (line break was here) ```===============``` – 6EQUJ5 Dec 11 '17 at 09:52
  • 1
    @6EQUJ5 I meant without using `eval`. `eval` is not safe to use in a script. https://stackoverflow.com/questions/17529220/why-should-eval-be-avoided-in-bash-and-what-should-i-use-instead – wisbucky Dec 11 '17 at 18:32
9

On most systems, you could get away with a simple

N=100
myvar=`perl -e "print '.' x $N;"`
Christopher Creutzig
  • 8,656
  • 35
  • 45
6

I demonstrated a way to accomplish this task with a single command in another question, assuming it's a fixed number of characters to be produced.

I added an addendum to the end about producing a variable number of repeated characters, which is what you asked for, so my previous answer is relevant here:

https://stackoverflow.com/a/17030976/2284005

I provided a full explanation of how it works there. Here I'll just add the code to accomplish what you're asking for:

    n=20 # This the number of characters you want to produce

    variable=$(printf "%0.s." $(seq 1 $n)) # Fill $variable with $n periods

    echo $variable # Output content of $variable to terminal

Outputs:

....................
Community
  • 1
  • 1
CaffeineConnoisseur
  • 3,635
  • 4
  • 19
  • 16
  • n=0 fails to produce the correct number of characters. As do most of the printf solutions. – NOYB Sep 07 '20 at 19:19
4

You can use C-style for loops in Bash:

num=100
string=$(for ((i=1; i<=$num; i++));do printf "%s" "#";done;printf "\n")

Or without a loop, using printf without using any externals such as sed or tr:

num=100
printf -v string "%*s" $num ' ' '' $'\n'
string=${string// /#}
Dennis Williamson
  • 346,391
  • 90
  • 374
  • 439
3

The solution without loops:

N=100
myvar=`seq 1 $N | sed 's/.*/./' | tr -d '\n'`
Aleksey Otrubennikov
  • 1,121
  • 1
  • 12
  • 26
2
num=100
myvar=$(jot -b . -s '' $num)
echo $myvar
Alexander Gladysh
  • 39,865
  • 32
  • 103
  • 160
-1

When I have to create a string that contains $x repetitions of a known character with $x below a constant value, I use this idiom:

base='....................'
# 0 <= $x <= ${#base}
x=5
expr "x$base" : "x\(.\{$x\}\)"    # Will output '\n' too

Output:

.....
dolmen
  • 8,126
  • 5
  • 40
  • 42
  • 2
    In bash and ksh (perhaps zsh), you could write `echo ${base:0:$x}` -- details [here](http://www.gnu.org/software/bash/manual/bashref.html#Shell-Parameter-Expansion) – glenn jackman Jul 22 '14 at 13:21