在Bash中重复打印一个字符

80

有没有办法在bash中重复打印相同的字符,就像你可以使用以下构造在python中做到这一点:

print('%' * 3)

提供

%%%

最短 + 最快 + 最大兼容性 printf %9s|tr ' ' '\n' - user5490177
9个回答

193

实际上有一个只需一行代码就能完成的方法:

    printf "%0.s-" {1..10}

打印

    ----------
这里是传递给 printf 的参数的详细分解:
  • %s - 这指定了任意长度的字符串
  • %0s - 这指定了长度为零的字符串,但如果参数更长,则会打印整个字符串
  • %0.s - 这与上面相同,但句点告诉 printf 如果字符串超过了指定的长度(为零),则截断字符串
  • {1..10} - 这是花括号扩展,实际上传递了参数 "1 2 3 4 5 6 7 8 9 10"
  • "-" - 这是提供给 printf 的额外字符,它可以是任何字符(对于“%”必须先用另一个“%”转义它,即“%%”)
  • 最后,如果您在格式字符串中指定的参数数量比给出的参数多,则 printf 的默认行为是返回到格式字符串开头并再次运行它。
因此这里的最终结果是告诉 printf ,如果提供的字符串长度大于零,则要求它打印一个长度为零且没有额外字符的字符串。然后在这个零长度字符串后面打印一个“-”(或其他任何一组字符)。接着您提供了 10 个参数,因此它会打印 10 个长度为零的字符串,每个字符串后面都有一个“-”。
这是一行代码,可以打印任意数量的重复字符!
编辑:
巧合的是,如果您想打印 $variable 字符,只需稍微更改参数,使用 seq 而不是花括号扩展,如下所示:
    printf '%0.s-' $(seq 1 $variable)

这将传递参数"1 2 3 4 ... $ variable"给printf,精确打印$variable个"-"实例。


7
很好,但这在 #!/bin/sh 中不起作用,只能在 #!/bin/bash 中使用。 - Daniele Vrut
2
由于这个方法使用了bash内置函数,对于重复字符数量较少的情况下,它应该比生成外部进程的方法更快。但是对于大量字符的情况,使用printf '%*s' 1000000 ''|tr ' ' '-'和其他方法会更快。 - Deadcode
2
因为我需要在密码破解程序中创建一个包含1,000,000个单词的单词表来进行性能测试,所以我看到了这个问题以及许多类似的问题。 - Hashim Aziz
1
作为示例,@jww {1..10} 打印了 10 次,如果要打印 3 次,则为 {1..3},如果您想要打印 $n 次,其中 $n = 3,则可以执行 printf '%0.s-' $(seq 1 $n) - CaffeineConnoisseur
1
稍作更正:0 是一个宽度说明符,用于指定最小长度。然后您提供了一个空的精度说明符 .(而不是 .#),它指定了最大宽度为 0。因此,您可以写成 printf '%.s-',因为宽度说明符是多余的。 - Qualia
显示剩余5条评论

58

当然可以,只需使用printf和一些bash字符串操作即可。

$ s=$(printf "%-30s" "*")
$ echo "${s// /*}"
******************************

可能有更简短的方法,但目前我会这样做。你可以将其制作成一个函数,以便将来存储在库中供使用。

printf_new() {
 str=$1
 num=$2
 v=$(printf "%-${num}s" "$str")
 echo "${v// /*}"
}

测试运行:

$ printf_new "*" 20
********************
$ printf_new "*" 10
**********
$ printf_new "%" 10
%%%%%%%%%%

5
如果使用printf -v,您可以避免在此处使用子shell。 printf -v str'%-30s'' '; echo "${str // /*}" - kojiro
2
这个非常慢,特别是对于大于1000个字符的情况。几乎任何东西都比它快,包括使用 printf '%.s*' {1..30} 或者对于大数字使用 printf '%*s' 1000000 ''|tr ' ' '*' - Deadcode
2
printf_new 在第三次测试运行时失败了。我会这样修复它:printf -v v "%-*s" "$num" ""; echo "${v// /$str}" - jarno
4
在Bash中实现这些琐碎的事情让我感到非常沮丧。 - ipeacocks

34

这个问题目前被接受的答案(由 ghostdog74提供)的方法,在字符数较高的情况下执行速度极慢。得票最高的答案(由 CaffeineConnoisseur)更好一些,但仍然相当缓慢。

在我的测试中,以下方法是执行速度最快的(甚至比Python版本还要快):

perl -E "print '*' x 1000"

第二名是Python命令:

python -c "print('*' * 1000)"
如果没有perl或python可用,那么这是第三好的选择:
head -c 1000 /dev/zero | tr '\0' '*'

第四名是使用 bash 中的 printf 内置命令及 tr 命令:

printf '%*s' 1000 | tr ' ' '*'

这里有一个来自CaffeineConnoisseur的答案,在处理大量重复字符时排名第五,但在处理少量字符时可能更快(因为它仅使用内置的bash命令,而不会产生外部进程):

printf '%.s*' {1..1000}

假设 * 是要输出的字符,在最后一个例子中,前面的 %.s 的目的是什么? - Hashim Aziz
"%s" 是 printf 的格式规范,简单地意味着字符串。在 "%" 和 "s" 之间,您可以为字符串设置长度属性。使用 "." 或 ".0" 将最大字符串长度设置为零,对于该字符串不打印任何内容。在此示例中,范围扩展为 1 2 3 4 5 ..... 98 99 100,并且将每个数字视为零长度字符串。这就是如何控制打印的星号数量。 - user.friendly
将重复的字符串转换为字符串变量,请使用以下命令: str=\perl -E "print '*' x 1000"`` - PeterK

15
我很喜欢这个:

我很喜欢这个:

echo $(yes % | head -n3)

你可能不喜欢这个:

for ((i=0; i<3; i++)){
   echo -ne "%"
}

你可能会喜欢这个:

s=$( printf "%3s" ); echo " ${s// /%}"

来源:http://dbaspot.com/shell/357767-bash-fast-way-repeat-string.html

还有这种形式,但并不是很有用:

echo %{,,}

9
+1表示支持“yes”和“head”结合的想法。 - fmark
那就是人们现在使用的!我去寻找/dev/y,但在我的现代系统上找不到它。 - Jeremy J Starcher
你8年前发布的链接已经过时,请编辑或彻底删除它,因为它会重定向到一个看起来可疑的网站... - gboffi

5

虽然不太美观,但你可以这样做:

$ for a in `seq 5`; do echo -n %; done
%%%%%

当然,seq 是一个外部程序(你很可能已经拥有了)。

2
为什么要使用另一个程序,当你可以简单地写:for a in {1..5}; do echo -n %; done - Daniele Vrut
1
我自己发现在脚本中,我的“解决方案”不起作用,这里提供你的解决方案。 - Daniele Vrut
-1. 比 printf "%0.s%%" {1..5} 慢,而后者比 printf '%*s' 5 ''|tr ' ' '%' 还要慢。 - Deadcode
5
@Deadcode中的-1一般用于表示错误的答案,而不是低效的答案。可能有其他完成此操作的方式,但这是完全有效的方法... - War10ck

3
  1. It is possible to obtain any number of zero (\0) character from /dev/zero. The only thing left to do it is

    head -c 20 /dev/zero |tr '\0' '+'
    

    Note that head and tr are external commands. So that it would be invoked in separate process.

  2. It is possible to "optimize" this solution with string caching.

    CACHE="$(head -c 1000 /dev/zero |tr '\0' '+')"
    echo "${CACHE:0:10}"
    echo "${CACHE:0:100}"
    echo "${CACHE:0:300}"
    

    There are only bash built-ins in the echo statement. So, we can use it in cycle.


2

另一个:

char='%'
count=5
result=$( printf "%${count}s" ' ' )
echo -e ${result// /$char}

1
#!/usr/bin/awk -f
BEGIN {
  while (c++ < 3) printf "%"
}

结果

%%%

0

这是最简单的方法

seq -s % 4|tr -d '[:digit:]'

请注意,创建的序列中只会有3个“%”符号。


-1. 打印一个前导换行符,打印比传递的数字少一个字符,并且比 printf '%*s' 3 ''|tr ' ' '%' 慢。 - Deadcode

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接