dog*_*ane 358

您可以使用:

printf '=%.0s' {1..100}
Run Code Online (Sandbox Code Playgroud)

这是如何工作的:

Bash扩展{1..100},因此命令变为:

printf '=%.0s' 1 2 3 4 ... 100
Run Code Online (Sandbox Code Playgroud)

我已经设置了printf的格式,=%.0s这意味着=无论给出什么参数,它总是会打印一个.因此它打印100 =秒.

  • 您不能在大括号扩展中使用变量.使用`seq`代替`$(seq 1 $ limit)`. (65认同)
  • 即使有大量重复计数也能很好地运行的出色解决方案.这是一个函数包装器,你可以用`repl = 100`来调用,例如(不幸的是,'eval`技巧,基于变量的大括号扩展):`repl(){printf"$ 1"'%.s' $(eval"echo {1 .."$(($ 2))"}"); }` (13认同)
  • 如果你将其功能化,最好将它从`$ s%.0s`重新排列到`%.0s $ s`,否则破坏会导致'printf`错误. (11认同)
  • 是否可以使用var设置上限?我已经尝试过但无法让它发挥作用. (5认同)
  • 这让我注意到了Bash的`printf`的行为:它继续应用格式字符串,直到没有参数为止.我原以为它只处理了格式字符串一次! (4认同)
  • 如果你想用变量`w`指定宽度,那么`printf"%$ {w} s怎么样'''| tr''=`? (2认同)
  • 它也可以在点后没有零的情况下工作:`echo "$(printf '=%.s' {1..100})"` (2认同)
  • 如果尝试重复连字符“-”,您可以将它们放在格式字符串“%.0s-”的末尾,否则您将收到错误,因为前导连字符将被解释为选项。 (2认同)

小智 84

没有简单的方法.但是例如:

seq -s= 100|tr -d '[:digit:]'
Run Code Online (Sandbox Code Playgroud)

或者也许是符合标准的方式:

printf %100s |tr " " "="
Run Code Online (Sandbox Code Playgroud)

还有一个tput rep,但至于手头的终端(xterm和linux)他们似乎不支持它:)

  • `printf``tr`是唯一的POSIX解决方案,因为`seq`,`yes`和`{1..3}`不是POSIX. (13认同)
  • 请注意,seq的第一个选项打印的数字少于给定的数字,因此该示例将打印99` =`字符. (2认同)
  • 要重复一个字符串而不是一个字符:`printf%100s | sed's// abc/g'` - 输出'abcabcabc ......' (2认同)
  • +1表示不使用循环,仅使用一个外部命令(`tr`)。您还可以将其扩展为`printf“%$ {COLUMNS} s \ n” | tr“”“ =”`。 (2认同)
  • @CamiloMartin:感谢您的跟进:它确实归结为“seq”实现(因此隐式地是平台):_GNU_“seq”(Linux)比指定的数字少_1个“=”(与我最初的不同)声称,但正如您所正确确定的那样),而 _BSD_ `seq` (类似 BSD 的平台,包括 OSX)产生所需的数字。简单测试命令:`seq -s= 100 | tr -d '[:数字:]\n' | wc -c` BSD `seq` 将 `=` 放在每个数字之后,包括最后一个,而 GNU seq 在最后一个数字之后放置一个换行符,因此相对于 `=` 计数少了 1。 (2认同)
  • @ mklement0好吧,我希望你用`wc`错误地计算最后一个换行符.我可以从中得出的唯一结论是"不应该使用`seq`". (2认同)

mkl*_*nt0 45

给@ gniourf_gniourf的帽子提示他的输入.

注意:这个答案并没有回答原来的问题,但补充了由现有的,有用的答案比较性能.

在执行速度方面对解决方案进行了比较 - 考虑内存要求(它们在不同的解决方案中有所不同,并且可能与大的重复计数有关).

摘要:

  • 如果您的重复计数很小,比如高达100左右,则值得使用仅限Bash的解决方案,因为外部实用程序的启动成本很重要,尤其是Perl.
    • 但实际上,如果你只需要一个重复字符的实例,那么所有现有的解决方案都可能没问题.
  • 使用大量重复计数时,请使用外部实用程序,因为它们会更快.
    • 特别是,避免使用大字符串
      (例如${var// /=})替换Bash的全局子字符串,因为它非常慢.

以下是时机了3.2 GHz的英特尔酷睿i5 CPU和融合驱动器,运行OSX 10.10.4和bash 3.2.57在后期2012的iMac采取,并且是1000次运行的平均值.

条目是:

  • 以执行持续时间的升序列出(最快的第一个)
  • 前缀为:
    • M......一个潜在的角色解决方案
    • S......一个单一字符的解决方案
    • P ...符合POSIX标准的解决方案
  • 然后简要介绍解决方案
  • 后缀为原始答案作者的姓名

  • 小重复次数:100
[M, P] printf %.s= [dogbane]:                           0.0002
[M   ] printf + bash global substr. replacement [Tim]:  0.0005
[M   ] echo -n - brace expansion loop [eugene y]:       0.0007
[M   ] echo -n - arithmetic loop [Eliah Kagan]:         0.0013
[M   ] seq -f [Sam Salisbury]:                          0.0016
[M   ] jot -b [Stefan Ludwig]:                          0.0016
[M   ] awk - $(count+1)="=" [Steven Penny (variant)]:   0.0019
[M, P] awk - while loop [Steven Penny]:                 0.0019
[S   ] printf + tr [user332325]:                        0.0021
[S   ] head + tr [eugene y]:                            0.0021
[S, P] dd + tr [mklement0]:                             0.0021
[M   ] printf + sed [user332325 (comment)]:             0.0021
[M   ] mawk - $(count+1)="=" [Steven Penny (variant)]:  0.0025
[M, P] mawk - while loop [Steven Penny]:                0.0026
[M   ] gawk - $(count+1)="=" [Steven Penny (variant)]:  0.0028
[M, P] gawk - while loop [Steven Penny]:                0.0028
[M   ] yes + head + tr [Digital Trauma]:                0.0029
[M   ] Perl [sid_com]:                                  0.0059
Run Code Online (Sandbox Code Playgroud)
  • Bash-only解决方案领先一揽子计划 - 但只有重复计数这么小!(见下文).
  • 外部工具的启动成本在这里很重要,尤其是Perl.如果必须在循环中调用它 - 在每次迭代中重复次数较少 - 请避免使用多实用程序awkperl解决方案.

  • 大重复次数:1000000(100万)
[M   ] Perl [sid_com]:                                  0.0067
[M   ] mawk - $(count+1)="=" [Steven Penny (variant)]:  0.0254
[M   ] gawk - $(count+1)="=" [Steven Penny (variant)]:  0.0599
[S   ] head + tr [eugene y]:                            0.1143
[S, P] dd + tr [mklement0]:                             0.1144
[S   ] printf + tr [user332325]:                        0.1164
[M, P] mawk - while loop [Steven Penny]:                0.1434
[M   ] seq -f [Sam Salisbury]:                          0.1452
[M   ] jot -b [Stefan Ludwig]:                          0.1690
[M   ] printf + sed [user332325 (comment)]:             0.1735
[M   ] yes + head + tr [Digital Trauma]:                0.1883
[M, P] gawk - while loop [Steven Penny]:                0.2493
[M   ] awk - $(count+1)="=" [Steven Penny (variant)]:   0.2614
[M, P] awk - while loop [Steven Penny]:                 0.3211
[M, P] printf %.s= [dogbane]:                           2.4565
[M   ] echo -n - brace expansion loop [eugene y]:       7.5877
[M   ] echo -n - arithmetic loop [Eliah Kagan]:         13.5426
[M   ] printf + bash global substr. replacement [Tim]:  n/a
Run Code Online (Sandbox Code Playgroud)
  • 该问题的Perl解决方案是迄今为止最快的.
  • Bash的全局字符串替换(${foo// /=})使用大字符串是令人费解的极其缓慢,并且已经被淘汰(在Bash 4.3.30中花了大约50分钟(!),在Bash 3.2.57中花了更长时间 - 我从未等待过它完成).
  • Bash循环很慢,并且算术循环((( i= 0; ... )))比大括号扩展的({1..n})慢- 尽管算术循环更节省内存.
  • awk指的是BSD awk(也可以在OSX上找到) - 它明显慢于gawk(GNU Awk),特别是mawk.
  • 请注意,大计数和多字符.字符串,内存消耗可以成为一个考虑因素 - 方法在这方面有所不同.

这是产生上述内容的Bash脚本(testrepeat).它需要2个参数:

  • 字符重复计数
  • 可选地,要执行的测试运行次数和计算平均时间

换句话说:上面的时间是用testrepeat 100 1000和获得的testrepeat 1000000 1000

#!/usr/bin/env bash

title() { printf '%s:\t' "$1"; }

TIMEFORMAT=$'%6Rs'

# The number of repetitions of the input chars. to produce
COUNT_REPETITIONS=${1?Arguments: <charRepeatCount> [<testRunCount>]}

# The number of test runs to perform to derive the average timing from.
COUNT_RUNS=${2:-1}

# Discard the (stdout) output generated by default.
# If you want to check the results, replace '/dev/null' on the following
# line with a prefix path to which a running index starting with 1 will
# be appended for each test run; e.g., outFilePrefix='outfile', which
# will produce outfile1, outfile2, ...
outFilePrefix=/dev/null

{

  outFile=$outFilePrefix
  ndx=0

  title '[M, P] printf %.s= [dogbane]'
  [[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
  # !! In order to use brace expansion with a variable, we must use `eval`.
  eval "
  time for (( n = 0; n < COUNT_RUNS; n++ )); do 
    printf '%.s=' {1..$COUNT_REPETITIONS} >"$outFile"
  done"

  title '[M   ] echo -n - arithmetic loop [Eliah Kagan]'
  [[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
  time for (( n = 0; n < COUNT_RUNS; n++ )); do 
    for ((i=0; i<COUNT_REPETITIONS; ++i)); do echo -n =; done >"$outFile"
  done


  title '[M   ] echo -n - brace expansion loop [eugene y]'
  [[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
  # !! In order to use brace expansion with a variable, we must use `eval`.
  eval "
  time for (( n = 0; n < COUNT_RUNS; n++ )); do 
    for i in {1..$COUNT_REPETITIONS}; do echo -n =; done >"$outFile"
  done
  "

  title '[M   ] printf + sed [user332325 (comment)]'
  [[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
  time for (( n = 0; n < COUNT_RUNS; n++ )); do 
    printf "%${COUNT_REPETITIONS}s" | sed 's/ /=/g' >"$outFile"
  done


  title '[S   ] printf + tr [user332325]'
  [[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
  time for (( n = 0; n < COUNT_RUNS; n++ )); do 
    printf "%${COUNT_REPETITIONS}s" | tr ' ' '='  >"$outFile"
  done


  title '[S   ] head + tr [eugene y]'
  [[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
  time for (( n = 0; n < COUNT_RUNS; n++ )); do 
    head -c $COUNT_REPETITIONS < /dev/zero | tr '\0' '=' >"$outFile"
  done


  title '[M   ] seq -f [Sam Salisbury]'
  [[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
  time for (( n = 0; n < COUNT_RUNS; n++ )); do 
    seq -f '=' -s '' $COUNT_REPETITIONS >"$outFile"
  done


  title '[M   ] jot -b [Stefan Ludwig]'
  [[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
  time for (( n = 0; n < COUNT_RUNS; n++ )); do 
    jot -s '' -b '=' $COUNT_REPETITIONS >"$outFile"
  done


  title '[M   ] yes + head + tr [Digital Trauma]'
  [[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
  time for (( n = 0; n < COUNT_RUNS; n++ )); do 
    yes = | head -$COUNT_REPETITIONS | tr -d '\n'  >"$outFile"
  done

  title '[M   ] Perl [sid_com]'
  [[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
  time for (( n = 0; n < COUNT_RUNS; n++ )); do 
    perl -e "print \"=\" x $COUNT_REPETITIONS" >"$outFile"
  done

  title '[S, P] dd + tr [mklement0]'
  [[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
  time for (( n = 0; n < COUNT_RUNS; n++ )); do 
    dd if=/dev/zero bs=$COUNT_REPETITIONS count=1 2>/dev/null | tr '\0' "=" >"$outFile"
  done

  # !! On OSX, awk is BSD awk, and mawk and gawk were installed later.
  # !! On Linux systems, awk may refer to either mawk or gawk.
  for awkBin in awk mawk gawk; do
    if [[ -x $(command -v $awkBin) ]]; then

      title "[M   ] $awkBin"' - $(count+1)="=" [Steven Penny (variant)]'
      [[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
      time for (( n = 0; n < COUNT_RUNS; n++ )); do 
        $awkBin -v count=$COUNT_REPETITIONS 'BEGIN { OFS="="; $(count+1)=""; print }' >"$outFile"
      done

      title "[M, P] $awkBin"' - while loop [Steven Penny]'
      [[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
      time for (( n = 0; n < COUNT_RUNS; n++ )); do 
        $awkBin -v count=$COUNT_REPETITIONS 'BEGIN { while (i++ < count) printf "=" }' >"$outFile"
      done

    fi
  done

  title '[M   ] printf + bash global substr. replacement [Tim]'
  [[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
  # !! In Bash 4.3.30 a single run with repeat count of 1 million took almost
  # !! 50 *minutes*(!) to complete; n Bash 3.2.57 it's seemingly even slower -
  # !! didn't wait for it to finish.
  # !! Thus, this test is skipped for counts that are likely to be much slower
  # !! than the other tests.
  skip=0
  [[ $BASH_VERSINFO -le 3 && COUNT_REPETITIONS -gt 1000 ]] && skip=1
  [[ $BASH_VERSINFO -eq 4 && COUNT_REPETITIONS -gt 10000 ]] && skip=1
  if (( skip )); then
    echo 'n/a' >&2
  else
    time for (( n = 0; n < COUNT_RUNS; n++ )); do 
      { printf -v t "%${COUNT_REPETITIONS}s" '='; printf %s "${t// /=}"; } >"$outFile"
    done
  fi
} 2>&1 | 
 sort -t$'\t' -k2,2n | 
   awk -F $'\t' -v count=$COUNT_RUNS '{ 
    printf "%s\t", $1; 
    if ($2 ~ "^n/a") { print $2 } else { printf "%.4f\n", $2 / count }}' |
     column -s$'\t' -t
Run Code Online (Sandbox Code Playgroud)

  • 因此,一旦达到启动 perl 的初始开销,perl 解决方案(sid_com)基本上是最快的。(从一次小重复的 59 毫秒到一百万次重复的 67 毫秒……因此 Perl 分叉在您的系统上大约花费了 59 毫秒) (2认同)

Eug*_*ash 43

有不止一种方法可以做到这一点.

使用循环:

使用printf内置:

printf '=%.0s' {1..100}
Run Code Online (Sandbox Code Playgroud)

在此处指定精度会截断字符串以适合指定的宽度(0).由于printf重用格式字符串消耗所有的参数,这只是简单地打印"="100次.

使用head(printf等)和tr:

head -c 100 < /dev/zero | tr '\0' '='
printf %100s | tr " " "="
Run Code Online (Sandbox Code Playgroud)

  • ++用于`head` /`tr`解决方案,即使在重复次数很高的情况下也能很好地工作(小警告:`head -c`不符合POSIX,但是BSD和GNU`head`都实现了它);尽管其他两种解决方案在这种情况下会很慢,但它们的确也具有使用_multi_字符字符串的优势。 (2认同)

Sam*_*ury 28

我刚刚使用seq找到了一种非常简单的方法:

更新:这适用于seqOS X附带的BSD.YMMV与其他版本

seq  -f "#" -s '' 10
Run Code Online (Sandbox Code Playgroud)

将'#'打印10次,如下所示:

##########
Run Code Online (Sandbox Code Playgroud)
  • -f "#"设置格式字符串以忽略数字,并#为每个数字打印.
  • -s '' 将分隔符设置为空字符串以删除seq在每个数字之间插入的换行符
  • 后的空间-f-s似乎是非常重要的.

编辑:这是一个方便的功能......

repeat () {
    seq  -f $1 -s '' $2; echo
}
Run Code Online (Sandbox Code Playgroud)

你可以这样打电话......

repeat "#" 10
Run Code Online (Sandbox Code Playgroud)

注意:如果您重复,#那么引号很重要!

  • 这给了我`seq:format'#'没有%指令.`seq`是数字,而不是字符串.请参阅https://www.gnu.org/software/coreutils/manual/html_node/seq-invocation.html (7认同)
  • @JohnB:BSD `seq` 被_巧妙地重新用于_这里复制_strings_:格式字符串传递给 `-f` - 通常用于格式化正在生成的 _numbers_ - 仅包含要在此处复制的字符串,以便输出包含该字符串的副本仅字符串。不幸的是,GNU `seq` 坚持在格式字符串中存在 _number format_,这是您看到的错误。 (3认同)

Dig*_*uma 19

这有两个有趣的方法:

ubuntu@ubuntu:~$ yes = | head -10 | paste -s -d '' -
==========
ubuntu@ubuntu:~$ yes = | head -10 | tr -d "\n"
==========ubuntu@ubuntu:~$ 

请注意,这两个略有不同 - 该paste方法以新行结束.该tr方法没有.

  • 做得很好; 请注意 _BSD_ `paste` 莫名其妙地需要 `-d '\0'` 来指定空分隔符,并且会因 `-d ''` 失败 - `-d '\0'` 应该适用于所有 POSIX 兼容的 `paste ` 实现,并且确实也可以与 _GNU_ `paste` 一起使用。 (2认同)

Tim*_*Tim 13

没有简单的方法.避免循环使用printf和替换.

str=$(printf "%40s")
echo ${str// /rep}
# echoes "rep" 40 times.
Run Code Online (Sandbox Code Playgroud)

  • 很好,但只有小的重复计数合理地执行.这是一个函数包装器,可以调用为`repl = 100`,例如(不输出尾随的`\n`):`repl(){local ts = $(printf"%$ {2} s") ; printf%s"$ {ts ///$ 1}"; }` (2认同)

mat*_*l87 9

这是我用来在 linux 中跨屏幕打印一行字符的内容(基于终端/屏幕宽度)

在屏幕上打印“=”:

printf '=%.0s' $(seq 1 $(tput cols))
Run Code Online (Sandbox Code Playgroud)

解释:

打印一个等于给定序列的次数:

printf '=%.0s' #sequence
Run Code Online (Sandbox Code Playgroud)

使用命令的输出(这是一个称为命令替换的 bash 功能):

$(example_command)
Run Code Online (Sandbox Code Playgroud)

给个序列,我以1到20为例。在最后一个命令中,使用 tput 命令而不是 20:

$(example_command)
Run Code Online (Sandbox Code Playgroud)

给出终端当前使用的列数:

seq 1 20
Run Code Online (Sandbox Code Playgroud)


小智 7

#!/usr/bin/awk -f
BEGIN {
  OFS = "="
  NF = 100
  print
}
Run Code Online (Sandbox Code Playgroud)

要么

#!/usr/bin/awk -f
BEGIN {
  while (z++ < 100) printf "="
}
Run Code Online (Sandbox Code Playgroud)

  • 做得很好; 这是POSIX兼容的,即使具有高重复次数也相当快,同时还支持多字符串.这是shell版本:`awk'BEGIN {while(c ++ <100)printf"="}'`.包含在参数化的shell函数中(例如调用`repeat 100 =`):`repeat(){awk -v count ="$ 1"-v txt =".$ 2"'BEGIN {txt = substr(txt,2 ); while(i ++ <count)printf txt}'; }`.(需要使用伪`.`前缀char和补充`substr`调用来解决BSD`awk`中的错误,其中传递_starts_和`=`的变量值会破坏命令.) (3认同)
  • 用户注意 - "original-awk"是非标准的,不推荐使用 (2认同)

Geo*_*xon 7

如果你想POSIX的合规性和一致性跨越不同的实现echoprintf,和/或其他贝壳不仅仅是bash:

seq(){ n=$1; while [ $n -le $2 ]; do echo $n; n=$((n+1)); done ;} # If you don't have it.

echo $(for each in $(seq 1 100); do printf "="; done)
Run Code Online (Sandbox Code Playgroud)

...将产生与perl -E 'say "=" x 100'几乎所有地方相同的输出.


Léa*_*ris 7

另一种将任意字符串重复 n 次的方法:

优点:

  • 适用于 POSIX 外壳。
  • 可以将输出分配给变量。
  • 重复任何字符串。
  • 即使重复非常大,也非常快。

缺点:

  • 需要 Gnu Core Utils 的yes命令。
#!/usr/bin/sh
to_repeat='='
repeat_count=80
yes "$to_repeat" | tr -d '\n' | head -c "$repeat_count"
Run Code Online (Sandbox Code Playgroud)

用一个 ANSI 终端和 US-ASCII 字符来重复。您可以使用 ANSI CSI 转义序列。这是重复字符的最快方法。

#!/usr/bin/env bash

char='='
repeat_count=80
printf '%c\e[%db' "$char" "$repeat_count"
Run Code Online (Sandbox Code Playgroud)

或静态:

打印一行 80 次=

printf '=\e[80b\n'

限制:

  • 并非所有终端都理解repeat_charANSI CSI 序列。
  • 只能重复 US-ASCII 或单字节 ISO 字符。
  • 重复在最后一列停止,因此无论终端宽度如何,您都可以使用大值来填充整行。
  • 重复仅用于显示。将输出捕获到 shell 变量中不会将repeat_charANSI CSI 序列扩展为重复字符。


Ed *_*all 6

另一个使用 printf 和 tr 的 bash 解决方案

注意。在我开始之前:

  • 我们还需要另一个答案吗?可能不会。
  • 这个答案已经在这里了吗?看不到,就到这里吧。

使用 的前导零填充功能printf并使用 转换零tr。这避免了任何{1..N}生成器:

$ printf '%040s' | tr '0' '='
========================================
Run Code Online (Sandbox Code Playgroud)

要将宽度设置为“N”个字符并自定义打印的字符:

#!/usr/bin/env bash
N=40
C='-'
printf "%0${N}s" | tr '0' "${C}"
Run Code Online (Sandbox Code Playgroud)

对于较大的 N,这比生成器的性能要好得多;在我的机器上(bash 3.2.57):

$ time printf '=%.0s' {1..1000000}         real: 0m2.580s
$ time printf '%01000000s' | tr '0' '='    real: 0m0.577s
Run Code Online (Sandbox Code Playgroud)


小智 5

在 bash 3.0 或更高版本中

for i in {1..100};do echo -n =;done
Run Code Online (Sandbox Code Playgroud)


Ste*_*wig 5

我猜这个问题的最初目的是仅使用 shell 的内置命令来执行此操作。因此,for循环和printfs就合法,同时repperl和也jot低于不肯。仍然,以下命令

jot -s "/" -b "\\" $((COLUMNS/2))

例如,打印一个窗口范围的行 \/\/\/\/\/\/\/\/\/\/\/\/

  • 做得很好; 即使重复计数很高(同时还支持多字符串),这也能很好地工作。为了更好地说明该方法,这里是 OP 命令的等价物:`jot -s '' -b '=' 100`。需要注意的是,虽然类似 BSD 的平台(包括 OSX)带有 `jot`,但 _Linux 发行版没有_。 (2认同)

gni*_*urf 5

没有eval,没有子shell,没有外部工具,没有括号扩展的纯Bash方式(即,您可以在变量中重复数字):

如果您得到一个n扩展为(非负)数字的变量和一个变量pattern,例如,

$ n=5
$ pattern=hello
$ printf -v output '%*s' "$n"
$ output=${output// /$pattern}
$ echo "$output"
hellohellohellohellohello
Run Code Online (Sandbox Code Playgroud)

您可以使用以下功能:

repeat() {
    # $1=number of patterns to repeat
    # $2=pattern
    # $3=output variable name
    local tmp
    printf -v tmp '%*s' "$1"
    printf -v "$3" '%s' "${tmp// /$2}"
}
Run Code Online (Sandbox Code Playgroud)

这样设置:

$ repeat 5 hello output
$ echo "$output"
hellohellohellohellohello
Run Code Online (Sandbox Code Playgroud)

对于这个小技巧,我们在以下方面使用printf了很多:

  • -v varnameprintf将格式字符串的内容放入变量中,而不是打印到标准输出中varname
  • '%* s':printf将使用参数打印相应数量的空格。例如,printf '%*s' 42将打印42个空格。
  • 最后,当变量中有所需的空格数时,我们使用参数扩展将所有空格替换为我们的模式:${var// /$pattern}将扩展为,将var所有空格替换为$pattern

您还可以通过使用间接扩展来消除函数中的tmp变量repeat

repeat() {
    # $1=number of patterns to repeat
    # $2=pattern
    # $3=output variable name
    printf -v "$3" '%*s' "$1"
    printf -v "$3" '%s' "${!3// /$2}"
}
Run Code Online (Sandbox Code Playgroud)


Eli*_*gan 5

正如其他人所说,在 bash 中括号扩展先于参数扩展,因此范围只能包含文字。并提供干净的解决方案,但不能完全从一个系统移植到另一个系统,即使您在每个系统上使用相同的 shell。(虽然越来越可用;例如,在 FreeBSD 9.3 和更高版本中。)和其他形式的间接总是有效但有些不雅。{m,n}seqjotseqeval

幸运的是,bash支持 C 风格的 for 循环(仅限算术表达式)。所以这里有一个简洁的“纯 bash”方式:

repecho() { for ((i=0; i<$1; ++i)); do echo -n "$2"; done; echo; }
Run Code Online (Sandbox Code Playgroud)

这将重复次数作为第一个参数,将要重复的字符串(可能是单个字符,如问题描述中所述)作为第二个参数。repecho 7 b输出bbbbbbb(以换行符结束)。

四年前,Dennis Williamson在他在 shell 脚本中创建重复字符字符串的出色回答中基本上给出了这个解决方案。我的函数体与那里的代码略有不同:

  • 由于这里的重点是在重复一个字符和shell是bash,它可能是安全的使用echo,而不是printf。我阅读了这个问题中的问题描述,表示倾向于使用echo. 上述函数定义适用于 bash 和ksh93。虽然printf更便携(通常应该用于这类事情),但它echo的语法可以说更具可读性。

    一些 shell 的echo内置函数将-自身解释为一个选项——尽管 的通常含义-, 使用 stdin 作为输入,对于 来说是无意义的echozsh 就是这样做的。并且肯定存在echo不识别的 s -n,因为它不是标准的。(许多 Bourne 风格的 shell 根本不接受 C 风格的 for 循环,因此echo不需要考虑它们的行为......)

  • 这里的任务是打印序列;在那里,它是将它分配给一个变量。

如果$n是所需的重复次数并且您不必重复使用它,并且您想要更短的东西:

while ((n--)); do echo -n "$s"; done; echo
Run Code Online (Sandbox Code Playgroud)

n必须是一个变量——这种方式不适用于位置参数。$s是要重复的文本。

  • 强烈避免做循环版本。`printf "%100s" | tr ' ' '='` 是最优的。 (2认同)

che*_*ier 5

问题是关于如何处理echo

echo -e ''$_{1..100}'\b='
Run Code Online (Sandbox Code Playgroud)

这将perl -E 'say "=" x 100'echo仅执行相同的操作。

  • [坏主意。](/sf/answers/4114577631/) 如果 `$_1`、`$_2` 或一百个变量中的任何其他变量都有值,这将会失败。 (2认同)
  • @JohnKugelman echo $( set --; eval echo -e \${{1..100}}'\\b=' ) (2认同)