Wie könnte ich das machen echo
?
perl -E 'say "=" x 100'
ruby -e 'puts "=" * 100'
oderpython -c 'print "=" * 100'
printf
mit seq
)svrb=`printf '%.sv' $(seq $vrb)`
Wie könnte ich das machen echo
?
perl -E 'say "=" x 100'
ruby -e 'puts "=" * 100'
oderpython -c 'print "=" * 100'
printf
mit seq
)svrb=`printf '%.sv' $(seq $vrb)`
Antworten:
Sie können verwenden:
printf '=%.0s' {1..100}
So funktioniert das:
Bash erweitert {1..100}, sodass der Befehl wie folgt lautet:
printf '=%.0s' 1 2 3 4 ... 100
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 .
repl = 100
zum Beispiel aufrufen können ( eval
leider sind Tricks erforderlich, um die repl() { printf "$1"'%.s' $(eval "echo {1.."$(($2))"}"); }
seq
stattdessen z $(seq 1 $limit)
.
$s%.0s
, da %.0s$s
sonst Striche einen printf
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:
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 :)
=
Zeichen gedruckt werden .
printf
tr
ist die POSIX - Lösung nur , weil seq
, yes
und {1..3}
ist nicht POSIX.
printf %100s | sed 's/ /abc/g'
- gibt 'abcabcabc ...' aus
tr
). Sie können es auch auf so etwas erweitern printf "%${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:
${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ösung[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
und die perl
Lösungen.[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// /=}
) 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 BSD awk
(wie auch unter OSX) - es ist merklich langsamer als gawk
(GNU Awk) und insbesondere mawk
.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
#!/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`
👍
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:
start=1
end=100
for ((i=$start; i<=$end; i++)); do echo -n =; done
Verwenden des printf
eingebauten:
printf '=%.0s' {1..100}
Wenn Sie hier eine Genauigkeit angeben, wird die Zeichenfolge auf die angegebene Breite ( 0
) gekürzt . Da die printf
Formatzeichenfolge wiederverwendet wird, um alle Argumente zu verbrauchen, wird dies einfach "="
100 Mal gedruckt .
Verwenden von head
( printf
usw.) und tr
:
head -c 100 < /dev/zero | tr '\0' '='
printf %100s | tr " " "="
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 GNU head
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
und head
- 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 die head -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 die head
Version und 0,675 s für die dd
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 Versionen
seq -f "#" -s '' 10
Druckt '#' 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 ...
repeat () {
seq -f $1 -s '' $2; echo
}
Was du so nennen kannst ...
repeat "#" 10
HINWEIS: Wenn Sie wiederholen, sind #
die Anführungszeichen wichtig!
seq: format ‘#’ has no % directive
. seq
ist für Zahlen, nicht für Zeichenfolgen. Siehe gnu.org/software/coreutils/manual/html_node/seq-invocation.html
seq
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 GNU seq
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 (andernfalls seq
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 verwenden seq
, funktioniert dies im Allgemeinen unter BSD-ähnlichen Betriebssystemen (z. B. FreeBSD). Im Gegensatz dazu funktioniert dies nicht unter Linux , wo GNU seq
verwendet wird.
Hier sind zwei interessante Möglichkeiten:
ubuntu @ ubuntu: ~ $ yes = | Kopf -10 | Einfügen -s -d '' - ========== ubuntu @ ubuntu: ~ $ yes = | Kopf -10 | tr -d "\ n" ========== ubuntu @ ubuntu: ~ $
Beachten Sie, dass diese beiden geringfügig voneinander abweichen. - Die paste
Methode endet in einer neuen Zeile. Die tr
Methode funktioniert nicht.
paste
unerklärlicherweise die -d '\0'
Angabe eines leeren Trennzeichens erfordert und mit -d ''
- fehlschlägt - -d '\0'
sollte mit allen POSIX-kompatiblen paste
Implementierungen funktionieren und tatsächlich auch mit 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
. Wichtiger jedoch: Wenn Sie es printf
trotzdem verwenden, können Sie auch den einfacheren und effizienteren Ansatz aus der akzeptierten Antwort printf '%.s=' $(seq 500)
Es gibt keinen einfachen Weg. Vermeiden Sie die Verwendung printf
und Ersetzung von Schleifen .
str=$(printf "%40s")
echo ${str// /rep}
# echoes "rep" 40 times.
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
und printf
und / 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 1 100); do printf "="; done)
... wird die gleiche Ausgabe wie perl -E 'say "=" x 100'
fast überall produzieren.
seq
es sich nicht um ein POSIX-Dienstprogramm handelt (obwohl BSD- und Linux-Systeme Implementierungen davon haben) - Sie können POSIX-Shell-Arithmetik while
stattdessen mit einer Schleife ausführen, wie in der Antwort von @ Xennex81 (mit printf "="
, wie Sie richtig vorschlagen, anstatt echo -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
:
echo -e ''$_{1..100}'\b='
Dies wird genau das Gleiche tun, perl -E 'say "=" x 100'
aber echo
nur mit.
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.
$ n=5
$ pattern=hello
$ printf -v output '%*s' "$n"
$ output=${output// /$pattern}
$ echo "$output"
hellohellohellohellohello
Sie können eine Funktion damit erstellen:
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}"
}
Mit diesem Set:
$ repeat 5 hello output
$ echo "$output"
hellohellohellohellohello
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ügt varname
.printf
verwendet das Argument, um die entsprechende Anzahl von Leerzeichen zu drucken. ZB printf '%*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 der repeat
Funktion 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}"
}
bash
die globalen Zeichenfolgenersetzungsvorgänge im Kontext der Parametererweiterung ( ${var//old/new}
) besonders langsam sind: unerträglich langsam in Bash 3.2.57
und 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 = var
dauert ungefähr 80 Sekunden (!) In Bash 3.2.57
und ungefähr 0,3 Sekunden in Bash 4.3.30
(viel schneller als eingeschaltet 3.2.57
, aber immer noch langsam).
#!/usr/bin/awk -f
BEGIN {
OFS = "="
NF = 100
print
}
Oder
#!/usr/bin/awk -f
BEGIN {
while (z++ < 100) printf "="
}
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 substr
Aufruf werden benötigt, um einen Fehler in BSD zu awk
=
NF = 100
Lö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 gawk
und noch schneller mit mawk
), und das POSIX bespricht weder die Zuordnung zu NF
, noch die Verwendung von Feldern in BEGIN
Blöcken. Sie können es auch in BSD awk
mit einer kleinen Änderung zum Laufen bringen: awk 'BEGIN { OFS = "="; $101=""; print }'
(aber seltsamerweise ist das in BSD awk
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 empfohlen
awk NF=100 OFS='=' <<< ""
(using bash
and gawk
)
Ich denke, der ursprüngliche Zweck der Frage war es, dies nur mit den eingebauten Befehlen der Shell zu tun. So for
Schleifen und printf
legitimen wären, während rep
, perl
und auch jot
würde unten nicht. Trotzdem der folgende Befehl
jot -s "/" -b "\\" $((COLUMNS/2))
Druckt beispielsweise eine fensterweite Zeile von \/\/\/\/\/\/\/\/\/\/\/\/
jot -s '' -b '=' 100
. Der Nachteil ist , dass während BSD-ähnlichen Plattformen, einschließlich OSX, komm mit jot
, Linux - Distributionen nicht .
apt install athena-jot
würde bieten jot
.
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:
repecho() { for ((i=0; i<$1; ++i)); do echo -n "$2"; done; echo; }
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änge bbbbbbb
(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 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 printf
es portabler ist (und normalerweise für solche Dinge verwendet werden sollte), ist echo
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 ist echo
. zsh macht das. Und es gibt definitiv echo
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 ihr echo
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:
while ((n--)); do echo -n "$s"; done; echo
n
muss eine Variable sein - funktioniert auf diese Weise nicht mit Positionsparametern. $s
ist der zu wiederholende Text.
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.
echo
System, das dies unterstützt -n
. Der Geist dessen, was Sie sagen, ist absolut richtig. printf
sollte 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 echo
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.
python -c "import sys; print(sys.argv[1] * int(sys.argv[2]))" "=" 100
Ein weiteres Mittel, um eine beliebige Zeichenfolge n-mal zu wiederholen:
Vorteile:
Nachteile:
yes
Befehl von Gnu Core Utils .#!/usr/bin/sh
to_repeat='='
repeat_count=80
yes "$to_repeat" | tr -d '\n' | head -c "$repeat_count"
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.
#!/usr/bin/env bash
char='='
repeat_count=80
printf '%c\e[%db' "$char" "$repeat_count"
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.Folgendes verwende ich, um unter Linux eine Zeichenzeile über den Bildschirm zu drucken (basierend auf der Terminal- / Bildschirmbreite).
printf '=%.0s' $(seq 1 $(tput cols))
Erläuterung:
Drucken Sie ein Gleichheitszeichen so oft wie in der angegebenen Reihenfolge:
printf '=%.0s' #sequence
Verwenden Sie die Ausgabe eines Befehls (dies ist eine Bash-Funktion namens Command Substitution):
$(example_command)
Geben Sie eine Sequenz an, ich habe 1 bis 20 als Beispiel verwendet. Im letzten Befehl wird der Befehl tput anstelle von 20 verwendet:
seq 1 20
Geben Sie die Anzahl der aktuell im Terminal verwendeten Spalten an:
tput cols
for i in {1..100}
do
echo -n '='
done
echo
Am einfachsten ist es, diesen Einzeiler in csh / tcsh zu verwenden:
printf "%50s\n" '' | tr '[:blank:]' '[=]'
Eine elegantere Alternative zur vorgeschlagenen Python-Lösung könnte sein:
python -c 'print "="*(1000)'
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========
length
wird 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 .
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:
printf "%$(( i*2 ))s"
Diese Version ist Dash-kompatibel:
until [ $(( i=i-1 )) -lt 0 ]; do echo -n " "; done
mit i ist die anfängliche Nummer.
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
}
Probeläufe
$ repeatString 'a1' 10
a1a1a1a1a1a1a1a1a1a1
$ repeatString 'a1' 0
$ repeatString '' 10
Referenzbibliothek unter: https://github.com/gdbtek/linux-cookbooks/blob/master/libraries/util.bash
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 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}
}
Am einfachsten ist es, diesen Einzeiler in Bash zu verwenden:
seq 10 | xargs -n 1 | xargs -I {} echo -n ===\>;echo
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 tcsh
oder OpenBSD ksh
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:
$ printf '=%.0s' `jot 64` | fold -16
================
================
================
================$
Leider erhalten wir keine nachgestellte Newline. die printf '\n'
nach der Falte durch ein Extra repariert werden kann:
$ printf "=%.0s" `jot 64` | fold -16 ; printf "\n"
================
================
================
================
$
Verweise:
Mein Vorschlag (Akzeptieren von Variablenwerten für n):
n=100
seq 1 $n | xargs -I {} printf =