How to repeat a dash (hyphen) in shell

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.


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 -.


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.


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.