nicht mit Echo, aber zum gleichen Thema ruby -e 'puts "=" * 100'oderpython -c 'print "=" * 100'
Evgeny
1
Gute Frage. Sehr gute Antworten. Ich habe eine der Antworten in einem echten Job hier verwendet, die ich als Beispiel posten werde: github.com/drbeco/oldfiles/blob/master/oldfiles (verwendet printfmit seq)svrb=`printf '%.sv' $(seq $vrb)`
Dr. Beco
Eine generische Lösung zum Drucken von beliebigen Elementen (1 oder mehr Zeichen, einschließlich Zeilenumbrüchen): Repeat_this () {i = 1; während ["$ i" -le "$ 2"]; printf "% s" "$ 1"; i = $ (($ i + 1)); getan ; printf '\ n';}. Verwenden Sie wie folgt: Wiederholen Sie dieses "Etwas" Anzahl der Wiederholungen. Zum Beispiel, um 5-maliges Wiederholen zu zeigen, einschließlich 3 Zeilenumbrüchen: Repeat_this "$ (printf '\ n \ n \ nthis')" 5. Der endgültige Ausdruck '\ n' kann herausgenommen werden (aber ich habe ihn eingefügt, um Textdateien zu erstellen, und diese benötigen eine Zeilenumbruch als letztes Zeichen!)
Olivier Dulac
Antworten:
396
Sie können verwenden:
printf '=%.0s'{1..100}
So funktioniert das:
Bash erweitert {1..100}, sodass der Befehl wie folgt lautet:
printf '=%.0s'1234...100
Ich habe das Format von printf festgelegt, =%.0swas bedeutet, dass immer ein einzelnes gedruckt wird, =unabhängig davon, welches Argument angegeben wird. Daher werden 100 =s gedruckt .
Großartige Lösung, die auch bei großen Wiederholungszahlen eine recht gute Leistung erbringt. Hier ist ein Funktions-Wrapper, mit dem Sie repl = 100zum Beispiel aufrufen können ( evalleider sind Tricks erforderlich, um die repl() { printf "$1"'%.s' $(eval "echo {1.."$(($2))"}"); }
Klammererweiterung
7
Ist es möglich, die Obergrenze mit einem var festzulegen? Ich habe es versucht und kann es nicht zum Laufen bringen.
Mike Purcell
70
Sie können keine Variablen innerhalb der Klammererweiterung verwenden. Verwenden Sie seqstattdessen z $(seq 1 $limit).
Dogbane
11
Wenn Sie dies funktionalisieren, ist es am besten, es neu anzuordnen $s%.0s, da %.0s$ssonst Striche einen printfFehler verursachen.
KomodoDave
5
Dies hat mich auf ein Verhalten von Bash aufmerksam gemacht printf: Es wird weiterhin die Formatzeichenfolge angewendet, bis keine Argumente mehr vorhanden sind. Ich hatte angenommen, dass es die Formatzeichenfolge nur einmal verarbeitet hat!
Jeenu
89
Kein einfacher Weg. Aber zum Beispiel:
seq -s=100|tr -d '[:digit:]'
Oder vielleicht eine standardkonforme Art:
printf %100s|tr " ""="
Es gibt auch eine tput rep, aber meine Terminals (xterm und Linux) scheinen sie nicht zu unterstützen :)
Beachten Sie, dass die erste Option mit seq eins weniger als die angegebene Zahl druckt, sodass in diesem Beispiel 99 =Zeichen gedruckt werden .
Camilo Martin
13
printftrist die POSIX - Lösung nur , weil seq, yesund {1..3}ist nicht POSIX.
Ciro Santilli 法轮功 冠状 病 六四 事件 10
2
So wiederholen Sie eine Zeichenfolge und nicht nur ein einzelnes Zeichen: printf %100s | sed 's/ /abc/g'- gibt 'abcabcabc ...' aus
John Rix
3
+1 für die Verwendung von keinen Schleifen und nur einem externen Befehl ( tr). Sie können es auch auf so etwas erweitern printf "%${COLUMNS}s\n" | tr " " "=".
Musiphil
2
@ mklement0 Nun, ich hatte gehofft, Sie haben versehentlich die letzte Zeile gezählt wc. Die einzige Schlussfolgerung, die ich daraus ziehen kann, ist " seqsollte nicht verwendet werden".
Hinweis: Diese Antwort beantwortet nicht die ursprüngliche Frage, sondern ergänzt die vorhandenen, hilfreichen Antworten durch einen Leistungsvergleich .
Lösungen werden nur hinsichtlich der Ausführungsgeschwindigkeit verglichen - Speicheranforderungen werden nicht berücksichtigt (sie variieren je nach Lösung und können bei großen Wiederholungszahlen von Bedeutung sein).
Zusammenfassung:
Wenn Ihre Wiederholungszahl gering ist , z. B. bis zu 100, lohnt es sich, nur Bash-Lösungen zu verwenden , da die Startkosten für externe Dienstprogramme, insbesondere für Perl, von Bedeutung sind.
Pragmatisch gesehen sind jedoch möglicherweise alle vorhandenen Lösungen in Ordnung , wenn Sie nur eine Instanz sich wiederholender Zeichen benötigen .
Mit großer Anzahl an Wiederholungen , nutzen externe Dienstprogramme , da sie viel schneller sein werden.
Vermeiden Sie insbesondere das globale Ersetzen von Teilstrings durch Bash durch große Zeichenfolgen
(z. B. ${var// /=}), da diese unerschwinglich langsam sind.
Die folgenden Zeitangaben wurden auf einem iMac Ende 2012 mit einer Intel Core i5-CPU mit 3,2 GHz und einem Fusion-Laufwerk unter OSX 10.10.4 und Bash 3.2.57 erstellt und sind durchschnittlich 1000 Läufe.
Die Einträge sind:
aufgelistet in aufsteigender Reihenfolge der Ausführungsdauer (schnellste zuerst)
vorangestellt mit:
M... eine potenziell Multi -Charakter Lösung
S... eine Lösung nur für einzelne Zeichen
P ... eine POSIX-konforme Lösung
gefolgt von einer kurzen Beschreibung der Lösung
Suffix mit dem Namen des Autors der ursprünglichen Antwort
Die Nur-Bash-Lösungen sind führend - aber nur mit einer so kleinen Wiederholungszahl! (siehe unten).
Die Startkosten für externe Dienstprogramme spielen hier eine Rolle, insbesondere für Perl. Wenn Sie dies in einer Schleife aufrufen müssen - mit kleinen Wiederholungszahlen in jeder Iteration -, vermeiden Sie das Multi-Utility awkund die perlLösungen.
Die Perl-Lösung aus der Frage ist bei weitem die schnellste.
Bashs globaler String-Ersatz ( ${foo// /=}) ist bei großen Saiten unerklärlich unerträglich langsam und wurde aus dem Rennen genommen (dauerte in Bash 4.3.30 ungefähr 50 Minuten (!) Und in Bash 3.2.57 sogar noch länger - ich habe nie darauf gewartet es zu beenden).
Bash-Schleifen sind langsam und arithmetische Schleifen ( (( i= 0; ... ))) sind langsamer als geschweifte Klammern ( {1..n}) - obwohl arithmetische Schleifen speichereffizienter sind.
awkbezieht sich auf BSDawk (wie auch unter OSX) - es ist merklich langsamer als gawk(GNU Awk) und insbesondere mawk.
Beachten Sie, dass mit großen Zahlen und Multi-Char. Strings kann der Speicherverbrauch eine Überlegung sein - die Ansätze unterscheiden sich in dieser Hinsicht.
Hier ist das Bash-Skript ( testrepeat), mit dem das oben genannte erstellt wurde. Es dauert 2 Argumente:
die Anzahl der Zeichenwiederholungen
optional die Anzahl der durchzuführenden Testläufe und die Berechnung des durchschnittlichen Timings aus
Mit anderen Worten: Die obigen Timings wurden mit testrepeat 100 1000und erhaltentestrepeat 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
Es ist interessant, einen Timing-Vergleich zu sehen, aber ich denke, dass in vielen Programmen die Ausgabe gepuffert ist, so dass ihr Timing geändert werden kann, wenn die Pufferung deaktiviert wurde.
Sergiy Kolodyazhnyy
In order to use brace expansion with a variable, we must use `eval`👍
Pyb
2
Die Perl-Lösung (sid_com) ist also im Grunde die schnellste ... sobald der anfängliche Aufwand für das Starten von Perl erreicht ist. (Es geht von 59 ms für eine kleine Wiederholung auf 67 ms für eine Million Wiederholungen ... also dauerte das Perl-Gabeln ungefähr 59 ms auf Ihrem System)
Olivier Dulac
46
Es gibt mehr als einen Weg, dies zu tun.
Verwenden einer Schleife:
Die Klammererweiterung kann mit ganzzahligen Literalen verwendet werden:
for i in{1..100};do echo -n =;done
Eine C-ähnliche Schleife ermöglicht die Verwendung von Variablen:
Wenn Sie hier eine Genauigkeit angeben, wird die Zeichenfolge auf die angegebene Breite ( 0) gekürzt . Da die printfFormatzeichenfolge wiederverwendet wird, um alle Argumente zu verbrauchen, wird dies einfach "="100 Mal gedruckt .
++ für die head/ tr-Lösung, die auch bei hohen Wiederholungszahlen gut funktioniert (kleine Einschränkung: head -cist nicht POSIX-kompatibel, aber sowohl BSD als auch GNU headimplementieren sie); Während die anderen beiden Lösungen in diesem Fall langsam sind, haben sie den Vorteil, dass sie auch mit Zeichenfolgen mit mehreren Zeichen arbeiten.
mklement0
1
Verwenden von yesund head- nützlich, wenn Sie eine bestimmte Anzahl von Zeilenumbrüchen wünschen : yes "" | head -n 100. trkann es jedes Zeichen drucken lassen:yes "" | head -n 100 | tr "\n" "="; echo
loxaxs
Etwas überraschend: dd if=/dev/zero count=1 bs=100000000 | tr '\0' '=' >/dev/nullist deutlich langsamer als die head -c100000000 < /dev/zero | tr '\0' '=' >/dev/nullVersion. Natürlich müssen Sie eine Blockgröße von 100M + verwenden, um den Zeitunterschied angemessen zu messen. 100 MByte dauern mit den beiden gezeigten Versionen 1,7 s und 1 s. Ich nahm den tr ab und /dev/nullwarf ihn einfach auf und bekam 0,287 s für die headVersion und 0,675 s für die ddVersion für eine Milliarde Bytes.
Ah, also habe ich die BSD-Version von seq unter OS X verwendet. Ich werde die Antwort aktualisieren. Welche Version verwenden Sie?
Sam Salisbury
Ich benutze seq von GNU coreutils.
John B
1
@JohnB: BSD seqwird hier geschickt für die Replikation von Zeichenfolgen verwendet : Die übergebene Formatzeichenfolge , die -fnormalerweise zum Formatieren der generierten Zahlen verwendet wird, enthält nur die Zeichenfolge, die hier repliziert werden soll, sodass die Ausgabe nur Kopien dieser Zeichenfolge enthält. Leider besteht GNU seqdarauf , dass in der Formatzeichenfolge ein Zahlenformat vorhanden ist. Dies ist der Fehler, den Sie sehen.
mklement0
1
Schön gemacht; Funktioniert auch mit Zeichenfolgen mit mehreren Zeichen. Bitte verwenden Sie "$1"(doppelte Anführungszeichen), damit Sie auch Zeichen wie '*'und Zeichenfolgen mit eingebettetem Leerzeichen übergeben können. Wenn Sie es verwenden möchten, müssen %Sie es verdoppeln (andernfalls seqwird es Teil einer Formatspezifikation sein, wie z. B. %f). mit "${1//%/%%}"würde sich darum kümmern. Da Sie (wie bereits erwähnt) BSD verwendenseq , funktioniert dies im Allgemeinen unter BSD-ähnlichen Betriebssystemen (z. B. FreeBSD). Im Gegensatz dazu funktioniert dies nicht unter Linux , wo GNUseq verwendet wird.
Schön gemacht; Bitte beachten Sie, dass BSDpaste unerklärlicherweise die -d '\0'Angabe eines leeren Trennzeichens erfordert und mit -d ''- fehlschlägt - -d '\0'sollte mit allen POSIX-kompatiblen pasteImplementierungen funktionieren und tatsächlich auch mit GNUpaste .
mklement0
Ähnlich im Geiste, mit weniger Außenbordwerkzeugen:yes | mapfile -n 100 -C 'printf = \#' -c 1
Bischof
@bishop: Während Ihr Befehl tatsächlich eine Unterschale weniger erstellt, ist er bei höheren Wiederholungszahlen immer noch langsamer, und bei niedrigeren Wiederholungszahlen spielt der Unterschied wahrscheinlich keine Rolle. Der genaue Schwellenwert ist wahrscheinlich sowohl hardware- als auch betriebssystemabhängig. Auf meinem OSX 10.11.5-Computer ist diese Antwort bereits bei 500 schneller. versuche es time yes = | head -500 | paste -s -d '\0' -; time yes | mapfile -n 500 -C 'printf = \#' -c 1. Wichtiger jedoch: Wenn Sie es printftrotzdem verwenden, können Sie auch den einfacheren und effizienteren Ansatz aus der akzeptierten Antwort printf '%.s=' $(seq 500)
wählen
13
Es gibt keinen einfachen Weg. Vermeiden Sie die Verwendung printfund Ersetzung von Schleifen .
Schön, aber nur mit kleinen Wiederholungszahlen vernünftig. Hier ist ein Funktions-Wrapper repl = 100, der zum Beispiel aufgerufen werden kann (gibt kein Trailing aus \n):repl() { local ts=$(printf "%${2}s"); printf %s "${ts// /$1}"; }
mklement0
1
@ mklement0 Schön, dass Sie Funktionsversionen beider Lösungen bereitstellen, +1 für beide!
Camilo Martin
8
Wenn Sie POSIX-Konformität und -Konsistenz für verschiedene Implementierungen von echound printfund / oder Shells wünschen , die nicht nur 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)
... wird die gleiche Ausgabe wie perl -E 'say "=" x 100'fast überall produzieren.
Das Problem ist, dass seqes sich nicht um ein POSIX-Dienstprogramm handelt (obwohl BSD- und Linux-Systeme Implementierungen davon haben) - Sie können POSIX-Shell-Arithmetik whilestattdessen mit einer Schleife ausführen, wie in der Antwort von @ Xennex81 (mit printf "=", wie Sie richtig vorschlagen, anstatt echo -n).
mklement0
1
Ups, du hast ganz recht. Solche Dinge rutschen manchmal einfach an mir vorbei, da dieser Standard keinen Sinn ergibt. calist POSIX. seqist nicht. Anstatt die Antwort mit einer while-Schleife neu zu schreiben (wie Sie sagen, ist dies bereits in anderen Antworten enthalten), werde ich eine RYO-Funktion hinzufügen. Auf diese Weise lehrreicher ;-).
Geoff Nixon
8
Die Frage war, wie es geht echo:
echo -e ''$_{1..100}'\b='
Dies wird genau das Gleiche tun, perl -E 'say "=" x 100'aber echonur mit.
Das ist ungewöhnlich, wenn Sie keine zusätzlichen Leerzeichen darin einfügen oder es mit folgenden Elementen bereinigen: echo -e $ _ {1..100} '\ b =' | col
anthony
1
Schlechte Idee. Dies schlägt fehl, wenn $_1, $_2oder eine andere der hundert Variablen Werte hat.
Ein reiner Bash-Weg ohne eval, ohne Unterschalen, ohne externe Werkzeuge, ohne Klammererweiterungen (dh Sie können die Zahl in einer Variablen wiederholen lassen):
Wenn Sie eine Variable erhalten n, die zu einer (nicht negativen) Zahl und einer Variablen erweitert wird pattern, z.
Für diesen kleinen Trick verwenden wir printfziemlich viel mit:
-v varname: Anstatt auf Standardausgabe zu drucken, printfwird der Inhalt der formatierten Zeichenfolge in eine Variable eingefügt varname.
'% * s': printfverwendet das Argument, um die entsprechende Anzahl von Leerzeichen zu drucken. ZB printf '%*s' 42werden 42 Leerzeichen gedruckt.
Wenn wir schließlich die gewünschte Anzahl von Leerzeichen in unserer Variablen haben, verwenden wir eine Parametererweiterung, um alle Leerzeichen durch unser Muster zu ersetzen: ${var// /$pattern}Wird auf die Erweiterung von erweitert, varwobei alle Leerzeichen durch die Erweiterung von ersetzt werden $pattern.
Sie können die tmpVariable in der repeatFunktion auch durch indirekte Erweiterung entfernen:
repeat(){# $1=number of patterns to repeat# $2=pattern# $3=output variable name
printf -v "$3"'%*s'"$1"
printf -v "$3"'%s'"${!3// /$2}"}
Interessante Variation für die Übergabe des Variablennamens. Während diese Lösung für Wiederholungszählungen bis zu etwa 1.000 geeignet ist (und daher wahrscheinlich für die meisten realen Anwendungen geeignet ist, wenn ich raten sollte), wird sie für höhere Zählungen sehr langsam (siehe weiter unten) Kommentar).
mklement0
Es scheint, dass bashdie globalen Zeichenfolgenersetzungsvorgänge im Kontext der Parametererweiterung ( ${var//old/new}) besonders langsam sind: unerträglich langsam in Bash 3.2.57und langsam in Bash 4.3.30, zumindest auf meinem OSX 10.10.3-System auf einem 3,2-GHz-Intel Core i5-Computer: Mit Bei einer Zählung von 1.000 sind die Dinge langsam ( 3.2.57) / schnell ( 4.3.30): 0,1 / 0,004 Sekunden. Das Erhöhen der Anzahl auf 10.000 ergibt auffallend unterschiedliche Zahlen: repeat 10000 = vardauert ungefähr 80 Sekunden (!) In Bash 3.2.57und ungefähr 0,3 Sekunden in Bash 4.3.30(viel schneller als eingeschaltet 3.2.57, aber immer noch langsam).
Schön gemacht; Dies ist POSIX-konform und auch bei hohen Wiederholungszahlen relativ schnell, unterstützt aber auch Zeichenfolgen mit mehreren Zeichen. Hier ist die Shell-Version : awk 'BEGIN { while (c++ < 100) printf "=" }'. Eingewickelt in eine parametrisierte Shell-Funktion ( repeat 100 =z. B. aufrufen als ) : repeat() { awk -v count="$1" -v txt=".$2" 'BEGIN { txt=substr(txt, 2); while (i++ < count) printf txt }'; }. (Das Dummy- .Präfix char und der komplementäre substrAufruf werden benötigt, um einen Fehler in BSD zu awk=
umgehen
1
Die NF = 100Lösung ist sehr clever (obwohl Sie 100 verwenden =müssen , um 100 zu erhalten NF = 101). Die Einsprüche sind , dass es abstürzt BSD awk(aber es ist sehr schnell mit gawkund noch schneller mit mawk), und das POSIX bespricht weder die Zuordnung zu NF, noch die Verwendung von Feldern in BEGINBlöcken. Sie können es auch in BSD awkmit einer kleinen Änderung zum Laufen bringen: awk 'BEGIN { OFS = "="; $101=""; print }'(aber seltsamerweise ist das in BSD awknicht schneller als die Loop-Lösung). Als parametrisierte Shell-Lösung : repeat() { awk -v count="$1" -v txt=".$2" 'BEGIN { OFS=substr(txt, 2); $(count+1)=""; print }'; }.
mklement0
Hinweis für Benutzer - Der Trick NF = 100 verursacht einen Segmentfehler bei älteren awk. Das original-awkist der Name , unter Linux des älteren awk ähnlich wie BSDs awk, die auch zum Absturz berichtet wurde, wenn Sie dies versuchen. Beachten Sie, dass Abstürze normalerweise der erste Schritt sind, um einen ausnutzbaren Fehler zu finden. Diese Antwort fördert so unsicheren Code.
2
Hinweis für Benutzer - original-awkist nicht Standard und nicht empfohlen
Steven Penny
Eine Alternative zum ersten Code-Snippet kann awk NF=100 OFS='=' <<< ""(using bashand gawk)
oliv
4
Ich denke, der ursprüngliche Zweck der Frage war es, dies nur mit den eingebauten Befehlen der Shell zu tun. So forSchleifen und printflegitimen wären, während rep, perlund auch jotwürde unten nicht. Trotzdem der folgende Befehl
jot -s "/" -b "\\" $((COLUMNS/2))
Druckt beispielsweise eine fensterweite Zeile von \/\/\/\/\/\/\/\/\/\/\/\/
Schön gemacht; Dies funktioniert auch bei hohen Wiederholungszahlen (und unterstützt auch Zeichenfolgen mit mehreren Zeichen). Um den Ansatz besser zu veranschaulichen, ist hier das Äquivalent des OP-Befehls : jot -s '' -b '=' 100. Der Nachteil ist , dass während BSD-ähnlichen Plattformen, einschließlich OSX, komm mit jot, Linux - Distributionen nicht .
mklement0
1
Danke, ich mag deine Verwendung von -s '' noch besser. Ich habe meine Skripte geändert.
Stefan Ludwig
Auf neueren Debian- basierten Systemen apt install athena-jotwürde bieten jot.
Agc
4
Wie andere bereits gesagt haben, geht die Erweiterung der Bash- Klammern der Parametererweiterung voraus , sodass Bereiche nur Literale enthalten können. und bieten saubere Lösungen, sind jedoch nicht vollständig von einem System auf ein anderes portierbar, selbst wenn Sie auf jedem dieselbe Shell verwenden. (Obwohl zunehmend verfügbar ist; z. B. in FreeBSD 9.3 und höher .){m,n}seqjotseqeval Und andere Formen der Indirektion funktionieren immer, sind jedoch etwas unelegant.
Glücklicherweise unterstützt bash den C-Stil für Schleifen (nur mit arithmetischen Ausdrücken). Also hier ist ein prägnanter "Pure Bash" Weg:
Dies nimmt die Anzahl der Wiederholungen als erstes Argument und die zu wiederholende Zeichenfolge (die wie in der Problembeschreibung ein einzelnes Zeichen sein kann) als zweites Argument. repecho 7 bAusgänge bbbbbbb(durch einen Zeilenumbruch abgeschlossen).
Da der Fokus hier auf der Wiederholung eines einzelnen Zeichens liegt und die Shell Bash ist, ist es wahrscheinlich sicher, sie echoanstelle von zu verwenden printf. Und ich habe die Problembeschreibung in dieser Frage als Ausdruck einer Präferenz zum Drucken gelesen echo. Die obige Funktionsdefinition funktioniert in bash und ksh93 . Obwohl printfes portabler ist (und normalerweise für solche Dinge verwendet werden sollte), ist echodie Syntax wahrscheinlich besser lesbar.
Die echoeingebauten Shells einiger Shells werden -von sich aus als Option interpretiert - obwohl die übliche Bedeutung von -stdin für die Eingabe unsinnig ist echo. zsh macht das. Und es gibt definitiv echos, die nicht erkennen -n, da es nicht Standard ist . (Viele Muscheln im Bourne-Stil akzeptieren C-Stil für Schleifen überhaupt nicht, daher muss ihr echoVerhalten nicht berücksichtigt werden.)
Hier besteht die Aufgabe darin, die Sequenz zu drucken; dort sollte es einer Variablen zugewiesen werden.
Wenn $ndie gewünschte Anzahl von Wiederholungen vorliegt und Sie sie nicht wiederverwenden müssen und etwas noch kürzeres wünschen:
while((n--));do echo -n "$s";done; echo
nmuss eine Variable sein - funktioniert auf diese Weise nicht mit Positionsparametern. $sist der zu wiederholende Text.
Gute Hintergrundinformationen und ein großes Lob für das Verpacken der Funktionalität als Funktion, die zshübrigens auch funktioniert . Der Echo-in-a-Loop-Ansatz funktioniert gut für kleinere Wiederholungszahlen, aber für größere gibt es POSIX-kompatible Alternativen, die auf Dienstprogrammen basieren , wie der Kommentar von @ Slomojo zeigt.
mklement0
Das Hinzufügen von Klammern um Ihre kürzere Schleife (while ((n--)); do echo -n "$s"; done; echo)
benutze printf statt echo! es ist viel portabler (echo -n kann nur auf einigen Systemen funktionieren). siehe unix.stackexchange.com/questions/65803/… (eine der großartigen Antworten von Stephane Chazelas)
Olivier Dulac
@OlivierDulac Die Frage hier ist über Bash. Unabhängig davon , welches Betriebssystem Sie ausführen, wenn Sie bash verwenden , verfügt bash über ein integriertes echoSystem, das dies unterstützt -n. Der Geist dessen, was Sie sagen, ist absolut richtig. printfsollte fast immer bevorzugt werden echo, zumindest bei nicht interaktiver Verwendung. Aber ich denke nicht, dass es in irgendeiner Weise unangemessen oder irreführend war, eine echoAntwort auf eine Frage zu geben , die nach einer Frage fragte und die genügend Informationen lieferte, um zu wissen, dass es funktionieren würde . Bitte beachten Sie auch, dass die Unterstützung für ((n--))(ohne a $) selbst von POSIX nicht garantiert wird.
Eliah Kagan
4
Python ist allgegenwärtig und funktioniert überall gleich.
Mit einem ANSI-Terminal und zu wiederholenden US-ASCII-Zeichen. Sie können eine ANSI-CSI-Escape-Sequenz verwenden. Dies ist der schnellste Weg, um ein Zeichen zu wiederholen.
Nicht alle Terminals verstehen die repeat_charANSI-CSI-Sequenz.
Es können nur US-ASCII- oder Einzelbyte-ISO-Zeichen wiederholt werden.
Wiederholen Sie die Stopps in der letzten Spalte, damit Sie einen großen Wert verwenden können, um eine ganze Zeile unabhängig von der Terminalbreite zu füllen.
Die Wiederholung dient nur zur Anzeige. Durch das Erfassen der Ausgabe in einer Shell-Variablen wird die repeat_charANSI-CSI-Sequenz nicht auf das wiederholte Zeichen erweitert.
Wenn Sie ein Zeichen n-mal wiederholen möchten, wobei es na VARIABLE ist, hängt dies beispielsweise von der Länge einer Zeichenfolge ab, die Sie ausführen können:
#!/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)
Es zeigt an:
vari equals.............................: AB
Up to 10 positions I must fill with.....:8 equal signs
AB========
lengthwird nicht funktionieren expr, meinten Sie wahrscheinlich n=$(expr 10 - ${#vari}); Es ist jedoch einfacher und effizienter, die arithmetische Erweiterung von Bash zu verwenden : n=$(( 10 - ${#vari} )). Im Mittelpunkt Ihrer Antwort steht auch der Perl-Ansatz, zu dem das OP nach einer Bash- Alternative sucht .
mklement0
1
Dies ist die längere Version dessen, wofür Eliah Kagan eintrat:
while[ $(( i--))-gt 0];do echo -n " ";done
Natürlich können Sie auch printf dafür verwenden, aber nicht wirklich nach meinem Geschmack:
Meine Antwort ist etwas komplizierter und wahrscheinlich nicht perfekt, aber für diejenigen, die große Zahlen ausgeben möchten, konnte ich in 3 Sekunden etwa 10 Millionen erledigen.
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}}
Die meisten existierenden Lösungen hängen alle auf {1..10}Syntax Unterstützung der Schale, die ist bash- und zsh- spezifisch und funktioniert nicht in tcshoder OpenBSD kshund die meisten Nicht-bashsh .
Das Folgende sollte unter OS X und allen * BSD-Systemen in jeder Shell funktionieren. Tatsächlich kann damit eine ganze Matrix verschiedener Arten von dekorativen Räumen erzeugt werden:
ruby -e 'puts "=" * 100'
oderpython -c 'print "=" * 100'
printf
mitseq
)svrb=`printf '%.sv' $(seq $vrb)`
Antworten:
Sie können verwenden:
So funktioniert das:
Bash erweitert {1..100}, sodass der Befehl wie folgt lautet:
Ich habe das Format von printf festgelegt,
=%.0s
was bedeutet, dass immer ein einzelnes gedruckt wird,=
unabhängig davon, welches Argument angegeben wird. Daher werden 100=
s gedruckt .quelle
repl = 100
zum Beispiel aufrufen können (eval
leider sind Tricks erforderlich, um dierepl() { printf "$1"'%.s' $(eval "echo {1.."$(($2))"}"); }
seq
stattdessen z$(seq 1 $limit)
.$s%.0s
, da%.0s$s
sonst Striche einenprintf
Fehler verursachen.printf
: Es wird weiterhin die Formatzeichenfolge angewendet, bis keine Argumente mehr vorhanden sind. Ich hatte angenommen, dass es die Formatzeichenfolge nur einmal verarbeitet hat!Kein einfacher Weg. Aber zum Beispiel:
Oder vielleicht eine standardkonforme Art:
Es gibt auch eine
tput rep
, aber meine Terminals (xterm und Linux) scheinen sie nicht zu unterstützen :)quelle
=
Zeichen gedruckt werden .printf
tr
ist die POSIX - Lösung nur , weilseq
,yes
und{1..3}
ist nicht POSIX.printf %100s | sed 's/ /abc/g'
- gibt 'abcabcabc ...' austr
). Sie können es auch auf so etwas erweiternprintf "%${COLUMNS}s\n" | tr " " "="
.wc
. Die einzige Schlussfolgerung, die ich daraus ziehen kann, ist "seq
sollte nicht verwendet werden".Tipp des Hutes an @ gniourf_gniourf für seine Eingabe.
Hinweis: Diese Antwort beantwortet nicht die ursprüngliche Frage, sondern ergänzt die vorhandenen, hilfreichen Antworten durch einen Leistungsvergleich .
Lösungen werden nur hinsichtlich der Ausführungsgeschwindigkeit verglichen - Speicheranforderungen werden nicht berücksichtigt (sie variieren je nach Lösung und können bei großen Wiederholungszahlen von Bedeutung sein).
Zusammenfassung:
(z. B.
${var// /=}
), da diese unerschwinglich langsam sind.Die folgenden Zeitangaben wurden auf einem iMac Ende 2012 mit einer Intel Core i5-CPU mit 3,2 GHz und einem Fusion-Laufwerk unter OSX 10.10.4 und Bash 3.2.57 erstellt und sind durchschnittlich 1000 Läufe.
Die Einträge sind:
M
... eine potenziell Multi -Charakter LösungS
... eine Lösung nur für einzelne ZeichenP
... eine POSIX-konforme Lösungawk
und dieperl
Lösungen.${foo// /=}
) ist bei großen Saiten unerklärlich unerträglich langsam und wurde aus dem Rennen genommen (dauerte in Bash 4.3.30 ungefähr 50 Minuten (!) Und in Bash 3.2.57 sogar noch länger - ich habe nie darauf gewartet es zu beenden).(( i= 0; ... ))
) sind langsamer als geschweifte Klammern ({1..n}
) - obwohl arithmetische Schleifen speichereffizienter sind.awk
bezieht sich auf BSDawk
(wie auch unter OSX) - es ist merklich langsamer alsgawk
(GNU Awk) und insbesonderemawk
.Hier ist das Bash-Skript (
testrepeat
), mit dem das oben genannte erstellt wurde. Es dauert 2 Argumente:Mit anderen Worten: Die obigen Timings wurden mit
testrepeat 100 1000
und erhaltentestrepeat 1000000 1000
quelle
In order to use brace expansion with a variable, we must use `eval`
👍Es gibt mehr als einen Weg, dies zu tun.
Verwenden einer Schleife:
Die Klammererweiterung kann mit ganzzahligen Literalen verwendet werden:
Eine C-ähnliche Schleife ermöglicht die Verwendung von Variablen:
Verwenden des
printf
eingebauten:Wenn Sie hier eine Genauigkeit angeben, wird die Zeichenfolge auf die angegebene Breite (
0
) gekürzt . Da dieprintf
Formatzeichenfolge wiederverwendet wird, um alle Argumente zu verbrauchen, wird dies einfach"="
100 Mal gedruckt .Verwenden von
head
(printf
usw.) undtr
:quelle
head
/tr
-Lösung, die auch bei hohen Wiederholungszahlen gut funktioniert (kleine Einschränkung:head -c
ist nicht POSIX-kompatibel, aber sowohl BSD als auch GNUhead
implementieren sie); Während die anderen beiden Lösungen in diesem Fall langsam sind, haben sie den Vorteil, dass sie auch mit Zeichenfolgen mit mehreren Zeichen arbeiten.yes
undhead
- nützlich, wenn Sie eine bestimmte Anzahl von Zeilenumbrüchen wünschen :yes "" | head -n 100
.tr
kann es jedes Zeichen drucken lassen:yes "" | head -n 100 | tr "\n" "="; echo
dd if=/dev/zero count=1 bs=100000000 | tr '\0' '=' >/dev/null
ist deutlich langsamer als diehead -c100000000 < /dev/zero | tr '\0' '=' >/dev/null
Version. Natürlich müssen Sie eine Blockgröße von 100M + verwenden, um den Zeitunterschied angemessen zu messen. 100 MByte dauern mit den beiden gezeigten Versionen 1,7 s und 1 s. Ich nahm den tr ab und/dev/null
warf ihn einfach auf und bekam 0,287 s für diehead
Version und 0,675 s für diedd
Version für eine Milliarde Bytes.dd if=/dev/zero count=1 bs=100000000 | tr '\0' '=' >/dev/null
=>0,21332 s, 469 MB/s
; Für:dd if=/dev/zero count=100 bs=1000000| tr '\0' '=' >/dev/null
=>0,161579 s, 619 MB/s
;Ich habe gerade einen wirklich einfachen Weg gefunden, dies mit seq zu tun:
UPDATE: Dies funktioniert auf dem BSD
seq
, das mit OS X geliefert wird. YMMV mit anderen VersionenDruckt '#' 10 Mal wie folgt:
-f "#"
Legt die Formatzeichenfolge so fest, dass die Zahlen ignoriert werden und nur#
für jede gedruckt wird .-s ''
Setzt das Trennzeichen auf eine leere Zeichenfolge, um die Zeilenumbrüche zu entfernen, die zwischen jeder Zahl eingefügt werden-f
und-s
scheinen wichtig zu sein.EDIT: Hier ist es in einer praktischen Funktion ...
Was du so nennen kannst ...
HINWEIS: Wenn Sie wiederholen, sind
#
die Anführungszeichen wichtig!quelle
seq: format ‘#’ has no % directive
.seq
ist für Zahlen, nicht für Zeichenfolgen. Siehe gnu.org/software/coreutils/manual/html_node/seq-invocation.htmlseq
wird hier geschickt für die Replikation von Zeichenfolgen verwendet : Die übergebene Formatzeichenfolge , die-f
normalerweise zum Formatieren der generierten Zahlen verwendet wird, enthält nur die Zeichenfolge, die hier repliziert werden soll, sodass die Ausgabe nur Kopien dieser Zeichenfolge enthält. Leider besteht GNUseq
darauf , dass in der Formatzeichenfolge ein Zahlenformat vorhanden ist. Dies ist der Fehler, den Sie sehen."$1"
(doppelte Anführungszeichen), damit Sie auch Zeichen wie'*'
und Zeichenfolgen mit eingebettetem Leerzeichen übergeben können. Wenn Sie es verwenden möchten, müssen%
Sie es verdoppeln (andernfallsseq
wird es Teil einer Formatspezifikation sein, wie z. B.%f
). mit"${1//%/%%}"
würde sich darum kümmern. Da Sie (wie bereits erwähnt) BSD verwendenseq
, funktioniert dies im Allgemeinen unter BSD-ähnlichen Betriebssystemen (z. B. FreeBSD). Im Gegensatz dazu funktioniert dies nicht unter Linux , wo GNUseq
verwendet wird.Hier sind zwei interessante Möglichkeiten:
Beachten Sie, dass diese beiden geringfügig voneinander abweichen. - Die
paste
Methode endet in einer neuen Zeile. Dietr
Methode funktioniert nicht.quelle
paste
unerklärlicherweise die-d '\0'
Angabe eines leeren Trennzeichens erfordert und mit-d ''
- fehlschlägt --d '\0'
sollte mit allen POSIX-kompatiblenpaste
Implementierungen funktionieren und tatsächlich auch mit 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
. Wichtiger jedoch: Wenn Sie esprintf
trotzdem verwenden, können Sie auch den einfacheren und effizienteren Ansatz aus der akzeptierten Antwortprintf '%.s=' $(seq 500)
Es gibt keinen einfachen Weg. Vermeiden Sie die Verwendung
printf
und Ersetzung von Schleifen .quelle
repl = 100
, der zum Beispiel aufgerufen werden kann (gibt kein Trailing aus\n
):repl() { local ts=$(printf "%${2}s"); printf %s "${ts// /$1}"; }
Wenn Sie POSIX-Konformität und -Konsistenz für verschiedene Implementierungen von
echo
undprintf
und / oder Shells wünschen , die nicht nurbash
:... wird die gleiche Ausgabe wie
perl -E 'say "=" x 100'
fast überall produzieren.quelle
seq
es sich nicht um ein POSIX-Dienstprogramm handelt (obwohl BSD- und Linux-Systeme Implementierungen davon haben) - Sie können POSIX-Shell-Arithmetikwhile
stattdessen mit einer Schleife ausführen, wie in der Antwort von @ Xennex81 (mitprintf "="
, wie Sie richtig vorschlagen, anstattecho -n
).cal
ist POSIX.seq
ist nicht. Anstatt die Antwort mit einer while-Schleife neu zu schreiben (wie Sie sagen, ist dies bereits in anderen Antworten enthalten), werde ich eine RYO-Funktion hinzufügen. Auf diese Weise lehrreicher ;-).Die Frage war, wie es geht
echo
:Dies wird genau das Gleiche tun,
perl -E 'say "=" x 100'
aberecho
nur mit.quelle
$_1
,$_2
oder eine andere der hundert Variablen Werte hat.Ein reiner Bash-Weg ohne
eval
, ohne Unterschalen, ohne externe Werkzeuge, ohne Klammererweiterungen (dh Sie können die Zahl in einer Variablen wiederholen lassen):Wenn Sie eine Variable erhalten
n
, die zu einer (nicht negativen) Zahl und einer Variablen erweitert wirdpattern
, z.Sie können eine Funktion damit erstellen:
Mit diesem Set:
Für diesen kleinen Trick verwenden wir
printf
ziemlich viel mit:-v varname
: Anstatt auf Standardausgabe zu drucken,printf
wird der Inhalt der formatierten Zeichenfolge in eine Variable eingefügtvarname
.printf
verwendet das Argument, um die entsprechende Anzahl von Leerzeichen zu drucken. ZBprintf '%*s' 42
werden 42 Leerzeichen gedruckt.${var// /$pattern}
Wird auf die Erweiterung von erweitert,var
wobei alle Leerzeichen durch die Erweiterung von ersetzt werden$pattern
.Sie können die
tmp
Variable in derrepeat
Funktion auch durch indirekte Erweiterung entfernen:quelle
bash
die globalen Zeichenfolgenersetzungsvorgänge im Kontext der Parametererweiterung (${var//old/new}
) besonders langsam sind: unerträglich langsam in Bash3.2.57
und langsam in Bash4.3.30
, zumindest auf meinem OSX 10.10.3-System auf einem 3,2-GHz-Intel Core i5-Computer: Mit Bei einer Zählung von 1.000 sind die Dinge langsam (3.2.57
) / schnell (4.3.30
): 0,1 / 0,004 Sekunden. Das Erhöhen der Anzahl auf 10.000 ergibt auffallend unterschiedliche Zahlen:repeat 10000 = var
dauert ungefähr 80 Sekunden (!) In Bash3.2.57
und ungefähr 0,3 Sekunden in Bash4.3.30
(viel schneller als eingeschaltet3.2.57
, aber immer noch langsam).Oder
Beispiel
quelle
awk 'BEGIN { while (c++ < 100) printf "=" }'
. Eingewickelt in eine parametrisierte Shell-Funktion (repeat 100 =
z. B. aufrufen als ) :repeat() { awk -v count="$1" -v txt=".$2" 'BEGIN { txt=substr(txt, 2); while (i++ < count) printf txt }'; }
. (Das Dummy-.
Präfix char und der komplementäresubstr
Aufruf werden benötigt, um einen Fehler in BSD zuawk
=
NF = 100
Lösung ist sehr clever (obwohl Sie 100 verwenden=
müssen , um 100 zu erhaltenNF = 101
). Die Einsprüche sind , dass es abstürzt BSDawk
(aber es ist sehr schnell mitgawk
und noch schneller mitmawk
), und das POSIX bespricht weder die Zuordnung zuNF
, noch die Verwendung von Feldern inBEGIN
Blöcken. Sie können es auch in BSDawk
mit einer kleinen Änderung zum Laufen bringen:awk 'BEGIN { OFS = "="; $101=""; print }'
(aber seltsamerweise ist das in BSDawk
nicht schneller als die Loop-Lösung). Als parametrisierte Shell-Lösung :repeat() { awk -v count="$1" -v txt=".$2" 'BEGIN { OFS=substr(txt, 2); $(count+1)=""; print }'; }
.original-awk
ist der Name , unter Linux des älteren awk ähnlich wie BSDs awk, die auch zum Absturz berichtet wurde, wenn Sie dies versuchen. Beachten Sie, dass Abstürze normalerweise der erste Schritt sind, um einen ausnutzbaren Fehler zu finden. Diese Antwort fördert so unsicheren Code.original-awk
ist nicht Standard und nicht empfohlenawk NF=100 OFS='=' <<< ""
(usingbash
andgawk
)Ich denke, der ursprüngliche Zweck der Frage war es, dies nur mit den eingebauten Befehlen der Shell zu tun. So
for
Schleifen undprintf
legitimen wären, währendrep
,perl
und auchjot
würde unten nicht. Trotzdem der folgende Befehljot -s "/" -b "\\" $((COLUMNS/2))
Druckt beispielsweise eine fensterweite Zeile von
\/\/\/\/\/\/\/\/\/\/\/\/
quelle
jot -s '' -b '=' 100
. Der Nachteil ist , dass während BSD-ähnlichen Plattformen, einschließlich OSX, komm mitjot
, Linux - Distributionen nicht .apt install athena-jot
würde bietenjot
.Wie andere bereits gesagt haben, geht die Erweiterung der Bash- Klammern der Parametererweiterung voraus , sodass Bereiche nur Literale enthalten können. und bieten saubere Lösungen, sind jedoch nicht vollständig von einem System auf ein anderes portierbar, selbst wenn Sie auf jedem dieselbe Shell verwenden. (Obwohl zunehmend verfügbar ist; z. B. in FreeBSD 9.3 und höher .)
{m,n}
seq
jot
seq
eval
Und andere Formen der Indirektion funktionieren immer, sind jedoch etwas unelegant.Glücklicherweise unterstützt bash den C-Stil für Schleifen (nur mit arithmetischen Ausdrücken). Also hier ist ein prägnanter "Pure Bash" Weg:
Dies nimmt die Anzahl der Wiederholungen als erstes Argument und die zu wiederholende Zeichenfolge (die wie in der Problembeschreibung ein einzelnes Zeichen sein kann) als zweites Argument.
repecho 7 b
Ausgängebbbbbbb
(durch einen Zeilenumbruch abgeschlossen).Dennis Williamson gab im Wesentlichen diese Lösung vor vier Jahren in seiner ausgezeichneten Antwort auf das Erstellen einer Reihe von wiederholten Zeichen in Shell-Schrift . Mein Funktionskörper unterscheidet sich geringfügig vom dortigen Code:
Da der Fokus hier auf der Wiederholung eines einzelnen Zeichens liegt und die Shell Bash ist, ist es wahrscheinlich sicher, sie
echo
anstelle von zu verwendenprintf
. Und ich habe die Problembeschreibung in dieser Frage als Ausdruck einer Präferenz zum Drucken gelesenecho
. Die obige Funktionsdefinition funktioniert in bash und ksh93 . Obwohlprintf
es portabler ist (und normalerweise für solche Dinge verwendet werden sollte), istecho
die Syntax wahrscheinlich besser lesbar.Die
echo
eingebauten Shells einiger Shells werden-
von sich aus als Option interpretiert - obwohl die übliche Bedeutung von-
stdin für die Eingabe unsinnig istecho
. zsh macht das. Und es gibt definitivecho
s, die nicht erkennen-n
, da es nicht Standard ist . (Viele Muscheln im Bourne-Stil akzeptieren C-Stil für Schleifen überhaupt nicht, daher muss ihrecho
Verhalten nicht berücksichtigt werden.)Hier besteht die Aufgabe darin, die Sequenz zu drucken; dort sollte es einer Variablen zugewiesen werden.
Wenn
$n
die gewünschte Anzahl von Wiederholungen vorliegt und Sie sie nicht wiederverwenden müssen und etwas noch kürzeres wünschen:n
muss eine Variable sein - funktioniert auf diese Weise nicht mit Positionsparametern.$s
ist der zu wiederholende Text.quelle
printf "%100s" | tr ' ' '='
ist optimal.zsh
übrigens auch funktioniert . Der Echo-in-a-Loop-Ansatz funktioniert gut für kleinere Wiederholungszahlen, aber für größere gibt es POSIX-kompatible Alternativen, die auf Dienstprogrammen basieren , wie der Kommentar von @ Slomojo zeigt.(while ((n--)); do echo -n "$s"; done; echo)
echo
System, das dies unterstützt-n
. Der Geist dessen, was Sie sagen, ist absolut richtig.printf
sollte fast immer bevorzugt werdenecho
, zumindest bei nicht interaktiver Verwendung. Aber ich denke nicht, dass es in irgendeiner Weise unangemessen oder irreführend war, eineecho
Antwort auf eine Frage zu geben , die nach einer Frage fragte und die genügend Informationen lieferte, um zu wissen, dass es funktionieren würde . Bitte beachten Sie auch, dass die Unterstützung für((n--))
(ohne a$
) selbst von POSIX nicht garantiert wird.Python ist allgegenwärtig und funktioniert überall gleich.
python -c "import sys; print('*' * int(sys.argv[1]))" "=" 100
Zeichen und Anzahl werden als separate Parameter übergeben.
quelle
python -c "import sys; print(sys.argv[1] * int(sys.argv[2]))" "=" 100
In Bash 3.0 oder höher
quelle
Ein weiteres Mittel, um eine beliebige Zeichenfolge n-mal zu wiederholen:
Vorteile:
Nachteile:
yes
Befehl von Gnu Core Utils .Mit einem ANSI-Terminal und zu wiederholenden US-ASCII-Zeichen. Sie können eine ANSI-CSI-Escape-Sequenz verwenden. Dies ist der schnellste Weg, um ein Zeichen zu wiederholen.
Oder statisch:
Drucken Sie eine Zeile 80 Mal
=
:printf '=\e[80b\n'
Einschränkungen:
repeat_char
ANSI-CSI-Sequenz.repeat_char
ANSI-CSI-Sequenz nicht auf das wiederholte Zeichen erweitert.quelle
Folgendes verwende ich, um unter Linux eine Zeichenzeile über den Bildschirm zu drucken (basierend auf der Terminal- / Bildschirmbreite).
Drucken Sie "=" über den Bildschirm:
Erläuterung:
Drucken Sie ein Gleichheitszeichen so oft wie in der angegebenen Reihenfolge:
Verwenden Sie die Ausgabe eines Befehls (dies ist eine Bash-Funktion namens Command Substitution):
Geben Sie eine Sequenz an, ich habe 1 bis 20 als Beispiel verwendet. Im letzten Befehl wird der Befehl tput anstelle von 20 verwendet:
Geben Sie die Anzahl der aktuell im Terminal verwendeten Spalten an:
quelle
quelle
quelle
Am einfachsten ist es, diesen Einzeiler in csh / tcsh zu verwenden:
quelle
Eine elegantere Alternative zur vorgeschlagenen Python-Lösung könnte sein:
quelle
Wenn Sie ein Zeichen n-mal wiederholen möchten, wobei es na VARIABLE ist, hängt dies beispielsweise von der Länge einer Zeichenfolge ab, die Sie ausführen können:
Es zeigt an:
quelle
length
wird nicht funktionierenexpr
, meinten Sie wahrscheinlichn=$(expr 10 - ${#vari})
; Es ist jedoch einfacher und effizienter, die arithmetische Erweiterung von Bash zu verwenden :n=$(( 10 - ${#vari} ))
. Im Mittelpunkt Ihrer Antwort steht auch der Perl-Ansatz, zu dem das OP nach einer Bash- Alternative sucht .Dies ist die längere Version dessen, wofür Eliah Kagan eintrat:
Natürlich können Sie auch printf dafür verwenden, aber nicht wirklich nach meinem Geschmack:
Diese Version ist Dash-kompatibel:
mit i ist die anfängliche Nummer.
quelle
while (( i-- )); do echo -n " "; done
funktioniert.Probeläufe
Referenzbibliothek unter: https://github.com/gdbtek/linux-cookbooks/blob/master/libraries/util.bash
quelle
Sie können dies tun,
echo
wenn aufecho
Folgendes folgtsed
:Eigentlich ist das
echo
dort unnötig.quelle
Meine Antwort ist etwas komplizierter und wahrscheinlich nicht perfekt, aber für diejenigen, die große Zahlen ausgeben möchten, konnte ich in 3 Sekunden etwa 10 Millionen erledigen.
quelle
Am einfachsten ist es, diesen Einzeiler in Bash zu verwenden:
quelle
Eine andere Möglichkeit besteht darin, GNU seq zu verwenden und alle generierten Zahlen und Zeilenumbrüche zu entfernen:
Dieser Befehl druckt das
#
Zeichen 100 Mal.quelle
Die meisten existierenden Lösungen hängen alle auf
{1..10}
Syntax Unterstützung der Schale, die istbash
- undzsh
- spezifisch und funktioniert nicht intcsh
oder OpenBSDksh
und die meisten Nicht-bashsh
.Das Folgende sollte unter OS X und allen * BSD-Systemen in jeder Shell funktionieren. Tatsächlich kann damit eine ganze Matrix verschiedener Arten von dekorativen Räumen erzeugt werden:
Leider erhalten wir keine nachgestellte Newline. die
printf '\n'
nach der Falte durch ein Extra repariert werden kann:Verweise:
quelle
Mein Vorschlag (Akzeptieren von Variablenwerten für n):
quelle