どうすればこれを行うことができecho
ますか?
perl -E 'say "=" x 100'
ruby -e 'puts "=" * 100'
ものpython -c 'print "=" * 100'
printf
してseq
)svrb=`printf '%.sv' $(seq $vrb)`
どうすればこれを行うことができecho
ますか?
perl -E 'say "=" x 100'
ruby -e 'puts "=" * 100'
ものpython -c 'print "=" * 100'
printf
してseq
)svrb=`printf '%.sv' $(seq $vrb)`
回答:
以下を使用できます。
printf '=%.0s' {1..100}
仕組み:
Bashは{1..100}を展開するため、コマンドは次のようになります。
printf '=%.0s' 1 2 3 4 ... 100
私はprintfのフォーマットを設定しました。これは、与えられた引数に関係なく=%.0s
、常に1つを出力することを意味し=
ます。したがって、100 =
秒印刷されます。
repl = 100
インスタンスのためには、(eval
策略は変数のブレース展開を基づかため、残念ながら、必要とされる):repl() { printf "$1"'%.s' $(eval "echo {1.."$(($2))"}"); }
seq
代わりに使用してください$(seq 1 $limit)
。
$s%.0s
する%.0s$s
場合、それをからに再配置することをお勧めしprintf
ます。そうしないと、ダッシュがエラーの原因になります。
printf
。引数がなくなるまで、フォーマット文字列を適用し続けます。私はそれがフォーマット文字列を一度だけ処理すると仮定していました!
簡単な方法はありません。しかし、例えば:
seq -s= 100|tr -d '[:digit:]'
または、おそらく標準に準拠した方法:
printf %100s |tr " " "="
もありますがtput rep
、私の手元の端末(xtermとlinux)はサポートしていないようです:)
=
文字を印刷します。
printf
tr
とはPOSIX ではないためseq
、これが唯一のPOSIXソリューションです。yes
{1..3}
printf %100s | sed 's/ /abc/g'
-「abcabcabc ...」を出力します
tr
)のみを使用する場合は+1 。また、に拡張することもできprintf "%${COLUMNS}s\n" | tr " " "="
ます。
wc
。私がこれから得ることができる唯一の結論は「seq
使用されるべきではない」です。
彼の入力のための@ gniourf_gniourfへの帽子の先端。
注:この回答は元の質問には答えませんが、パフォーマンスを比較することにより、既存の役立つ回答を補足します。
ソリューションは実行速度のみで比較されます-メモリー要件は考慮されません(ソリューションによって異なり、繰り返し回数が多い場合に問題になることがあります)。
概要:
${var// /=}
)で置き換えることは、非常に遅いため避けてください。以下はタイミングです、OSX 10.10.4とbash 3.2.57を実行し、3.2 GHz Intel Core i5 CPUとFusion Driveを搭載した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
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
${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
In order to use brace expansion with a variable, we must use `eval`
👍
それを行うには複数の方法があります。
ループを使用する:
ブレース展開は整数リテラルで使用できます。
for i in {1..100}; do echo -n =; done
Cのようなループでは、変数を使用できます。
start=1
end=100
for ((i=$start; i<=$end; i++)); do echo -n =; done
printf
組み込みを使用する:
printf '=%.0s' {1..100}
ここで精度を指定すると、指定した幅(0
)に合わせて文字列が切り捨てられます。printf
すべての引数を消費するフォーマット文字列を再利用し、これは単純に印刷し"="
100回。
使用head
(printf
など)とtr
:
head -c 100 < /dev/zero | tr '\0' '='
printf %100s | tr " " "="
head
/ tr
ソリューションの++は、繰り返し回数が多い場合でもうまく機能します(小さな注意:head -c
POSIXに準拠していませんが、BSDとGNUの両方でhead
実装されています)。その場合、他の2つのソリューションは遅くなりますが、複数文字の文字列を処理するという利点もあります。
yes
とhead
、特定の数の改行が必要な場合に役立ちますyes "" | head -n 100
。tr
任意の文字を印刷できます:yes "" | head -n 100 | tr "\n" "="; echo
dd if=/dev/zero count=1 bs=100000000 | tr '\0' '=' >/dev/null
よりもかなり遅いですhead -c100000000 < /dev/zero | tr '\0' '=' >/dev/null
。もちろん、時間差を合理的に測定するには、100M +のブロックサイズを使用する必要があります。100Mバイトには1.7秒と1秒かかり、2つのバージョンが示されています。私はtrを外してダンプした/dev/null
ところ、head
バージョンが0.287秒、バージョンが0.675秒dd
、10億バイトでした。
dd if=/dev/zero count=1 bs=100000000 | tr '\0' '=' >/dev/null
=> 0,21332 s, 469 MB/s
; 対象:dd if=/dev/zero count=100 bs=1000000| tr '\0' '=' >/dev/null
=> 0,161579 s, 619 MB/s
;
seqを使用してこれを行う非常に簡単な方法を見つけました。
更新:これseq
はOS Xに付属するBSD で動作します。他のバージョンのYMMV
seq -f "#" -s '' 10
次のように、「#」を10回出力します。
##########
-f "#"
数字を無視して、#
それぞれについて出力するだけのフォーマット文字列を設定します。-s ''
区切り文字を空の文字列に設定して、seqが各数値の間に挿入する改行を削除します-f
と後のスペースは-s
重要なようです。編集:これは便利な機能です...
repeat () {
seq -f $1 -s '' $2; echo
}
あなたはこのように呼ぶことができます...
repeat "#" 10
注:繰り返す#
場合は、引用符が重要です!
seq: format ‘#’ has no % directive
。 seq
文字列ではなく数値用です。gnu.org/software/coreutils/manual/html_node/seq-invocation.html
seq
は文字列を複製するためにここで巧妙に転用されています:渡されるフォーマット文字列-f
-通常は生成される数値をフォーマットするために使用されます-ここに複製する文字列のみが含まれるため、出力にはその文字列のコピーのみが含まれます。残念ながら、GNU は、表示されているエラーであるフォーマット文字列に数値フォーマットがseq
存在することを要求しています。
"$1"
(二重引用符)を使用してください'*'
。空白文字が埋め込まれた文字列やなどの文字を渡すこともできます。最後に、を使用できるようにするには%
、それを2倍にする必要があります(それ以外の場合seq
は、のような形式仕様の一部と見なされます%f
)。使用"${1//%/%%}"
することでそれを処理できます。あなたが使っている(あなたが言及したように)のでBSDを seq
、これは一般的にはBSDライクなOS上で動作します(例えば、FreeBSDの) -対照的に、それはLinux上で動作しません、GNUが seq
使用されています。
ここに2つの興味深い方法があります。
ubuntu @ ubuntu:〜$はい= | 頭-10 | 貼り付け-s -d ''- ========== ubuntu @ ubuntu:〜$はい= | 頭-10 | tr -d "\ n" ========== ubuntu @ ubuntu:〜$
これら2つは微妙に異なることに注意してください- paste
メソッドは新しい行で終わります。tr
この方法にはありません。
paste
不可解に必要-d '\0'
であり、失敗することに注意してください-d ''
- -d '\0'
すべてのPOSIX互換のpaste
実装で動作し、GNU paste
でも動作するはずです。
yes | mapfile -n 100 -C 'printf = \#' -c 1
time yes = | head -500 | paste -s -d '\0' -; time yes | mapfile -n 500 -C 'printf = \#' -c 1
。さらに重要なことは、しかし:あなたが使用している場合はprintf
、とにかく、あなたにも受け入れ答えから両方のシンプルでより効率的なアプローチで行くことがあります。printf '%.s=' $(seq 500)
簡単な方法はありません。ループの使用printf
と置換を避けます。
str=$(printf "%40s")
echo ${str// /rep}
# echoes "rep" 40 times.
repl = 100
(出力は、後続しないたとえば、\n
:)repl() { local ts=$(printf "%${2}s"); printf %s "${ts// /$1}"; }
あなたはの異なる実装間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)
... perl -E 'say "=" x 100'
ほぼどこでも同じ出力を生成します。
seq
、POSIXユーティリティではないことです(BSDおよびLinuxシステムには実装されていますが)- while
@ Xennex81の回答のように、代わりにループを使用してPOSIXシェル演算を実行できます(ではなく、printf "="
正しく提案されているecho -n
)。
cal
POSIXです。seq
ではありません。とにかく、whileループで答えを書き直すのではなく(言ったように、それは他の答えに既にあります)、RYO関数を追加します。その方法でより教育的です;-)。
問題はそれをどのように行うかについてでしたecho
:
echo -e ''$_{1..100}'\b='
これはまったく同じことを行いますperl -E 'say "=" x 100'
が、それecho
だけです。
なしeval
、サブシェルなし、外部ツールなし、ブレース展開なしの純粋なBash方法(つまり、変数内で繰り返す数を指定できます):
n
(負ではない)数に展開する変数と変数が与えられた場合pattern
、例えば、
$ n=5
$ pattern=hello
$ printf -v output '%*s' "$n"
$ output=${output// /$pattern}
$ echo "$output"
hellohellohellohellohello
あなたはこれで関数を作ることができます:
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}"
}
このセットで:
$ repeat 5 hello output
$ echo "$output"
hellohellohellohellohello
この小さなトリックのために、私たちは次のもので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}"
}
bash
パラメータ展開(の文脈でのグローバルな文字列置換操作${var//old/new}
耐え難いほど遅いのbashで:特に遅い)3.2.57
、およびbashで遅く4.3.30
少なくとも3.2 GHzのインテルCore i5のマシン上で私のOSX 10.10.3システム上で、:でカウントが1,000、物事が遅い(3.2.57
)/速い(4.3.30
):0.1 / 0.004秒。カウントを10,000に増やすと、著しく異なる数値が生成されます。bashで repeat 10000 = var
約80秒(!)かかり、bash 3.2.57
で約0.3秒かかります4.3.30
(onよりはるかに高速ですが3.2.57
、それでも低速です)。
#!/usr/bin/awk -f
BEGIN {
OFS = "="
NF = 100
print
}
または
#!/usr/bin/awk -f
BEGIN {
while (z++ < 100) printf "="
}
awk 'BEGIN { while (c++ < 100) printf "=" }'
です。(呼出しとしてパラメータシェル関数にラップrepeat 100 =
例えば、) repeat() { awk -v count="$1" -v txt=".$2" 'BEGIN { txt=substr(txt, 2); while (i++ < count) printf txt }'; }
。(BSDのバグを回避するには.
、ダミーのプレフィックスcharと補完的なsubstr
呼び出しが必要ですawk
=
NF = 100
解決策は、(100を取得するためにかかわらず、非常に賢いです=
、あなたが使用する必要がありますNF = 101
)。注意点は、BSDをクラッシュさせることですawk
(ただし、を使用すると非常に高速にgawk
なり、さらに高速になりますmawk
)。POSIXでは、ブロック内のフィールドへの割り当てNF
や使用については説明されていませんBEGIN
。BSD awk
でも同様に微調整することで機能させることができますawk 'BEGIN { OFS = "="; $101=""; print }'
(ただし、奇妙なことに、BSD awk
ではループソリューションよりも高速ではありません)。パラメータ化されたシェルの解決策として:repeat() { awk -v count="$1" -v txt=".$2" 'BEGIN { OFS=substr(txt, 2); $(count+1)=""; print }'; }
。
original-awk
は、BSDのawkに似た古いawkのLinuxでの名前であり、これを試すとクラッシュすることが報告されています。通常、クラッシュは悪用可能なバグを見つけるための最初のステップです。この答えは、安全でないコードを非常に促進しています。
original-awk
非標準であり、推奨されません
awk NF=100 OFS='=' <<< ""
(bash
およびを使用gawk
)を使用できます
質問の元々の目的は、シェルの組み込みコマンドだけでこれを行うことだったと思います。だからfor
、ループおよびprintf
sは、正当であろうがrep
、perl
とにもjot
以下ではないだろう。それでも、次のコマンド
jot -s "/" -b "\\" $((COLUMNS/2))
たとえば、ウィンドウ全体の行を出力します \/\/\/\/\/\/\/\/\/\/\/\/
jot -s '' -b '=' 100
。OSXを含むBSD風のプラットフォームにはが付属しているのjot
に対し、Linuxディストリビューションには付属していないことに注意してください。
apt install athena-jot
は、を提供しますjot
。
他の人が言ったように、bashでは中括弧の展開はパラメータの展開の前に行われるため、範囲にはリテラルのみを含めることができます。また、クリーンなソリューションを提供しますが、それぞれに同じシェルを使用している場合でも、システム間での完全な移植性はありません。(ただし、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; }
これは、最初の引数として繰り返しの数を取り、2番目の引数として繰り返される文字列(問題の説明のように、単一の文字である場合があります)を取ります。repecho 7 b
出力bbbbbbb
(改行で終了)。
デニスウィリアムソンは、基本的にこの解決策を4年前にシェルスクリプトで繰り返し文字列を作成することに対する彼の優れた答えで与えました。私の関数本体はそこでのコードと少し異なります:
ここでの焦点は単一の文字を繰り返すことにあり、シェルはbashであるため、のecho
代わりに使用することはおそらく安全ですprintf
。そして、私はこの質問の問題の説明を、を使用して印刷することを好むことを表現していると読みましたecho
。上記の関数定義は、bashおよびksh93で機能します。printf
より移植性がありますが(通常、この種のものに使用する必要があります)、echo
の構文は間違いなく読みやすくなっています。
一部のシェルのecho
組み込みコマンドは-
、それ自体をオプションとして解釈します。ただし、-
入力にstdinを使用するというの通常の意味は、には意味がありませんecho
。zshはこれを行います。そして、それは標準ではないので、それをecho
認識しないものは確かに存在します。(多くのBourneスタイルのシェルは、Cスタイルのforループをまったく受け入れないため、その動作を考慮する必要はありません。)-n
echo
ここでのタスクはシーケンスを印刷することです。そこで、それを変数に割り当てることでした。
もしは$n
繰り返し、所望の数であり、あなたはそれを再利用する必要はありません、あなたも短く何かをしたいです:
while ((n--)); do echo -n "$s"; done; echo
n
変数でなければなりません-この方法は位置パラメータでは機能しません。$s
繰り返されるテキストです。
printf "%100s" | tr ' ' '='
最適です。
zsh
。echo-in-a-loopアプローチは、繰り返し回数が少ない場合にうまく機能しますが、@ Slomojoのコメントで証明されているように、繰り返し回数が多い場合は、ユーティリティに基づくPOSIX準拠の代替手段があります。
echo
をサポートするビルトインがあります-n
。あなたの言っている精神は完全に正しいです。printf
ほとんどの場合echo
、少なくとも非インタラクティブな使用では、が優先されます。しかしecho
、質問をし、それが機能することを知るのに十分な情報を提供してくれた質問に回答するのは、決して不適切でも誤解を招くものでもないと思います。((n--))
(なしの$
)のサポート自体は、POSIXでは保証されないことにも注意してください。
Pythonはユビキタスであり、どこでも同じように動作します。
python -c "import sys; print('*' * int(sys.argv[1]))" "=" 100
文字とカウントは別々のパラメーターとして渡されます。
python -c "import sys; print(sys.argv[1] * int(sys.argv[2]))" "=" 100
任意の文字列をn回繰り返す別の方法:
長所:
短所:
yes
コマンドが必要です。#!/usr/bin/sh
to_repeat='='
repeat_count=80
yes "$to_repeat" | tr -d '\n' | head -c "$repeat_count"
ANSI端末とUS-ASCII文字を繰り返します。ANSI CSIエスケープシーケンスを使用できます。これは、文字を繰り返す最も速い方法です。
#!/usr/bin/env bash
char='='
repeat_count=80
printf '%c\e[%db' "$char" "$repeat_count"
または静的に:
80回の行を印刷します=
。
printf '=\e[80b\n'
制限:
repeat_char
ANSI CSIシーケンスを理解するわけではありません。repeat_char
しても、ANSI CSIシーケンスは繰り返される文字に展開されません。これは、Linuxの画面全体に文字の行を印刷するために使用するものです(ターミナル/画面の幅に基づく)。
printf '=%.0s' $(seq 1 $(tput cols))
説明:
指定されたシーケンスと同じ回数だけ等号を出力します。
printf '=%.0s' #sequence
コマンドの出力を使用します(これはコマンド置換と呼ばれるbash機能です):
$(example_command)
シーケンスを示します。例として1〜20を使用しました。最後のコマンドでは、20の代わりにtputコマンドが使用されています。
seq 1 20
端末で現在使用されている列の数を指定します。
tput cols
for i in {1..100}
do
echo -n '='
done
echo
提案されたPythonソリューションのよりエレガントな代替案は次のとおりです。
python -c 'print "="*(1000)'
文字をn回繰り返す場合は、たとえば、実行できる文字列の長さに応じてVARIABLE回数を繰り返します。
#!/bin/bash
vari='AB'
n=$(expr 10 - length $vari)
echo 'vari equals.............................: '$vari
echo 'Up to 10 positions I must fill with.....: '$n' equal signs'
echo $vari$(perl -E 'say "=" x '$n)
表示されます:
vari equals.............................: AB
Up to 10 positions I must fill with.....: 8 equal signs
AB========
length
で動作しませんexpr
、あなたはおそらく意味しましたn=$(expr 10 - ${#vari})
; ただし、Bashの算術展開を使用する方が簡単で効率的ですn=$(( 10 - ${#vari} ))
。また、あなたの答えの中核にあるのは、OPがBashの代替を探しているまさにPerlのアプローチです 。
function repeatString()
{
local -r string="${1}"
local -r numberToRepeat="${2}"
if [[ "${string}" != '' && "${numberToRepeat}" =~ ^[1-9][0-9]*$ ]]
then
local -r result="$(printf "%${numberToRepeat}s")"
echo -e "${result// /${string}}"
fi
}
サンプルの実行
$ repeatString 'a1' 10
a1a1a1a1a1a1a1a1a1a1
$ repeatString 'a1' 0
$ repeatString '' 10
参照ライブラリ:https : //github.com/gdbtek/linux-cookbooks/blob/master/libraries/util.bash
私の答えはもう少し複雑で、おそらく完璧ではありませんが、大きな数を出力したい人にとっては、3秒で約1000万回実行できました。
repeatString(){
# argument 1: The string to print
# argument 2: The number of times to print
stringToPrint=$1
length=$2
# Find the largest integer value of x in 2^x=(number of times to repeat) using logarithms
power=`echo "l(${length})/l(2)" | bc -l`
power=`echo "scale=0; ${power}/1" | bc`
# Get the difference between the length and 2^x
diff=`echo "${length} - 2^${power}" | bc`
# Double the string length to the power of x
for i in `seq "${power}"`; do
stringToPrint="${stringToPrint}${stringToPrint}"
done
#Since we know that the string is now at least bigger than half the total, grab however many more we need and add it to the string.
stringToPrint="${stringToPrint}${stringToPrint:0:${diff}}"
echo ${stringToPrint}
}
ほとんどの既存のソリューションはすべて{1..10}
、シェルの構文サポートに依存しています。これはbash
-およびzsh
-固有のものでありtcsh
、OpenBSD ksh
やほとんどの非bash では機能しません。sh
。
以下は、OS Xおよびすべての* BSDシステムで動作します。実際、さまざまなタイプの装飾スペースのマトリックス全体を生成するために使用できます。
$ printf '=%.0s' `jot 64` | fold -16
================
================
================
================$
悲しいことに、末尾の改行はありません。printf '\n'
折りたたみ後にエキストラで修正できます:
$ printf "=%.0s" `jot 64` | fold -16 ; printf "\n"
================
================
================
================
$
参照:
私の提案(nの変数値を受け入れる):
n=100
seq 1 $n | xargs -I {} printf =