Bunu nasıl yapabilirim echo
?
perl -E 'say "=" x 100'
ruby -e 'puts "=" * 100'
ya dapython -c 'print "=" * 100'
printf
ile seq
)svrb=`printf '%.sv' $(seq $vrb)`
Bunu nasıl yapabilirim echo
?
perl -E 'say "=" x 100'
ruby -e 'puts "=" * 100'
ya dapython -c 'print "=" * 100'
printf
ile seq
)svrb=`printf '%.sv' $(seq $vrb)`
Yanıtlar:
Kullanabilirsiniz:
printf '=%.0s' {1..100}
Bu nasıl çalışır:
Bash {1..100} 'i genişletir, böylece komut şöyle olur:
printf '=%.0s' 1 2 3 4 ... 100
Printf'in formatını ayarladım =%.0s
, yani =
hangi argümanın verildiğine bakılmaksızın her zaman tek bir baskı yapacak . Bu nedenle 100 =
s yazdırır .
repl = 100
(örneğin, eval
bir değişken üzerinde ayracı genişlemesini dayandırılması için hile maalesef gereklidir):repl() { printf "$1"'%.s' $(eval "echo {1.."$(($2))"}"); }
seq
mesela yerine $(seq 1 $limit)
.
$s%.0s
için %.0s$s
aksi tire bir sebep printf
hatası.
printf
etti: hiçbir argüman kalmayıncaya kadar format dizesini uygulamaya devam ediyor. Biçim dizesini yalnızca bir kez işlediğini varsaymıştım!
Kolay yolu yok. Ancak, örneğin:
seq -s= 100|tr -d '[:digit:]'
Ya da belki standartlara uygun bir yol:
printf %100s |tr " " "="
Bir de var tput rep
, ama eldeki terminallerim için (xterm ve linux) desteklemiyorlar :)
=
karakter basacaktır .
printf
tr
Çünkü sadece POSIX çözümdür seq
, yes
ve {1..3}
POSIX değildir.
printf %100s | sed 's/ /abc/g'
- 'abcabcabc ...' çıktıları
tr
) kullanmak için +1 . Ayrıca böyle bir şeye genişletebilirsiniz printf "%${COLUMNS}s\n" | tr " " "="
.
wc
. Bundan alabileceğim tek sonuç " seq
kullanılmamalı" dır .
@ Gniourf_gniourf girişi için şapka ucu .
Not: Bu cevap vermez değil orijinal soruya cevap ancak tamamlar tarafından mevcut, faydalı cevaplar performansını karşılaştıran .
Çözümler edilir sadece yürütme hızı açısından karşılaştırıldığında - bellek gereksinimleri vardır değil hesabı (onlar çözümleri arasında farklılık ve büyük tekrarlama sayıları ile fark olabilir) önünde.
Özet:
${var// /=}
) Küresel alt dize değiştirme işleminden kaçınılmalıdır , çünkü yasaklanmıştır.Aşağıdaki zamanlamalar OSX 10.10.4 ve bash 3.2.57 çalıştıran bir 3.2 GHz Intel Core i5 CPU ve Fusion Drive, bir geç-2012 iMac alınan ve 1000 koşular ortalamasıdır.
Girişler:
M
... potansiyel olarak çok karakterli bir çözümS
... tek karakterli bir çözümP
... POSIX uyumlu bir çözüm[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
ve perl
çözümlerden kaçının .[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// /=}
), büyük dizelerle açıklanamaz derecede yavaştır ve Bash 4.3.30'da (50 dakika (!) Ve Bash 3.2.57'de daha da uzun sürdü - hiç beklemedim bitirmek için).(( i= 0; ... ))
) küme ayracı genişletilmiş olanlardan ( {1..n}
) daha yavaştır - aritmetik döngüler daha fazla bellek verimlidir.awk
anlamına gelir BSD awk
(ayrıca OSX'te bulunduğu gibi) - gözle görülür şekilde daha yavaş olduğunu gawk
(GNU AWK) ve özelliklemawk
.İşte Bash komut ( testrepeat
yukarıda üretilen). 2 argüman alır:
Başka bir deyişle: yukarıdaki zamanlamalar testrepeat 100 1000
vetestrepeat 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`
👍
Bunu yapmanın birden fazla yolu var.
Bir döngü kullanma:
Brace genişletmesi tamsayı değişmez değerleri ile kullanılabilir:
for i in {1..100}; do echo -n =; done
C benzeri bir döngü değişkenlerin kullanımına izin verir:
start=1
end=100
for ((i=$start; i<=$end; i++)); do echo -n =; done
Yerleşik kullanımı printf
:
printf '=%.0s' {1..100}
Burada bir hassasiyet belirtilmesi, dizeyi belirtilen genişliğe ( 0
) uyacak şekilde keser . Gibi printf
tekrar kullanım biçimi dize bu basitçe yazdırır tüm argüman tüketmeye "="
100 kez.
Kullanılması head
( printf
vs) ve tr
:
head -c 100 < /dev/zero | tr '\0' '='
printf %100s | tr " " "="
head
/ tr
çözüm için (küçük uyarı: head -c
POSIX uyumlu değildir, ancak hem BSD hem de GNU head
uygular); bu durumda diğer iki çözüm yavaş olsa da, çok karakterli dizelerle de çalışma avantajına sahiptirler .
yes
ve head
- kullanışlı sen satırbaşıyla belirli sayıda istiyorsanız: yes "" | head -n 100
. tr
herhangi bir karakteri yazdırabilirsiniz:yes "" | head -n 100 | tr "\n" "="; echo
dd if=/dev/zero count=1 bs=100000000 | tr '\0' '=' >/dev/null
önemli ölçüde yavaş head -c100000000 < /dev/zero | tr '\0' '=' >/dev/null
. Tabii ki zaman farkını makul bir şekilde ölçmek için 100M + 'lık bir blok boyutu kullanmanız gerekir. 100M bayt, gösterilen iki sürümle 1,7 sn ve 1 sn sürer. Ben tr çıkardı ve sadece sürüm /dev/null
için 0.287 s head
ve dd
bir milyar bayt için sürüm 0.675 s aldım .
dd if=/dev/zero count=1 bs=100000000 | tr '\0' '=' >/dev/null
=> 0,21332 s, 469 MB/s
; İçin: dd if=/dev/zero count=100 bs=1000000| tr '\0' '=' >/dev/null
=> 0,161579 s, 619 MB/s
;
Ben seq kullanarak bunu yapmak için çok kolay bir yol buldum:
GÜNCELLEME: Bu seq
, OS X ile birlikte gelen BSD'de çalışır.YMMV diğer sürümlerle birlikte
seq -f "#" -s '' 10
'#' 10 kez yazdıracak, şöyle:
##########
-f "#"
biçim dizesini sayıları yok saymak ve #
her biri için yazdırmak üzere ayarlar .-s ''
her sayı arasına eklenen satırları kaldırmak için ayırıcıyı boş bir dizeye ayarlar-f
ve -s
önemli gibi görünüyor.EDIT: İşte kullanışlı bir işlevi var ...
repeat () {
seq -f $1 -s '' $2; echo
}
Buna şöyle diyebilirsiniz ...
repeat "#" 10
NOT: Tekrarlıyorsanız #
, tırnak işaretleri önemlidir!
seq: format ‘#’ has no % directive
. seq
dizeler için değil sayılar içindir. Bkz. Gnu.org/software/coreutils/manual/html_node/seq-invocation.html
seq
, burada dizeleri çoğaltmak için akıllıca yeniden konumlandırılıyor: geçirilen biçim dizesi - normalde üretilen sayıları biçimlendirmek için kullanılır - yalnızca çıktının yalnızca bu dizenin kopyalarını içermesi için burada çoğaltılacak dizeyi içerir. Ne yazık ki, GNU biçim dizesinde bir sayı biçiminin varlığında ısrar ediyor , bu da gördüğünüz hata. -f
seq
"$1"
(çift tırnak işareti) kullanın , böylece '*'
gömülü boşluklu dizeler ve dizeler gibi karakterleri de iletebilirsiniz . Son olarak, kullanabilmek %
istiyorsanız, iki katına çıkarmanız gerekir (aksi seq
takdirde bunun bir biçim belirtiminin bir parçası olduğunu düşünürsünüz %f
); kullanmak "${1//%/%%}"
bununla ilgilenirdi. Kullandığınız (Sözünü gibi) bu yana BSD seq
, bu genel olarak BSD benzeri işletim sisteminde çalışacak (örn FreeBSD) - aksine, bu Linux üzerinde çalışma olmaz , GNU seq
kullanılır.
İşte iki ilginç yol:
ubuntu @ ubuntu: ~ $ evet = | kafa -10 | yapıştır -s -d '' - ========== ubuntu @ ubuntu: ~ $ evet = | kafa -10 | tr -d "\ n" ========== ubuntu @ ubuntu: ~ $
Bu ikisinin son derece farklı olduğuna dikkat edin - paste
Yöntem yeni bir satırda sona erer. tr
Yöntem değildir.
paste
açıklanamaz gerektiren -d '\0'
boş bir sınırlayıcı belirtmek için, ve başarısız olur -d ''
- -d '\0'
tüm POSIX uyumlu zekâ çalışmalıdır paste
uygulamaları ve aslında çalışır GNU paste
de.
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
. Daha da önemlisi: printf
yine de kullanıyorsanız , kabul edilen cevaptan hem daha basit hem de daha verimli yaklaşımı kullanabilirsiniz:printf '%.s=' $(seq 500)
Basit bir yolu yok. Kullanarak printf
ve değiştirerek döngülerden kaçının .
str=$(printf "%40s")
echo ${str// /rep}
# echoes "rep" 40 times.
repl = 100
, örneğin (bir iz çıkışı vermez) olarak çağrılabilen bir işlev \n
repl() { local ts=$(printf "%${2}s"); printf %s "${ts// /$1}"; }
Eğer farklı uygulamaları üzerinden POSIX uyumu ve tutarlılığı istiyorsanız echo
ve printf
diğeri sadece daha ve / veya kabukları 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'
hemen hemen her yerde aynı çıktıyı üretecek .
seq
bir POSIX yardımcı programı değil (BSD ve Linux sistemlerinin uygulamaları olmasına rağmen) - while
@ Xennex81'in cevabında olduğu gibi bir döngü ile POSIX kabuk aritmetiği yapabilirsiniz ( printf "="
doğru olarak önerdiğiniz gibi değil echo -n
).
cal
POSIX. seq
değil. Her neyse, cevabı bir while döngüsü ile yeniden yazmak yerine (dediğiniz gibi, zaten diğer cevaplarda) Bir RYO işlevi ekleyeceğim. Bu şekilde daha eğitici ;-).
Soru, bunun nasıl yapılacağıydı echo
:
echo -e ''$_{1..100}'\b='
Bu irade tamamen aynı yapacak perl -E 'say "=" x 100'
fakat echo
sadece.
eval
Alt kabukları, harici araçları, küme ayracı genişletmeleri olmayan saf bir Bash yolu (yani, bir değişkente yinelenecek numaraya sahip olabilirsiniz):
Size n
(negatif olmayan) bir sayıya genişleyen bir değişken pattern
ve örneğin,
$ n=5
$ pattern=hello
$ printf -v output '%*s' "$n"
$ output=${output// /$pattern}
$ echo "$output"
hellohellohellohellohello
Bununla bir işlev yapabilirsiniz:
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}"
}
Bu set ile:
$ repeat 5 hello output
$ echo "$output"
hellohellohellohellohello
Bu küçük hile için aşağıdakileri çok kullanıyoruz printf
:
-v varname
: standart çıktıya yazdırmak yerine printf
, biçimlendirilmiş dizenin içeriğini değişkene koyacaktır varname
.printf
bağımsız değişkeni karşılık gelen boşluk sayısını yazdırmak için kullanır. Örneğin, printf '%*s' 42
42 boşluk basacaktır.${var// /$pattern}
genişlemesine, genişlemesinin var
yerini alan tüm boşluklarla genişler $pattern
.Dolaylı genişletmeyi kullanarak işlevdeki tmp
değişkenten de kurtulabilirsiniz 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
, parametre genişletme ( ${var//old/new}
) bağlamındaki global dize değiştirme işlemleri özellikle yavaş: bash'da dayanılmaz derecede yavaş 3.2.57
ve 4.3.30
bash'da yavaş , en azından 3.2 Ghz Intel Core i5 makinesindeki OSX 10.10.3 sistemimde: 1.000 sayı, işler yavaş ( 3.2.57
) / hızlı ( 4.3.30
): 0.1 / 0.004 saniye. Sayımı 10.000'e çıkarmak çarpıcı derecede farklı sayılar sağlar: repeat 10000 = var
bash'da yaklaşık 80 saniye (!) Ve bash'da 3.2.57
yaklaşık 0.3 saniye 4.3.30
(ondan çok daha hızlı 3.2.57
, ama yine de yavaş).
#!/usr/bin/awk -f
BEGIN {
OFS = "="
NF = 100
print
}
Veya
#!/usr/bin/awk -f
BEGIN {
while (z++ < 100) printf "="
}
awk 'BEGIN { while (c++ < 100) printf "=" }'
. (Çağırmak bir parametreli kabuk işlev sarılmış repeat 100 =
, örneğin,): repeat() { awk -v count="$1" -v txt=".$2" 'BEGIN { txt=substr(txt, 2); while (i++ < count) printf txt }'; }
. (Kukla .
öneki karakter ve tamamlayıcı substr
BSD bir hata etrafında işe ihtiyaç vardır çağrı awk
değişken değeri olduğunu geçen başlar ile =
araları komutu.)
NF = 100
Çözeltisi (100 almak için olsa çok zeki =
, kullanmak gerekir NF = 101
). Uyarılar o BSD çöker vardır awk
(ama çok hızlı gawk
ve daha hızlı olan mawk
) ve POSIX geçen ne olduğunu atama için NF
, ne de alanların kullanılması BEGIN
blokları. BSD'de awk
de hafif bir değişiklikle çalışmasını sağlayabilirsiniz : awk 'BEGIN { OFS = "="; $101=""; print }'
(ama merakla, awk
döngü çözümünden daha hızlı olmayan BSD'de). Parametreli bir kabuk çözelti olarak: repeat() { awk -v count="$1" -v txt=".$2" 'BEGIN { OFS=substr(txt, 2); $(count+1)=""; print }'; }
.
original-awk
denemek istiyorsanız, çöktüğü bildirilen BSD'nin awk'ına benzer eski awk'ın Linux altındaki adıdır. Kilitlenmenin genellikle yararlanılabilir bir hata bulma yolundaki ilk adım olduğunu unutmayın. Bu cevap güvensiz kodu teşvik ediyor.
original-awk
standart değildir ve önerilmez
awk NF=100 OFS='=' <<< ""
( bash
ve kullanarak gawk
)
Sorunun asıl amacı bunu sadece kabuğun yerleşik komutlarıyla yapmaktı. Yani for
döngüler ve printf
s, meşru olurdu süre rep
, perl
ve ayrıca jot
aşağıda olmaz. Yine de, aşağıdaki komut
jot -s "/" -b "\\" $((COLUMNS/2))
örneğin, bir pencere genişliğinde \/\/\/\/\/\/\/\/\/\/\/\/
jot -s '' -b '=' 100
. Uyarı, OSX de dahil olmak üzere BSD benzeri platformların gelmesine rağmenjot
, Linux dağıtımlarının gelmemesidir .
apt install athena-jot
sağlayacaktır jot
.
Diğerlerinin söylediği gibi, bash ayracı genişletmesinde parametre genişletmesinden önce gelir , bu nedenle aralıklar yalnızca değişmez değerler içerebilir. ve temiz çözümler sunar ancak her birinde aynı kabuğu kullansanız bile bir sistemden diğerine tamamen taşınabilir değildir. (Her ne kadar artan bir şekilde mevcut olsa da; örneğin, FreeBSD 9.3 ve üstü sürümlerde ) ve diğer dolaylı biçimler her zaman işe yarar, ancak bir şekilde yetersizdir.{m,n}
seq
jot
seq
eval
Neyse ki, bash döngüler için C stilini destekler (yalnızca aritmetik ifadelerle). İşte özlü bir "saf bash" yolu:
repecho() { for ((i=0; i<$1; ++i)); do echo -n "$2"; done; echo; }
Bu, ilk bağımsız değişken olarak tekrar sayısını ve ikinci bağımsız değişken olarak tekrarlanacak dizeyi (sorun açıklamasında olduğu gibi tek bir karakter olabilir) alır. repecho 7 b
çıktılar bbbbbbb
(bir satırsonu ile sonlandırılır).
Dennis Williamson verdi onun mükemmel cevap dört yıl önce esasen bu çözümü için kabuk komut dosyası tekrarlanan karakter dizesini oluşturma . Benim işlev gövdesi orada kod biraz farklıdır:
Buradaki odak tek bir karakteri tekrarlamak ve kabuk bash olduğundan, muhtemelen echo
yerine kullanmak güvenlidir printf
. Ve bu sorudaki sorun tanımını yazdırmayı tercih ettiğini ifade ediyorum echo
. Yukarıdaki fonksiyon tanımı bash ve ksh93 ile çalışır . Her ne kadar printf
daha taşınabilir olsa da (ve genellikle bu tür şeyler için kullanılmalıdır), echo
sözdizimi muhtemelen daha okunabilirdir.
Bazı mermilerin echo
yapıları -
tek başına bir seçenek olarak yorumlanır - her ne kadar -
giriş için stdin kullanmak anlamsız olsa da echo
. zsh bunu yapar. Ve kesinlikle orada mevcut echo
tanımaz s -n
olarak, standart değildir . (Bourne tarzı mermilerin çoğu döngüler için C-stili kabul etmezler, bu nedenle echo
davranışlarının dikkate alınması gerekmez.)
Burada görev diziyi yazdırmak; orada bir değişkene atamaktı.
Eğer $n
tekrar istenilen sayı ve bunu yeniden gerekmez, ve hatta daha kısa bir şey istiyorum:
while ((n--)); do echo -n "$s"; done; echo
n
değişken olmalıdır - bu şekilde konumsal parametrelerle çalışmaz. $s
tekrarlanacak metindir.
printf "%100s" | tr ' ' '='
en uygunudur.
zsh
tesadüfen çalışan bir işlev olarak paketlemek için iyi arka plan bilgisi ve kudos . Döngüdeki yankı yaklaşımı daha küçük tekrar sayıları için iyi çalışır, ancak daha büyük olanlar için POSIX uyumlu alternatifler vardır. , @ Slomojo'nun yorumunda kanıtlandığı gibi yardımcı programlara .
echo
destekleyen bir yerleşik vardır -n
. Söylediklerinizin ruhu kesinlikle doğrudur. en azından interaktif olmayan kullanımda printf
neredeyse her zaman tercih edilmelidir echo
. Ancak echo
, bir soru soran ve işe yarayacağını bilmek için yeterli bilgi veren bir soruya cevap vermenin uygunsuz veya yanıltıcı olduğunu düşünmüyorum . Lütfen ((n--))
($
) kendisinin POSIX tarafından garanti edilmediğini .
Python her yerde bulunur ve her yerde aynı şekilde çalışır.
python -c "import sys; print('*' * int(sys.argv[1]))" "=" 100
Karakter ve sayı ayrı parametreler olarak iletilir.
python -c "import sys; print(sys.argv[1] * int(sys.argv[2]))" "=" 100
Rasgele bir dizeyi n kez tekrarlamanın başka bir anlamı:
Artıları:
Eksileri:
yes
komutunu gerektirir .#!/usr/bin/sh
to_repeat='='
repeat_count=80
yes "$to_repeat" | tr -d '\n' | head -c "$repeat_count"
Bir ANSI terminali ve US-ASCII karakterleri ile tekrarlayın. Bir ANSI CSI kaçış dizisi kullanabilirsiniz. Bir karakteri tekrar etmenin en hızlı yoludur.
#!/usr/bin/env bash
char='='
repeat_count=80
printf '%c\e[%db' "$char" "$repeat_count"
Veya statik olarak:
80 kez bir satır yazdırın =
:
printf '=\e[80b\n'
Sınırlamalar:
repeat_char
ANSI CSI dizisini anlamaz .repeat_char
ANSI CSI dizisini tekrarlanan karaktere genişletmez .Linux'ta ekran boyunca bir karakter satırı yazdırmak için kullandığım şey (terminal / ekran genişliğine göre)
printf '=%.0s' $(seq 1 $(tput cols))
Açıklama:
Belirtilen sırayla eşit sayıda işaret yazdırın:
printf '=%.0s' #sequence
Bir komutun çıkışını kullanın (bu, Komut Değiştirme olarak adlandırılan bir bash özelliğidir):
$(example_command)
Bir dizi verin, örnek olarak 1'den 20'ye kadar kullandım. Son komutta 20 yerine tput komutu kullanılır:
seq 1 20
Terminalde şu anda kullanılan sütun sayısını verin:
tput cols
for i in {1..100}
do
echo -n '='
done
echo
En basit olanı bu tek astarı csh / tcsh'de kullanmaktır:
printf "%50s\n" '' | tr '[:blank:]' '[=]'
Önerilen Python çözümüne daha zarif bir alternatif olabilir:
python -c 'print "="*(1000)'
Örneğin, yapabileceğiniz bir dizenin uzunluğuna bağlı olarak bir karakteri n kez DEĞİŞKEN olmak üzere tekrarlamak istediğinizde:
#!/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)
Görüntüleniyor:
vari equals.............................: AB
Up to 10 positions I must fill with.....: 8 equal signs
AB========
length
çalışmayacak expr
, muhtemelen anlamına geliyordu n=$(expr 10 - ${#vari})
; ancak, Bash'in aritmetik kullanımı daha basit ve daha verimli: n=$(( 10 - ${#vari} ))
. Ayrıca, cevabınızın merkezinde OP'nin Bash alternatifi aradığı Perl yaklaşımı var .
Eliah Kagan'ın benimsediği şeyin daha uzun versiyonu:
while [ $(( i-- )) -gt 0 ]; do echo -n " "; done
Elbette bunun için printf kullanabilirsiniz, ancak benim zevkime göre değil:
printf "%$(( i*2 ))s"
Bu sürüm Dash uyumludur:
until [ $(( i=i-1 )) -lt 0 ]; do echo -n " "; done
ben ilk sayı olmak.
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
}
Örnek çalışmalar
$ repeatString 'a1' 10
a1a1a1a1a1a1a1a1a1a1
$ repeatString 'a1' 0
$ repeatString '' 10
Referans lib: https://github.com/gdbtek/linux-cookbooks/blob/master/libraries/util.bash
Cevabım biraz daha karmaşık ve muhtemelen mükemmel değil, ancak çok sayıda çıktı almak isteyenler için 3 saniyede yaklaşık 10 milyon yapmayı başardım.
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}
}
En basit olanı, bu tek astarı bash'de kullanmaktır:
seq 10 | xargs -n 1 | xargs -I {} echo -n ===\>;echo
Mevcut çözümlerin çoğu {1..10}
, kabuğun sözdizimi desteğine bağlıdır ; bu bash
- ve zsh
- spesifiktir ve tcsh
OpenBSD'lerde ksh
ve çoğu bash içinde çalışmazsh
.
Aşağıdakiler OS X ve tüm * BSD sistemleri üzerinde herhangi bir kabukta çalışmalıdır; aslında, çeşitli dekoratif alan türlerinden oluşan bir bütün matris oluşturmak için kullanılabilir:
$ printf '=%.0s' `jot 64` | fold -16
================
================
================
================$
Ne yazık ki, sondaki yeni bir satır almıyoruz; printf '\n'
kattan sonra ekstra bir şekilde sabitlenebilir :
$ printf "=%.0s" `jot 64` | fold -16 ; printf "\n"
================
================
================
================
$
Referanslar:
Teklifim ( n için değişken değerleri kabul etmek ):
n=100
seq 1 $n | xargs -I {} printf =