How to repeat a dash (hyphen) in shell

2019-04-20 17:56发布

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.

6条回答
我欲成王,谁敢阻挡
2楼-- · 2019-04-20 18:16

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

查看更多
贼婆χ
3楼-- · 2019-04-20 18:19
  1. jot can do it, with no bashisms:

    jot -s '' -b - 100
    
  2. seq too, but not as well, it needs a tr:

    seq -s- 100 | tr -d '[0-9]'
    
查看更多
淡お忘
4楼-- · 2019-04-20 18:21

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.

查看更多
别忘想泡老子
5楼-- · 2019-04-20 18:21

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.

查看更多
霸刀☆藐视天下
6楼-- · 2019-04-20 18:22

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.

查看更多
Anthone
7楼-- · 2019-04-20 18:23

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

查看更多
登录 后发表回答