repeating a character using printf and appending a newline at the end

printf %.1s @{1..20} $'\n'

the shell expands the braces first, this is called "Brace Expansion".
@{1..20} into @1 @2 @3 ... and so on
Then the first byte of each parameter will be output, including the last argument $'\n' consisting of one byte - the newline character


With zsh:

printf '%s\n' ${(l[20][@])}

(using the l left-padding parameter expansion flag. You could also use the right padding one here).

Of course, you don't have to use printf. You could also use print or echo here which do add a \n by default. (printf '%s\n' "$string" can be written print -r -- "$string" or echo -E - "$string" in zsh, though if $string doesn't contain backslashes and doesn't start with -, that can be simplified to print "$string"/echo "$string").

If the end-goal is to display a list of strings padded to the width of the screen, you'd do:

$ lines=(short 'longer text' 'even longer')
$ print -rC1 -- ${(ml[$COLUMNS][@][ ])lines}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ short
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ longer text
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ even longer
$ print -rC1 -- ${(mr[$COLUMNS][@][ ])lines}
short @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
longer text @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
even longer @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Where the m flag causes zsh to take into account the display width of each character (like for those double-width characters above (which your browser may not render with exactly double-width, but your terminal should)).

print -rC1 -- is like printf '%s\n' or print -rl -- to print one element per line except in the case where no arguments are passed to it (like when lines=()) in which case it prints nothing instead of an empty line).


One printf, ends in newline, variable size, works in dash, ksh, bash and zsh:

$ printf '%*.0s\n' 33 "" | tr " " "@"
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Tags:

Printf

Sed