How can I repeat the character -
n times in shell? I have read and tried this, but this does not work for -
. It throws error invalid option
. Below is the exact command that I used:
printf '-%.0s' {1..100}
Original posted line: printf '-%0.s' {1..100}
I also tried escaping -
by putting a \
but in that case it repeats \-
n times.
This throws an error:
$ printf '-%.0s' {1..100}; echo ""
bash: printf: -%: invalid option
printf: usage: printf [-v var] format [arguments]
This works fine under bash
:
$ printf -- '-%.0s' {1..100}; echo ""
----------------------------------------------------------------------------------------------------
For other shells, try:
printf -- '-%.0s' $(seq 100); echo ""
The problem was the printf
expects that -
starts an option. As is common among Unix/POSIX utilities in this type of situation, --
signals to printf
to expect no more options.
John1024's helpful answer provides a generic solution that shows how to disambiguate options from operands for all POSIX-like utilities.
In the case at hand, the simplest solution is (works not only in bash
, but also in ksh
and zsh
):
printf '%.0s-' {1..100}
Placing %.0s
before the -
avoids the issue of an initial -
getting mistaken for an option.
Slightly optimized:[1]
printf '%.s-' {1..100}
[1] %.0s
is in practice the most portable form (to be fully portable, you must also avoid the brace expansion, {...}
).
%.s
, the equivalent shorthand form, is supported by bash
, ksh
, and dash
, but not zsh
<= v5.2 - even though it is equally POSIX-compliant : "The precision [the part after .
] shall take the form of a ( '.' ) followed by a decimal digit string; a null digit string is treated as zero."
As a side note: The question originally contained a benign (in Bash) typo that sparked a debate: %0.s
instead of %.0s
: %0.s
should effectively be the same as %.0s
, and for that matter, the same as %.s
and %0.0s
(all effectively request: print a [minimum zero-width] field filled with a zero-length string), but in practice isn't: zsh
<= v5.2 doesn't handle %0.s
correctly (again, due to the .s
part).
Similarly, the GNU printf
external-utility implementation (/usr/bin/printf
), as of GNU coreutils v8.24, reports an error with %0.s
, because it generally doesn't accept a field width of 0
with s
: invalid conversion specification
- this matters for lesser-known shells that don't provide printf
as a builtin. Note that the BSD/OSX implementation does not have this problem.
Both zsh
's (<= v5.2) behavior with %.s
and GNU /usr/bin/printf
's behavior with %0s
are deviations from the POSIX spec that smell like bugs.
This question asks about zsh
's behavior regarding %.s
, and the bug has since been confirmed and reported as fixed via a post-v5.2 commit that has yet to be released as of this writing.
Use a for
loop and number range:
for i in {1..10};
do echo "-";
done
Or on a single line:
for i in {1..10};
do echo -n "-";
done
which outputs ----------
.
EDIT: This was before your printf
edit.
I would recommend using a traditional for
loop, as there is no need to spawn sub-processes or expand 100 arguments:
N=100
for((i = 0; i < $N; ++i)); do
printf -
done
It is curious that printf -%s
triggers "invalid option" but printf -
does not. To perhaps be extra safe, you could do printf %s -
.
You can also use tput
along with printf
to accomplish filling the terminal with an exact number of dashes, either drawing the line directly, or writing the line of dashes to a variable (say line
) for repeated use, e.g. to write a screen width line of dashes to the variable line
, you could do:
$ eval printf -v line '%.0s-' {1..$(tput cols)}
and then simply echo "$line"
each time you need to draw the line. You can also write it directly to the screen with.
$ eval printf '%.0s-' {1..$(tput cols)}
(I'm not a huge fan of eval
, but this is one use where you are guaranteed the result of the command cannot be harmful).