nie echo, ale na ten sam temat ruby -e 'puts "=" * 100'lubpython -c 'print "=" * 100'
Jewgienij,
1
Świetne pytanie. Bardzo dobre odpowiedzi. Użyłem jednej z odpowiedzi w prawdziwej pracy, którą opublikuję jako przykład: github.com/drbeco/oldfiles/blob/master/oldfiles (używane printfz seq)svrb=`printf '%.sv' $(seq $vrb)`
Dr Beco
Ogólne rozwiązanie do drukowania cokolwiek (1 lub więcej znaków, nawet włączając znaki nowej linii): Repeat_this () {i = 1; while [„$ i” -le „2 $”]; do printf "% s" "$ 1"; i = $ (($ i + 1)); Gotowe ; printf '\ n';}. Użyj tego: Powtórz_to „coś” Liczba_repetycji. Na przykład, aby zaprezentować powtarzanie 5 razy, w tym 3 nowe wiersze: Powtórz_to "$ (printf '\ n \ n \ nthis')" 5. Ostatni printf '\ n' może zostać wyjęty (ale wstawiłem go, aby utworzyć pliki tekstowe, a te potrzebują nowego wiersza jako ostatniego znaku!)
Olivier Dulac
Odpowiedzi:
396
Możesz użyć:
printf '=%.0s'{1..100}
Jak to działa:
Bash rozwija {1..100}, więc polecenie staje się:
printf '=%.0s'1234...100
Ustawiłem format printf, =%.0sco oznacza, że zawsze będzie drukował jeden, =bez względu na podany argument. Dlatego drukuje 100 =s.
Świetne rozwiązanie, które działa dość dobrze nawet przy dużej liczbie powtórzeń. Oto opakowanie funkcji, które można wywołać repl = 100na przykład ( evalniestety wymagane jest repl() { printf "$1"'%.s' $(eval "echo {1.."$(($2))"}"); }
podstęp w
7
Czy można ustawić górny limit za pomocą var? Próbowałem i nie mogę go uruchomić.
Mike Purcell,
70
Nie można używać zmiennych w ramach rozwijania nawiasów. seqZamiast tego użyj np $(seq 1 $limit).
dogbane
11
Jeśli to sfunkcjonalizujesz, najlepiej zmienić jego kolejność, $s%.0saby w %.0s$sprzeciwnym razie kreski spowodowały printfbłąd.
KomodoDave
5
To sprawiło, że zauważyłem zachowanie Basha printf: kontynuuje stosowanie łańcucha formatu, dopóki nie pozostaną żadne argumenty. Zakładałem, że przetworzył ciąg formatu tylko raz!
Jeenu
89
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 :)
Zauważ, że pierwsza opcja z sekwencją drukuje o jeden mniej niż podana liczba, więc w tym przykładzie wydrukuje 99 =znaków.
Camilo Martin
13
printftrjest jedynym rozwiązaniem, ponieważ POSIX seq, yesa {1..3}nie są POSIX.
Ciro Santilli 10 冠状 病 六四 事件 法轮功
2
Aby powtórzyć ciąg zamiast jednego znaku: printf %100s | sed 's/ /abc/g'- wypisuje „abcabcabc ...”
John Rix,
3
+1 za brak pętli i tylko jedno zewnętrzne polecenie ( tr). Możesz także rozszerzyć go na coś takiego printf "%${COLUMNS}s\n" | tr " " "=".
musiphil
2
@ mklement0 Cóż, miałem nadzieję, że przez pomyłkę liczysz ostatnią nową linię wc. Jedyny wniosek, jaki mogę z tego wyciągnąć, to „ seqnie należy używać”.
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:
Jeśli liczba powtórzeń jest niewielka , powiedzmy do około 100, warto wybrać rozwiązania oparte tylko na Bash , ponieważ koszty uruchomienia zewnętrznych narzędzi są ważne, zwłaszcza Perla.
Pragmatycznie rzecz biorąc, jeśli potrzebujesz tylko jednego wystąpienia powtarzających się znaków, wszystkie istniejące rozwiązania mogą być w porządku.
Z dużych powtarzanych zarzutów , użyć zewnętrznych narzędzi , jak zostaną one znacznie szybciej.
W szczególności unikaj globalnego zastępowania podciągów przez Bash dużymi łańcuchami
(np. ${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:
wymienione w kolejności rosnącej czasu wykonywania (najpierw najszybszy)
Rozwiązania oparte wyłącznie na Bash są na czele - ale tylko z powtarzaniem liczą się tak małe! (patrz poniżej).
Tu liczy się koszt uruchomienia zewnętrznych narzędzi, zwłaszcza Perla. Jeśli musisz to wywoływać w pętli - z małą liczbą powtórzeń liczy się w każdej iteracji - unikaj wielofunkcyjności awki perlrozwiązań.
Rozwiązanie Perla z pytania jest zdecydowanie najszybsze.
Globalna zamiana łańcuchów znaków (Bash ${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ć).
Pętle Bash są powolne, a pętle arytmetyczne ( (( 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.
awkodnosi się do BSDawk (jak również w OSX) - jest zauważalnie wolniejszy niż gawk(GNU Awk), a zwłaszcza mawk.
Zauważ, że przy dużych liczbach i wielu znakach. ciągów, zużycie pamięci może stać się rozważeniem - podejścia różnią się pod tym względem.
Oto skrypt Bash ( testrepeat), który wytworzył powyższe. Wymaga 2 argumentów:
liczba powtórzeń znaków
opcjonalnie liczba uruchomień testowych do wykonania i obliczenia średniego czasu
Innymi słowy: powyższe czasy uzyskano za pomocą testrepeat 100 1000itestrepeat 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++));dofor((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=12>/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;doif[[-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"donefidone
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=1if(( skip ));then
echo 'n/a'>&2else
time for(( n =0; n < COUNT_RUNS; n++));do{ printf -v t "%${COUNT_REPETITIONS}s"'='; printf %s "${t// /=}";}>"$outFile"donefi}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
Interesujące jest porównanie czasowe, ale myślę, że w wielu programach dane wyjściowe są buforowane, więc ich czas można zmienić, jeśli buforowanie zostało wyłączone.
Sergiy Kolodyazhnyy,
In order to use brace expansion with a variable, we must use `eval`👍
pyb
2
Zatem rozwiązanie perla (sid_com) jest zasadniczo najszybsze ... po osiągnięciu początkowego obciążenia związanego z uruchomieniem perla. (z 59 ms na małe powtórzenie do 67 ms na milion powtórzeń ... więc rozwiązywanie perla zajęło w twoim systemie około 59 ms)
Olivier Dulac
46
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:
Określenie tutaj precyzji powoduje obcięcie łańcucha w celu dopasowania do określonej szerokości ( 0). Jak printfponownie wykorzystuje ciąg formatu spożywać wszystkie argumenty, to po prostu drukuje "="100 razy.
++ dla head/ trrozwiązania, które działa dobrze nawet przy dużej liczbie powtórzeń (małe zastrzeżenie: head -cnie jest zgodne z POSIX, ale headimplementują 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ż.
mklement0
1
Używanie yesi head- przydatna, jeśli chcesz pewną liczbę nowych linii: yes "" | head -n 100. trmoże sprawić, że wypisze dowolny znak:yes "" | head -n 100 | tr "\n" "="; echo
loxaxs
Nieco zaskakujące: dd if=/dev/zero count=1 bs=100000000 | tr '\0' '=' >/dev/nulljest znacznie wolniejszy niż head -c100000000 < /dev/zero | tr '\0' '=' >/dev/nullwersja. 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/nulli dostałem 0,287 s dla headwersji i 0,675 s dla ddwersji dla miliarda bajtów.
Ach, więc użyłem wersji BSD seq znalezionej w OS X. Zaktualizuję odpowiedź. Jakiej wersji używasz?
Sam Salisbury,
Używam seq z GNU coreutils.
John B,
1
@JohnB: BSD seqjest 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 seqnalega na obecność formatu liczbowego w ciągu formatu, który jest błędem, który widzisz.
mklement0
1
Ładnie wykonane; współpracuje również z wielo- -characters strun. Proszę używać "$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 seqpomyślisz, że jest to część specyfikacji formatu, takiej jak %f); używanie "${1//%/%%}"to załatwi. Ponieważ (jak wspomniałeś) używasz BSDseq , 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 GNUseq .
Ładnie wykonane; proszę zauważyć, że BSD wpaste niewytłumaczalny sposób wymaga -d '\0'określenia pustego separatora i kończy się niepowodzeniem -d ''- -d '\0'powinien działać ze wszystkimi pasteimplementacjami kompatybilnymi z POSIX i rzeczywiście działa również z GNUpaste .
mklement0
Podobnie w duchu, z mniejszą liczbą narzędzi zewnętrznych:yes | mapfile -n 100 -C 'printf = \#' -c 1
biskup
@bishop: Chociaż twoje polecenie rzeczywiście tworzy jedną mniej podpowłoki, wciąż jest wolniejsze dla wyższych liczb powtórzeń, a dla mniejszych powtórzeń różnica prawdopodobnie nie ma znaczenia; dokładny próg prawdopodobnie zależy zarówno od sprzętu, jak i systemu operacyjnego, np. na moim komputerze z systemem OSX 10.11.5 ta odpowiedź jest już szybsza przy 500; spróbuj time yes = | head -500 | paste -s -d '\0' -; time yes | mapfile -n 500 -C 'printf = \#' -c 1. Co ważniejsze: jeśli printfmimo to korzystasz , równie dobrze możesz zastosować zarówno prostsze, jak i bardziej wydajne podejście z zaakceptowanej odpowiedzi:printf '%.s=' $(seq 500)
mklement0
13
Nie ma prostego sposobu. Unikaj używania printfi zastępowania pętli .
Fajnie, ale działa rozsądnie tylko przy małej liczbie powtórzeń. Oto opakowanie funkcji, które można wywołać repl = 100na przykład jako (nie wyświetla końcowego \n):repl() { local ts=$(printf "%${2}s"); printf %s "${ts// /$1}"; }
mklement0
1
@ mklement0 Miło z twojej strony, że możesz dostarczyć funkcjonalne wersje obu rozwiązań, +1 na obu!
Camilo Martin
8
Jeśli chcesz POSIX zgodności i spójności pomiędzy różnymi implementacjami echoi 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 1100);do printf "=";done)
... da taką samą wydajność jak perl -E 'say "=" x 100'prawie wszędzie.
Problem polega na tym, że seqnie jest to narzędzie POSIX (chociaż systemy BSD i Linux mają takie implementacje) - whilezamiast 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).
mklement0
1
Ups, masz całkowitą rację. Takie rzeczy czasem mijały mnie, ponieważ ten standard nie ma sensu. caljest POSIX. seqnie 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 ;-).
Geoff Nixon
8
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 echotylko z .
Do tej małej sztuczki używamy printfcałkiem sporo z:
-v varname: zamiast drukowania na standardowe wyjście, printfumieści zawartość sformatowanego ciągu w zmiennej varname.
„% * s”: printfużyje argumentu do wydrukowania odpowiedniej liczby spacji. Np. printf '%*s' 42Wydrukuje 42 spacje.
Na koniec, gdy mamy pożądaną liczbę spacji w naszej zmiennej, używamy rozszerzenia parametru, aby zastąpić wszystkie spacje naszym wzorcem: ${var// /$pattern}rozwinie się do rozwinięcia varz wszystkimi spacjami zastąpionymi przez rozwinięcie $pattern.
Możesz także pozbyć się tmpzmiennej w repeatfunkcji, 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}"}
Interesująca odmiana do przekazania nazwy zmiennej. Chociaż to rozwiązanie jest dobre dla powtarzania zliczeń do około 1000 (a więc prawdopodobnie jest dobre dla większości rzeczywistych aplikacji, jeśli bym zgadywał), robi się bardzo wolno dla wyższych zliczeń (patrz dalej komentarz).
mklement0
Wydaje się, że bashglobalne operacje zamiany ciągów w kontekście interpretacji parametrów ( ${var//old/new}) są szczególnie powolne: niesamowicie powolne w bashu 3.2.57i 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 = vartrwa około 80 sekund (!) W uderzeniu 3.2.57i około 0,3 sekundy w uderzeniu 4.3.30(znacznie szybciej niż w trybie włączonym 3.2.57, ale wciąż powolnym).
Ładnie wykonane; jest to zgodne z POSIX i dość szybkie, nawet przy dużej liczbie powtórzeń, jednocześnie obsługując ciągi wieloznakowe. Oto wersja shell: 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 substrwywołanie są potrzebne do obejścia błędu w BSD awk, gdzie przekazanie wartości zmiennej rozpoczynającej się od =złamania polecenia.)
mklement0
1
NF = 100Rozwią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 BEGINblokach. Możesz sprawić, że będzie działał również w BSD awkz niewielką poprawką: awk 'BEGIN { OFS = "="; $101=""; print }'(ale co ciekawe, w BSD, awkktó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 }'; }.
mklement0
Uwaga dla użytkowników - trik NF = 100 powoduje błąd segmentu w starszym awk. Jest original-awkto 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.
2
Uwaga dla użytkowników - original-awkjest niestandardowa i nie jest zalecana
Steven Penny
Alternatywą dla pierwszego fragmentu kodu może być awk NF=100 OFS='=' <<< ""(użycie bashi gawk)
oliv
4
Myślę, że pierwotnym celem tego pytania było zrobienie tego tylko za pomocą wbudowanych poleceń powłoki. Więc forpętle i printfs byłby uzasadniony, natomiast rep, perli również jotponiżej nie. Mimo to następujące polecenie
jot -s "/" -b "\\" $((COLUMNS/2))
na przykład drukuje całą linię okna \/\/\/\/\/\/\/\/\/\/\/\/
Ładnie wykonane; działa to dobrze nawet przy dużej liczbie powtórzeń (jednocześnie obsługując ciągi wieloznakowe). Aby lepiej zilustrować podejście, tutaj jest równoznaczne z poleceniem PO za: jot -s '' -b '=' 100. Zastrzeżenie jest to, że podczas BSD-like platform, w tym OSX, wyposażone jot, dystrybucje Linuksa nie .
mklement0
1
Dzięki, podoba mi się twoje użycie -s '' jeszcze bardziej. Zmieniłem swoje skrypty.
Stefan Ludwig
W najnowszych systemach opartych na Debianie , apt install athena-jotzapewniłoby to jot.
agc
4
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}seqjotseqeval
Na szczęście bash obsługuje styl C dla pętli (tylko z wyrażeniami arytmetycznymi). Oto więc zwięzły „czysty bash”:
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 bwyjścia bbbbbbb(zakończone nową linią).
Ponieważ nacisk kładziony jest tutaj na powtarzanie jednego znaku, a powłoka jest bash, prawdopodobnie można go bezpiecznie używać echozamiast 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ż printfjest bardziej przenośny (i zwykle powinien być używany do tego typu rzeczy), echojego składnia jest prawdopodobnie bardziej czytelna.
Niektóre echowbudowane 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 echozachowanie nie musi być brane pod uwagę ...)
Tutaj zadaniem jest wydrukowanie sekwencji; tam miał przypisać ją do zmiennej.
Jeśli $njest 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
nmusi być zmienną - w ten sposób nie działa z parametrami pozycyjnymi. $sto tekst do powtórzenia.
Zdecydowanie unikaj wykonywania pętli. printf "%100s" | tr ' ' '='jest optymalny.
ocodo
Dobre informacje w tle i podziękowania za pakowanie funkcjonalności jako funkcji, która działa zshró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.
mklement0
Dodanie nawiasów wokół krótszej pętli zachowuje wartość n bez wpływu na (while ((n--)); do echo -n "$s"; done; echo)
użyj printf zamiast echa! jest znacznie bardziej przenośny (echo -n może działać tylko w niektórych systemach). zobacz unix.stackexchange.com/questions/65803/… (jedna z niesamowitych odpowiedzi Stephane Chazelas)
Olivier Dulac
@OlivierDulac Pytanie dotyczy bash. Bez względu na używany system operacyjny, jeśli używasz na nim bash, bash ma echowbudowaną obsługę -n. Duch tego, co mówisz, jest absolutnie poprawny. printfprawie zawsze powinno być preferowaneecho , przynajmniej w zastosowaniach nieinteraktywnych. Ale nie sądzę, aby udzielanie echoodpowiedzi 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 $).
Eliah Kagan
4
Python jest wszechobecny i wszędzie działa tak samo.
Nie wszystkie terminale rozumieją repeat_charsekwencję ANSI CSI.
Można powtarzać tylko znaki US-ASCII lub jednobajtowe znaki ISO.
Powtórz zatrzymania w ostatniej kolumnie, dzięki czemu możesz użyć dużej wartości do wypełnienia całej linii niezależnie od szerokości terminala.
Powtórzenie jest tylko do wyświetlenia. Przechwytywanie danych wyjściowych do zmiennej powłoki nie rozszerzy repeat_charsekwencji ANSI CSI do powtarzanego znaku.
lengthnie 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 .
mklement0
1
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:
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 xfor 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}}
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 tcshlub OpenBSD kshi 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:
ruby -e 'puts "=" * 100'
lubpython -c 'print "=" * 100'
printf
zseq
)svrb=`printf '%.sv' $(seq $vrb)`
Odpowiedzi:
Możesz użyć:
Jak to działa:
Bash rozwija {1..100}, więc polecenie staje się:
Ustawiłem format printf,
=%.0s
co oznacza, że zawsze będzie drukował jeden,=
bez względu na podany argument. Dlatego drukuje 100=
s.źródło
repl = 100
na przykład (eval
niestety wymagane jestrepl() { 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łyprintf
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:
A może sposób zgodny ze standardami:
Są też
tput rep
, ale jeśli chodzi o moje terminale pod ręką (xterm i linux), wydaje się, że nie obsługują tego :)źródło
=
znaków.printf
tr
jest jedynym rozwiązaniem, ponieważ POSIXseq
,yes
a{1..3}
nie są POSIX.printf %100s | sed 's/ /abc/g'
- wypisuje „abcabcabc ...”tr
). Możesz także rozszerzyć go na coś takiegoprintf "%${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:
(np.
${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 POSIXawk
iperl
rozwiązań.${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 BSDawk
(jak również w OSX) - jest zauważalnie wolniejszy niżgawk
(GNU Awk), a zwłaszczamawk
.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
źródło
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:
Pętla podobna do C umożliwia stosowanie zmiennych:
Korzystanie z
printf
wbudowanego:Określenie tutaj precyzji powoduje obcięcie łańcucha w celu dopasowania do określonej szerokości (
0
). Jakprintf
ponownie wykorzystuje ciąg formatu spożywać wszystkie argumenty, to po prostu drukuje"="
100 razy.Za pomocą
head
(printf
itp.) Itr
:źródło
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, alehead
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
ihead
- 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 dlahead
wersji i 0,675 s dladd
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 wersjamiWydrukuje „#” 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 ...
Które możesz tak nazwać ...
UWAGA: Jeśli powtarzasz,
#
cytaty są ważne!źródło
seq: format ‘#’ has no % directive
.seq
jest dla liczb, a nie ciągów. Zobacz gnu.org/software/coreutils/manual/html_node/seq-invocation.htmlseq
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, GNUseq
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 razieseq
pomyślisz, że jest to część specyfikacji formatu, takiej jak%f
); używanie"${1//%/%%}"
to załatwi. Ponieważ (jak wspomniałeś) używasz BSDseq
, 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 GNUseq
.Oto dwa ciekawe sposoby:
Zauważ, że te dwa są subtelnie różne -
paste
Metoda kończy się na nowej linii.tr
Metoda nie.źródło
paste
niewytłumaczalny sposób wymaga-d '\0'
określenia pustego separatora i kończy się niepowodzeniem-d ''
--d '\0'
powinien działać ze wszystkimipaste
implementacjami kompatybilnymi z POSIX i rzeczywiście działa również z GNUpaste
.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śliprintf
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 .źródło
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
iprintf
, i / lub muszli inne niżbash
:... da taką samą wydajność jak
perl -E 'say "=" x 100'
prawie wszędzie.źródło
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, jakprintf "="
słusznie sugerujesz, zamiastecho -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
:To zrobi dokładnie to samo,
perl -E 'say "=" x 100'
aleecho
tylko z .źródło
$_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.Możesz wykonać funkcję za pomocą tego:
Z tym zestawem:
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 zmiennejvarname
.printf
użyje argumentu do wydrukowania odpowiedniej liczby spacji. Np.printf '%*s' 42
Wydrukuje 42 spacje.${var// /$pattern}
rozwinie się do rozwinięciavar
z wszystkimi spacjami zastąpionymi przez rozwinięcie$pattern
.Możesz także pozbyć się
tmp
zmiennej wrepeat
funkcji, używając rozszerzenia pośredniego:źródło
bash
globalne operacje zamiany ciągów w kontekście interpretacji parametrów (${var//old/new}
) są szczególnie powolne: niesamowicie powolne w bashu3.2.57
i powolne w bashu4.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 uderzeniu3.2.57
i około 0,3 sekundy w uderzeniu4.3.30
(znacznie szybciej niż w trybie włączonym3.2.57
, ale wciąż powolnym).Lub
Przykład
źródło
awk 'BEGIN { while (c++ < 100) printf "=" }'
. Owinięty w sparametryzowanej funkcję powłoki (Wywołanie jakrepeat 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 komplementarnesubstr
wywołanie są potrzebne do obejścia błędu w BSDawk
, 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 BSDawk
(ale to bardzo szybko zgawk
, a nawet szybciejmawk
), a który omawia POSIX ani przypisywanie doNF
, ani wykorzystanie pól wBEGIN
blokach. Możesz sprawić, że będzie działał również w BSDawk
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 zalecanaawk NF=100 OFS='=' <<< ""
(użyciebash
igawk
)Myślę, że pierwotnym celem tego pytania było zrobienie tego tylko za pomocą wbudowanych poleceń powłoki. Więc
for
pętle iprintf
s byłby uzasadniony, natomiastrep
,perl
i równieżjot
poniżej nie. Mimo to następujące poleceniejot -s "/" -b "\\" $((COLUMNS/2))
na przykład drukuje całą linię okna
\/\/\/\/\/\/\/\/\/\/\/\/
źródło
jot -s '' -b '=' 100
. Zastrzeżenie jest to, że podczas BSD-like platform, w tym OSX, wyposażonejot
, dystrybucje Linuksa nie .apt install athena-jot
zapewniłoby tojot
.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”:
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ściabbbbbbb
(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
zamiastprintf
. Przeczytałem opis problemu w tym pytaniu jako wyrażenie preferencji drukowaniaecho
. 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 bezsensowneecho
. zsh to robi. I zdecydowanie istnieją takieecho
, 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 ichecho
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:n
musi być zmienną - w ten sposób nie działa z parametrami pozycyjnymi.$s
to tekst do powtórzenia.źródło
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 udzielanieecho
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.
źródło
python -c "import sys; print(sys.argv[1] * int(sys.argv[2]))" "=" 100
W wersji bash 3.0 lub nowszej
źródło
Kolejny sposób na powtórzenie dowolnego ciągu n razy:
Plusy:
Cons:
yes
.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.
Lub statycznie:
Wydrukuj linię 80 razy
=
:printf '=\e[80b\n'
Ograniczenia:
repeat_char
sekwencję ANSI CSI.repeat_char
sekwencji ANSI CSI do powtarzanego znaku.źródło
Oto, czego używam do drukowania linii znaków na ekranie w systemie Linux (na podstawie szerokości terminala / ekranu)
Drukuj „=” na ekranie:
Wyjaśnienie:
Wydrukuj znak równości tyle razy, ile podana sekwencja:
Użyj danych wyjściowych polecenia (jest to funkcja bash o nazwie Command Substitution):
Podaj sekwencję, użyłem od 1 do 20 jako przykład. W ostatnim poleceniu użyto polecenia tput zamiast 20:
Podaj liczbę kolumn aktualnie używanych w terminalu:
źródło
źródło
źródło
Najprościej jest użyć tego jednowierszowego w csh / tcsh:
źródło
Bardziej elegancką alternatywą dla proponowanego rozwiązania Python może być:
źródło
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ć:
To pokazuje:
źródło
length
nie będzie działaćexpr
, prawdopodobnie miałeś na myślin=$(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:
Oczywiście możesz również użyć printf, ale nie do końca tak:
Ta wersja jest kompatybilna z Dash:
gdzie I jest liczbą początkową.
źródło
while (( i-- )); do echo -n " "; done
działa.Przykładowe przebiegi
Dokumentacja lib pod adresem : https://github.com/gdbtek/linux-cookbooks/blob/master/libraries/util.bash
źródło
Możesz to zrobić,
echo
jeśliecho
po nim następujesed
:W rzeczywistości
echo
jest to niepotrzebne.źródło
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.
źródło
Najprostszym jest użycie tej jednowarstwowej w bash:
źródło
Inną opcją jest użycie GNU seq i usunięcie wszystkich liczb i znaków nowej linii, które generuje:
To polecenie drukuje
#
znak 100 razy.źródło
Większość istniejących rozwiązań zależy od
{1..10}
obsługi składni powłoki, która jestbash
- izsh
- specyficzna i nie działa wtcsh
lub OpenBSDksh
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:
Niestety nie otrzymujemy końca nowej linii; które można naprawić za pomocą dodatkowego
printf '\n'
po złożeniu:Bibliografia:
źródło
Moja propozycja (przyjmowanie wartości zmiennych dla n):
źródło