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 =
秒.
小智 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)他们似乎不支持它:)
mkl*_*nt0 45
给@ gniourf_gniourf的帽子提示他的输入.
注意:这个答案并没有回答原来的问题,但补充了由现有的,有用的答案比较性能.
仅在执行速度方面对解决方案进行了比较 - 不考虑内存要求(它们在不同的解决方案中有所不同,并且可能与大的重复计数有关).
摘要:
${var// /=}
)替换Bash的全局子字符串,因为它非常慢.以下是时机了3.2 GHz的英特尔酷睿i5 CPU和融合驱动器,运行OSX 10.10.4和bash 3.2.57在后期2012的iMac采取,并且是1000次运行的平均值.
条目是:
M
......一个潜在的多角色解决方案S
......一个单一字符的解决方案P
...符合POSIX标准的解决方案[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)
awk
和perl
解决方案.[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)
${foo// /=}
)使用大字符串是令人费解的极其缓慢,并且已经被淘汰(在Bash 4.3.30中花了大约50分钟(!),在Bash 3.2.57中花了更长时间 - 我从未等待过它完成).(( 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)
Eug*_*ash 43
有不止一种方法可以做到这一点.
使用循环:
大括号扩展可以与整数文字一起使用:
for i in {1..100}; do echo -n =; done
Run Code Online (Sandbox Code Playgroud)类似C的循环允许使用变量:
start=1
end=100
for ((i=$start; i<=$end; i++)); do echo -n =; done
Run Code Online (Sandbox Code Playgroud)使用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)
Sam*_*ury 28
我刚刚使用seq找到了一种非常简单的方法:
更新:这适用于seq
OS 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)
注意:如果您重复,#
那么引号很重要!
Dig*_*uma 19
这有两个有趣的方法:
ubuntu@ubuntu:~$ yes = | head -10 | paste -s -d '' - ========== ubuntu@ubuntu:~$ yes = | head -10 | tr -d "\n" ==========ubuntu@ubuntu:~$
请注意,这两个略有不同 - 该paste
方法以新行结束.该tr
方法没有.
Tim*_*Tim 13
没有简单的方法.避免循环使用printf
和替换.
str=$(printf "%40s")
echo ${str// /rep}
# echoes "rep" 40 times.
Run Code Online (Sandbox Code Playgroud)
这是我用来在 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的合规性和一致性跨越不同的实现echo
和printf
,和/或其他贝壳不仅仅是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'
几乎所有地方相同的输出.
另一种将任意字符串重复 n 次的方法:
优点:
缺点:
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_char
ANSI CSI 序列。repeat_char
ANSI CSI 序列扩展为重复字符。另一个使用 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)
我猜这个问题的最初目的是仅使用 shell 的内置命令来执行此操作。因此,for
循环和printf
s就合法,同时rep
,perl
和也jot
低于不肯。仍然,以下命令
jot -s "/" -b "\\" $((COLUMNS/2))
例如,打印一个窗口范围的行 \/\/\/\/\/\/\/\/\/\/\/\/
没有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 varname
:printf
将格式字符串的内容放入变量中,而不是打印到标准输出中varname
。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)
正如其他人所说,在 bash 中括号扩展先于参数扩展,因此范围只能包含文字。并提供干净的解决方案,但不能完全从一个系统移植到另一个系统,即使您在每个系统上使用相同的 shell。(虽然越来越可用;例如,在 FreeBSD 9.3 和更高版本中。)和其他形式的间接总是有效但有些不雅。{m,n}
seq
jot
seq
eval
幸运的是,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 作为输入,对于 来说是无意义的echo
。zsh 就是这样做的。并且肯定存在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
是要重复的文本。
问题是关于如何处理echo
:
echo -e ''$_{1..100}'\b='
Run Code Online (Sandbox Code Playgroud)
这将perl -E 'say "=" x 100'
与echo
仅执行相同的操作。