Jak mogłem to zrobić echo
?
perl -E 'say "=" x 100'
ruby -e 'puts "=" * 100'
lubpython -c 'print "=" * 100'
printf
z seq
)svrb=`printf '%.sv' $(seq $vrb)`
Jak mogłem to zrobić echo
?
perl -E 'say "=" x 100'
ruby -e 'puts "=" * 100'
lubpython -c 'print "=" * 100'
printf
z seq
)svrb=`printf '%.sv' $(seq $vrb)`
Odpowiedzi:
Możesz użyć:
printf '=%.0s' {1..100}
Jak to działa:
Bash rozwija {1..100}, więc polecenie staje się:
printf '=%.0s' 1 2 3 4 ... 100
Ustawiłem format printf, =%.0s
co oznacza, że zawsze będzie drukował jeden, =
bez względu na podany argument. Dlatego drukuje 100 =
s.
repl = 100
na przykład ( eval
niestety wymagane jest repl() { printf "$1"'%.s' $(eval "echo {1.."$(($2))"}"); }
seq
Zamiast tego użyj np $(seq 1 $limit)
.
$s%.0s
aby w %.0s$s
przeciwnym razie kreski spowodowały printf
błąd.
printf
: kontynuuje stosowanie łańcucha formatu, dopóki nie pozostaną żadne argumenty. Zakładałem, że przetworzył ciąg formatu tylko raz!
Nie ma łatwego sposobu. Ale na przykład:
seq -s= 100|tr -d '[:digit:]'
A może sposób zgodny ze standardami:
printf %100s |tr " " "="
Są też tput rep
, ale jeśli chodzi o moje terminale pod ręką (xterm i linux), wydaje się, że nie obsługują tego :)
=
znaków.
printf
tr
jest jedynym rozwiązaniem, ponieważ POSIX seq
, yes
a {1..3}
nie są POSIX.
printf %100s | sed 's/ /abc/g'
- wypisuje „abcabcabc ...”
tr
). Możesz także rozszerzyć go na coś takiego printf "%${COLUMNS}s\n" | tr " " "="
.
wc
. Jedyny wniosek, jaki mogę z tego wyciągnąć, to „ seq
nie należy używać”.
Wskazówka kapelusza do jego @ gniourf_gniourf .
Uwaga: Ta odpowiedź nie odpowiada na pierwotne pytanie, ale uzupełnia istniejące, pomocne odpowiedzi, porównując wydajność .
Rozwiązania są porównywane tylko pod względem szybkości wykonania - wymagania pamięci nie są brane pod uwagę (różnią się w zależności od rozwiązania i mogą mieć znaczenie przy dużej liczbie powtórzeń).
Podsumowanie:
${var// /=}
), Ponieważ jest to zbyt wolne.Poniżej znajdują się czasy pobrane na komputerze iMac z końca 2012 r. Z procesorem Intel Core i5 3,2 GHz i dyskiem Fusion, działającym w systemie OSX 10.10.4 i bash 3.2.57, i są to średnio 1000 uruchomień.
Wpisy to:
M
... potencjalnie rozwiązanie wielu znakówS
... rozwiązanie tylko dla jednego znakuP
... rozwiązanie zgodne z 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
i perl
rozwiązań.[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// /=}
) jest niewytłumaczalnie powolna z dużymi łańcuchami i została wyłączona z działania (zajęło około 50 minut (!) W wersji Bash 4.3.30, a nawet dłużej w wersji Bash 3.2.57 - nigdy nie czekałem to zakończyć).(( i= 0; ... ))
) są wolniejsze niż pętle z rozszerzeniem nawiasów klamrowych ( {1..n}
) - chociaż pętle arytmetyczne są bardziej wydajne pod względem pamięci.awk
odnosi się do BSD awk
(jak również w OSX) - jest zauważalnie wolniejszy niż gawk
(GNU Awk), a zwłaszcza mawk
.Oto skrypt Bash ( testrepeat
), który wytworzył powyższe. Wymaga 2 argumentów:
Innymi słowy: powyższe czasy uzyskano za pomocą testrepeat 100 1000
itestrepeat 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`
👍
Jest na to więcej niż jeden sposób.
Za pomocą pętli:
Rozwijania nawiasów klamrowych można używać z literałami całkowitymi:
for i in {1..100}; do echo -n =; done
Pętla podobna do C umożliwia stosowanie zmiennych:
start=1
end=100
for ((i=$start; i<=$end; i++)); do echo -n =; done
Korzystanie z printf
wbudowanego:
printf '=%.0s' {1..100}
Określenie tutaj precyzji powoduje obcięcie łańcucha w celu dopasowania do określonej szerokości ( 0
). Jak printf
ponownie wykorzystuje ciąg formatu spożywać wszystkie argumenty, to po prostu drukuje "="
100 razy.
Za pomocą head
( printf
itp.) I tr
:
head -c 100 < /dev/zero | tr '\0' '='
printf %100s | tr " " "="
head
/ tr
rozwiązania, które działa dobrze nawet przy dużej liczbie powtórzeń (małe zastrzeżenie: head -c
nie jest zgodne z POSIX, ale head
implementują go zarówno BSD, jak i GNU ); podczas gdy dwa inne rozwiązania będzie wolno w takim przypadku, mają tę zaletę, że działa z wielu ciągów dwuznakowego też.
yes
i head
- przydatna, jeśli chcesz pewną liczbę nowych linii: yes "" | head -n 100
. tr
może sprawić, że wypisze dowolny znak:yes "" | head -n 100 | tr "\n" "="; echo
dd if=/dev/zero count=1 bs=100000000 | tr '\0' '=' >/dev/null
jest znacznie wolniejszy niż head -c100000000 < /dev/zero | tr '\0' '=' >/dev/null
wersja. Oczywiście musisz użyć bloku o wielkości 100 M +, aby rozsądnie zmierzyć różnicę czasu. 100M bajtów zajmuje 1,7 si 1 s przy pokazanych dwóch odpowiednich wersjach. Zdjąłem tr i po prostu zrzuciłem go /dev/null
i dostałem 0,287 s dla head
wersji i 0,675 s dla dd
wersji dla miliarda bajtów.
dd if=/dev/zero count=1 bs=100000000 | tr '\0' '=' >/dev/null
=> 0,21332 s, 469 MB/s
; Dla: dd if=/dev/zero count=100 bs=1000000| tr '\0' '=' >/dev/null
=> 0,161579 s, 619 MB/s
;
Właśnie znalazłem bardzo prosty sposób, aby to zrobić za pomocą seq:
AKTUALIZACJA: Działa na BSD seq
dostarczanym z OS X. YMMV z innymi wersjami
seq -f "#" -s '' 10
Wydrukuje „#” 10 razy, tak jak to:
##########
-f "#"
ustawia ciąg formatu, aby ignorował liczby i po prostu drukował #
dla każdego z nich.-s ''
ustawia separator na pusty ciąg, aby usunąć znaki nowej linii, które sekwencja wstawia między każdą liczbą-f
i -s
wydają się być ważne.EDYCJA: Oto przydatna funkcja ...
repeat () {
seq -f $1 -s '' $2; echo
}
Które możesz tak nazwać ...
repeat "#" 10
UWAGA: Jeśli powtarzasz, #
cytaty są ważne!
seq: format ‘#’ has no % directive
. seq
jest dla liczb, a nie ciągów. Zobacz gnu.org/software/coreutils/manual/html_node/seq-invocation.html
seq
jest sprytnie zmieniane tutaj, aby powielać ciągi : przekazany ciąg formatu -f
- zwykle używany do formatowania generowanych liczb - zawiera tylko ciąg do replikacji tutaj, tak że dane wyjściowe zawierają tylko kopie tego ciągu. Niestety, GNU seq
nalega na obecność formatu liczbowego w ciągu formatu, który jest błędem, który widzisz.
"$1"
(podwójne cudzysłowy), aby można było także przekazywać znaki takie jak '*'
i ciągi znaków z osadzonymi białymi znakami . Wreszcie, jeśli chcesz móc korzystać %
, musisz go podwoić (w przeciwnym razie seq
pomyślisz, że jest to część specyfikacji formatu, takiej jak %f
); używanie "${1//%/%%}"
to załatwi. Ponieważ (jak wspomniałeś) używasz BSD seq
, będzie to działało ogólnie na systemach operacyjnych podobnych do BSD (np. FreeBSD) - przeciwnie, nie będzie działać na Linuksie , w którym używany jest GNU seq
.
Oto dwa ciekawe sposoby:
ubuntu @ ubuntu: ~ $ yes = | głowa -10 | wklej -s -d '' - ========== ubuntu @ ubuntu: ~ $ yes = | głowa -10 | tr -d "\ n" ========== ubuntu @ ubuntu: ~ $
Zauważ, że te dwa są subtelnie różne - paste
Metoda kończy się na nowej linii. tr
Metoda nie.
paste
niewytłumaczalny sposób wymaga -d '\0'
określenia pustego separatora i kończy się niepowodzeniem -d ''
- -d '\0'
powinien działać ze wszystkimi paste
implementacjami kompatybilnymi z POSIX i rzeczywiście działa również z 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
. Co ważniejsze: jeśli printf
mimo to korzystasz , równie dobrze możesz zastosować zarówno prostsze, jak i bardziej wydajne podejście z zaakceptowanej odpowiedzi:printf '%.s=' $(seq 500)
Nie ma prostego sposobu. Unikaj używania printf
i zastępowania pętli .
str=$(printf "%40s")
echo ${str// /rep}
# echoes "rep" 40 times.
repl = 100
na przykład jako (nie wyświetla końcowego \n
):repl() { local ts=$(printf "%${2}s"); printf %s "${ts// /$1}"; }
Jeśli chcesz POSIX zgodności i spójności pomiędzy różnymi implementacjami echo
i printf
, i / lub muszli inne niż 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)
... da taką samą wydajność jak perl -E 'say "=" x 100'
prawie wszędzie.
seq
nie jest to narzędzie POSIX (chociaż systemy BSD i Linux mają takie implementacje) - while
zamiast tego można wykonywać arytmetykę powłoki POSIX za pomocą pętli, jak w odpowiedzi @ Xennex81 (zamiast, jak printf "="
słusznie sugerujesz, zamiast echo -n
).
cal
jest POSIX. seq
nie jest. W każdym razie, zamiast przepisać odpowiedź za pomocą pętli while (jak mówisz, to już jest w innych odpowiedziach) dodam funkcję RYO. Więcej edukacyjnych w ten sposób ;-).
Pytanie dotyczyło tego, jak to zrobić echo
:
echo -e ''$_{1..100}'\b='
To zrobi dokładnie to samo, perl -E 'say "=" x 100'
ale echo
tylko z .
$_1
, $_2
lub jakakolwiek inna ze stu zmiennych ma wartości.
Czysty sposób Bash bez eval
, bez podpowłoki, bez zewnętrznych narzędzi, bez rozszerzeń nawiasów (tzn. Możesz mieć liczbę do powtórzenia w zmiennej):
Jeśli otrzymasz zmienną, n
która rozwija się do liczby (nieujemnej) i zmienną pattern
, np.
$ n=5
$ pattern=hello
$ printf -v output '%*s' "$n"
$ output=${output// /$pattern}
$ echo "$output"
hellohellohellohellohello
Możesz wykonać funkcję za pomocą tego:
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}"
}
Z tym zestawem:
$ repeat 5 hello output
$ echo "$output"
hellohellohellohellohello
Do tej małej sztuczki używamy printf
całkiem sporo z:
-v varname
: zamiast drukowania na standardowe wyjście, printf
umieści zawartość sformatowanego ciągu w zmiennej varname
.printf
użyje argumentu do wydrukowania odpowiedniej liczby spacji. Np. printf '%*s' 42
Wydrukuje 42 spacje.${var// /$pattern}
rozwinie się do rozwinięcia var
z wszystkimi spacjami zastąpionymi przez rozwinięcie $pattern
.Możesz także pozbyć się tmp
zmiennej w repeat
funkcji, używając rozszerzenia pośredniego:
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
globalne operacje zamiany ciągów w kontekście interpretacji parametrów ( ${var//old/new}
) są szczególnie powolne: niesamowicie powolne w bashu 3.2.57
i powolne w bashu 4.3.30
, przynajmniej w moim systemie OSX 10.10.3 na maszynie Intel Core i5 3,2 Ghz: Z liczba 1000, rzeczy są wolne ( 3.2.57
) / szybkie ( 4.3.30
): 0,1 / 0,004 sekundy. Zwiększenie liczby do 10.000 daje uderzająco różne liczby: repeat 10000 = var
trwa około 80 sekund (!) W uderzeniu 3.2.57
i około 0,3 sekundy w uderzeniu 4.3.30
(znacznie szybciej niż w trybie włączonym 3.2.57
, ale wciąż powolnym).
#!/usr/bin/awk -f
BEGIN {
OFS = "="
NF = 100
print
}
Lub
#!/usr/bin/awk -f
BEGIN {
while (z++ < 100) printf "="
}
awk 'BEGIN { while (c++ < 100) printf "=" }'
. Owinięty w sparametryzowanej funkcję powłoki (Wywołanie jak repeat 100 =
, na przykład) repeat() { awk -v count="$1" -v txt=".$2" 'BEGIN { txt=substr(txt, 2); while (i++ < count) printf txt }'; }
. (Atrapa .
przedrostka char i komplementarne substr
wywołanie są potrzebne do obejścia błędu w BSD awk
, gdzie przekazanie wartości zmiennej rozpoczynającej się od =
złamania polecenia.)
NF = 100
Rozwiązanie jest bardzo mądry (chociaż dostać 100 =
, należy użyć NF = 101
). Te zastrzeżenia są takie, że wywala BSD awk
(ale to bardzo szybko z gawk
, a nawet szybciej mawk
), a który omawia POSIX ani przypisywanie do NF
, ani wykorzystanie pól w BEGIN
blokach. Możesz sprawić, że będzie działał również w BSD awk
z niewielką poprawką: awk 'BEGIN { OFS = "="; $101=""; print }'
(ale co ciekawe, w BSD, awk
która nie jest szybsza niż rozwiązanie pętli). Jako sparametryzowanego roztworu powłoki: repeat() { awk -v count="$1" -v txt=".$2" 'BEGIN { OFS=substr(txt, 2); $(count+1)=""; print }'; }
.
original-awk
to nazwa pod Linuksem starszego awk podobnego do awk BSD, który również został zgłoszony do awarii, jeśli chcesz tego spróbować. Pamiętaj, że zawieszanie się jest zwykle pierwszym krokiem do znalezienia możliwego do wykorzystania błędu. Ta odpowiedź tak promuje niepewny kod.
original-awk
jest niestandardowa i nie jest zalecana
awk NF=100 OFS='=' <<< ""
(użycie bash
i gawk
)
Myślę, że pierwotnym celem tego pytania było zrobienie tego tylko za pomocą wbudowanych poleceń powłoki. Więc for
pętle i printf
s byłby uzasadniony, natomiast rep
, perl
i również jot
poniżej nie. Mimo to następujące polecenie
jot -s "/" -b "\\" $((COLUMNS/2))
na przykład drukuje całą linię okna \/\/\/\/\/\/\/\/\/\/\/\/
jot -s '' -b '=' 100
. Zastrzeżenie jest to, że podczas BSD-like platform, w tym OSX, wyposażone jot
, dystrybucje Linuksa nie .
apt install athena-jot
zapewniłoby to jot
.
Jak powiedzieli inni, w interpretacji nawiasów klamrowych poprzedza się interpretację parametrów , więc zakresy mogą zawierać tylko literały. i zapewniają czyste rozwiązania, ale nie są w pełni przenośne z jednego systemu do drugiego, nawet jeśli używasz tej samej powłoki na każdym z nich. (Chociaż jest coraz bardziej dostępny; np. We FreeBSD 9.3 i nowszych .) I inne formy pośrednictwa zawsze działają, ale są nieco nieeleganckie.{m,n}
seq
jot
seq
eval
Na szczęście bash obsługuje styl C dla pętli (tylko z wyrażeniami arytmetycznymi). Oto więc zwięzły „czysty bash”:
repecho() { for ((i=0; i<$1; ++i)); do echo -n "$2"; done; echo; }
Pobiera to liczbę powtórzeń jako pierwszy argument, a ciąg do powtórzenia (który może być pojedynczym znakiem, jak w opisie problemu) jako drugi argument. repecho 7 b
wyjścia bbbbbbb
(zakończone nową linią).
Dennis Williamson podał zasadniczo to rozwiązanie cztery lata temu w swojej doskonałej odpowiedzi na temat Tworzenie ciągu powtarzających się znaków w skrypcie powłoki . Moje ciało funkcji różni się nieznacznie od kodu tam:
Ponieważ nacisk kładziony jest tutaj na powtarzanie jednego znaku, a powłoka jest bash, prawdopodobnie można go bezpiecznie używać echo
zamiast printf
. Przeczytałem opis problemu w tym pytaniu jako wyrażenie preferencji drukowania echo
. Powyższa definicja funkcji działa w bash i ksh93 . Chociaż printf
jest bardziej przenośny (i zwykle powinien być używany do tego typu rzeczy), echo
jego składnia jest prawdopodobnie bardziej czytelna.
Niektóre echo
wbudowane powłoki interpretują -
się jako opcja - chociaż zwykłe znaczenie -
używania stdin jako danych wejściowych jest bezsensowne echo
. zsh to robi. I zdecydowanie istnieją takie echo
, które nie rozpoznają -n
, ponieważ nie jest to standard . (Wiele powłok w stylu Bourne'a w ogóle nie akceptuje pętli w stylu C, dlatego ich echo
zachowanie nie musi być brane pod uwagę ...)
Tutaj zadaniem jest wydrukowanie sekwencji; tam miał przypisać ją do zmiennej.
Jeśli $n
jest pożądana liczba powtórzeń i nie musisz jej ponownie używać, a chcesz czegoś jeszcze krótszego:
while ((n--)); do echo -n "$s"; done; echo
n
musi być zmienną - w ten sposób nie działa z parametrami pozycyjnymi. $s
to tekst do powtórzenia.
printf "%100s" | tr ' ' '='
jest optymalny.
zsh
również przy okazji. Podejście echo w pętli działa dobrze dla mniejszych zliczeń powtórzeń, ale dla większych istnieją alternatywy zgodne z POSIX oparte na narzędziach , o czym świadczy komentarz @ Slomojo.
(while ((n--)); do echo -n "$s"; done; echo)
echo
wbudowaną obsługę -n
. Duch tego, co mówisz, jest absolutnie poprawny. printf
prawie zawsze powinno być preferowaneecho
, przynajmniej w zastosowaniach nieinteraktywnych. Ale nie sądzę, aby udzielanie echo
odpowiedzi na pytanie, które zadawało pytanie, było w jakikolwiek sposób niewłaściwe lub mylące i dawało wystarczającą ilość informacji, aby wiedzieć, że zadziała . Należy również pamiętać, że POSIX nie gwarantuje wsparcia dla ((n--))
(bez a $
).
Python jest wszechobecny i wszędzie działa tak samo.
python -c "import sys; print('*' * int(sys.argv[1]))" "=" 100
Znak i liczba są przekazywane jako osobne parametry.
python -c "import sys; print(sys.argv[1] * int(sys.argv[2]))" "=" 100
Kolejny sposób na powtórzenie dowolnego ciągu n razy:
Plusy:
Cons:
yes
.#!/usr/bin/sh
to_repeat='='
repeat_count=80
yes "$to_repeat" | tr -d '\n' | head -c "$repeat_count"
Z terminalem ANSI i znakami US-ASCII do powtórzenia. Możesz użyć sekwencji ucieczki ANSI CSI. Jest to najszybszy sposób na powtórzenie postaci.
#!/usr/bin/env bash
char='='
repeat_count=80
printf '%c\e[%db' "$char" "$repeat_count"
Lub statycznie:
Wydrukuj linię 80 razy =
:
printf '=\e[80b\n'
Ograniczenia:
repeat_char
sekwencję ANSI CSI.repeat_char
sekwencji ANSI CSI do powtarzanego znaku.Oto, czego używam do drukowania linii znaków na ekranie w systemie Linux (na podstawie szerokości terminala / ekranu)
printf '=%.0s' $(seq 1 $(tput cols))
Wyjaśnienie:
Wydrukuj znak równości tyle razy, ile podana sekwencja:
printf '=%.0s' #sequence
Użyj danych wyjściowych polecenia (jest to funkcja bash o nazwie Command Substitution):
$(example_command)
Podaj sekwencję, użyłem od 1 do 20 jako przykład. W ostatnim poleceniu użyto polecenia tput zamiast 20:
seq 1 20
Podaj liczbę kolumn aktualnie używanych w terminalu:
tput cols
for i in {1..100}
do
echo -n '='
done
echo
Najprościej jest użyć tego jednowierszowego w csh / tcsh:
printf "%50s\n" '' | tr '[:blank:]' '[=]'
Bardziej elegancką alternatywą dla proponowanego rozwiązania Python może być:
python -c 'print "="*(1000)'
Jeśli chcesz powtórzyć znak n razy NA ZMIENNĄ liczbę razy w zależności, powiedzmy, od długości łańcucha, który możesz wykonać:
#!/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)
To pokazuje:
vari equals.............................: AB
Up to 10 positions I must fill with.....: 8 equal signs
AB========
length
nie będzie działać expr
, prawdopodobnie miałeś na myśli n=$(expr 10 - ${#vari})
; Jednakże, jest to prostsze i bardziej efektywne w użyciu arytmetyczną ekspansję atakujących za: n=$(( 10 - ${#vari} ))
. Również u podstaw twojej odpowiedzi znajduje się podejście Perla, w którym OP szuka alternatywy dla Bash .
To jest dłuższa wersja tego, co opowiadał Eliah Kagan:
while [ $(( i-- )) -gt 0 ]; do echo -n " "; done
Oczywiście możesz również użyć printf, ale nie do końca tak:
printf "%$(( i*2 ))s"
Ta wersja jest kompatybilna z Dash:
until [ $(( i=i-1 )) -lt 0 ]; do echo -n " "; done
gdzie I jest liczbą początkową.
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
}
Przykładowe przebiegi
$ repeatString 'a1' 10
a1a1a1a1a1a1a1a1a1a1
$ repeatString 'a1' 0
$ repeatString '' 10
Dokumentacja lib pod adresem : https://github.com/gdbtek/linux-cookbooks/blob/master/libraries/util.bash
Moja odpowiedź jest nieco bardziej skomplikowana i prawdopodobnie nie idealna, ale dla tych, którzy szukają dużych liczb, byłem w stanie zrobić około 10 milionów w 3 sekundy.
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}
}
Najprostszym jest użycie tej jednowarstwowej w bash:
seq 10 | xargs -n 1 | xargs -I {} echo -n ===\>;echo
Większość istniejących rozwiązań zależy od {1..10}
obsługi składni powłoki, która jest bash
- i zsh
- specyficzna i nie działa w tcsh
lub OpenBSD ksh
i większość nie bashsh
.
Następujące powinny działać na OS X i wszystkich systemach * BSD w dowolnej powłoce; w rzeczywistości można go wykorzystać do wygenerowania całej matrycy różnego rodzaju przestrzeni dekoracyjnej:
$ printf '=%.0s' `jot 64` | fold -16
================
================
================
================$
Niestety nie otrzymujemy końca nowej linii; które można naprawić za pomocą dodatkowego printf '\n'
po złożeniu:
$ printf "=%.0s" `jot 64` | fold -16 ; printf "\n"
================
================
================
================
$
Bibliografia:
Moja propozycja (przyjmowanie wartości zmiennych dla n):
n=100
seq 1 $n | xargs -I {} printf =