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.