Linux-Befehl zum n-maligen Wiederholen einer Zeichenfolge

71

Gibt es einen integrierten Linux-Befehl, der die Ausgabe einer Zeichenfolge ermöglicht, die n-mal eine Eingabezeichenfolge ist?

GetFree
quelle
1
Mit "eingebautem Linux-Befehl" meine ich wohl den Shell-Befehl, und da Sie nicht erwähnen, welche Shell Sie verwenden, gehe ich davon aus, dass es sich um Bash handelt. Sie können dies überprüfen, indem Sie "echo $ SHELL" in die Befehlszeile eingeben und Sie sollten etwas Ähnliches wie "/ bin / bash" zurückbekommen. Wenn Sie dies nicht tun, sollten Sie Ihre Antwort bearbeiten, um anzugeben, was angezeigt wird. Prost :)
Adrian Petrescu
7
Ich habe die Frage mit "bash" markiert. Ich dachte, das wäre genug gewesen.
GetFree

Antworten:

75
adrian@Fourier:~$ printf 'HelloWorld\n%.0s' {1..5}
HelloWorld
HelloWorld
HelloWorld
HelloWorld
HelloWorld
adrian@Fourier:~$
Adrian Petrescu
quelle
3
Können Sie erklären, wie das funktioniert? Ich verstehe den Befehl printf, da er mit dem in C / C ++ identisch ist. Aber ich verstehe nicht, wie das {1..5} erweitert wird und wie das in Verbindung mit dem Teil "% .0s" funktioniert.
GetFree
4
Es ist ein bisschen wie ein Hack :) Versuchen Sie, "printf 'HelloWorld% d \ n' 1 2 3 4 5" auszuführen, und es wird wahrscheinlich für Sie klicken. Das% .0s-Flag soll nichts tun, nur Argumente aufgreifen. Wenn bash dann mehr Argumente als Formatangaben enthält, druckt es einfach mehrere Kopien aus und greift nach so vielen, wie es benötigt. So erhalten Sie den Effekt. Die Ausgabe von "printf 'HelloWorld% d% d \ n' 1 2 3 4 5 6" macht es wahrscheinlich noch deutlicher. Hoffe das hilft!
Adrian Petrescu
Aha. Es ist das besondere Verhalten von printf, das die Wiederholung ermöglicht
GetFree
1
(Ich sollte beachten, dass dies aus rein theoretischer Sicht wahrscheinlich die schnellste Lösung ist, da ein einzelnes Shell-Primitiv verwendet wird - keine externen Prozesse. In der Realität spielt die Leistung von Bash-Skripten jedoch keine Rolle: )
Adrian Petrescu
1
Was ist zu spezifisch printfist , dass es immer wieder überschüssige Argumente an den Format - String, „Looping“ kostenlos an. Mit "Überschuss" meine ich, dass es mehr Argumente als %Platzhalter gibt.
Dennis Williamson
69

Hier ist ein altmodischer Weg, der ziemlich portabel ist:

yes "HelloWorld" | head -n 10

Dies ist eine konventionellere Version von Adrian Petrescus Antwort mit Klammererweiterung:

for i in {1..5}
do
    echo "HelloWorld"
done

Das entspricht:

for i in 1 2 3 4 5

Dies ist eine etwas präzisere und dynamischere Version der Antwort von Pike :

printf -v spaces '%*s' 10 ''; printf '%s\n' ${spaces// /ten}
Dennis Williamson
quelle
Wie werden Sie die neuen Zeilen mit dem Befehl yes los?
GetFree
3
Eine Möglichkeit besteht darin, es durchzuleiten, sed -n 'H;${x;s/\n//gp}'oder eine sed -n ':t;${s/\n//gp};N;bt'andere, echo $(yes "HelloWorld" | head -n 10)die ein Leerzeichen zwischen jeder Kopie der Zeichenfolge hinzufügt. Ein weiterer Weg besteht darin, es tr -d '\n'durchzuleiten, wodurch auch der letzte Zeilenumbruch beseitigt wird.
Dennis Williamson
2
Es ist wie Haskell in einer Bash-Shell: Hashell?
Wchargin
4
Die Ja-Lösung ist ziemlich ordentlich
Piggybox
Die yesLösung war genau das, was ich brauchte, da ich einen Befehl duplizieren wollte (dessen Ausgabe schwankt). Also:yes "$(my-command)" | head -n 2
Arnsholt
14

Dies kann parametrisiert werden und erfordert keine temporäre Variable, FWIW:

printf "%${N}s" | sed 's/ /blah/g'

Oder wenn $Nes die Größe eines Bash-Arrays hat:

echo ${ARR[@]/*/blah}
Twifkak
quelle
3
Dies ist die kürzeste POSIX 7- Lösung, die ich bisher gesehen habe seq, yesund {1..5}es handelt sich nicht um POSIX 7.
Ciro Santilli am
Sie sollten keine Daten in printfden Formatbezeichner von mischen . Was ist, wenn die Daten Formatzeichenfolgen enthalten? Dies ist der richtige Weg, um die "Genauigkeit" (Länge) dynamisch anzugeben: printf '%*s' "$N"- Machen Sie es sich zur Gewohnheit, die Formatzeichenfolge in einfache Anführungszeichen zu setzen, um eine variable Erweiterung dort zu verhindern.
Dennis Williamson
13

Einige gute Möglichkeiten wurden bereits erwähnt. Ich kann aber nicht gut alt vergessen seq:

[john @ awesome] $ für i in `seq 5`; mach ein Echo "Hi"; fertig
Hallo
Hallo
Hallo
Hallo
Hallo
John T
quelle
Dieser respektiert tatsächlich eine Null und behandelt sie als Null! (Der {i..j}Trick gibt niemals einen leeren Bereich zurück.)
JellicleCat
10

Vielleicht eine andere Möglichkeit, die allgemeiner und nützlicher für Sie ist:

adrian@Fourier:~$ n=5
adrian@Fourier:~$ for (( c=1; c<=n; c++)) ; do echo "HelloWorld" ; done
HelloWorld
HelloWorld
HelloWorld
HelloWorld
HelloWorld
adrian@Fourier:~$ 

Die Bash-Shell ist mächtiger als die meisten Leute denken :)

Adrian Petrescu
quelle
Dies ist meine Stimme, da es vollständig Shell-intern ist; kein gabeln erforderlich.
23.
2
Auf welche Gabelung beziehen Sie sich? Die ursprüngliche Antwort erfordert keine. Die Ausgabe von 'type printf' ist 'printf ist eine eingebaute Shell' und wird daher innerhalb des ursprünglichen Bash-Prozesses ausgeführt.
CodeGnome
Dies ist der einzige bisher ( yes, printf, for i in {1..5}) , dass , wenn die nNull, es leeren String zurück , ohne existieren Status 1. Auch aufgrund der mathematischen Notation zum Vergleich, ist es leicht um 1 versetzt zu haben (zB durch die Veränderung <=zu <)
Mehrad Mahmoudian
10

Sie können einen Trick verwenden. Das Echo einer leeren Variablen gibt nichts aus. So können Sie schreiben:

echo word$wojek{1..100}

Wenn $wojek1 $wojek2... $wojek100nicht existierende Variablen sind, werden Sie Ihr Wort 100-mal ohne irgendetwas anderes wiederholen lassen.

Wojciech Waga
quelle
1
Es ist ein hässlicher hässlicher Hack, und dennoch kann ich nicht anders, als es zu lieben und es zu benutzen.
16807
Liebe es! Vielleicht macht die Verwendung von $_anstelle $wojekdie Absicht klarer.
Mihai Todor
7

Wiederholen Sie die nZeiten, setzen Sie einfach n-1Kommas zwischen {}:

$ echo 'helloworld'{,,}
helloworld helloworld helloworld

Wiederholt 'helloworld' zweimal nach dem ersten Echo.

kev
quelle
5
Schön, aber was ist, wenn ich nvon einer Variablen bekommen will ?
GetFree
1
es fügt nach jeder "helloworld" ein zusätzliches Leerzeichen hinzu
PADYMKO
Dies scheint nicht zu gestatten, dass Sie Zeilenumbrüche in die Zeichenfolge einfügen (dh helloworld auf ihre eigenen Zeilen setzen)
TankorSmash
5
awk 'BEGIN {while (c++<4) printf "Hello"}'

Ergebnis

Hallo Hallo Hallo Hallo
Steven Penny
quelle
Verwenden Sie dies ohne awk: while ((c ++ <5)); mach printf 'hallo'; erledigt
emf
4

Ich habe mit der yesLösung Rohrbruchwarnungen erhalten. Hier ist eine weitere gute Alternative:

$ seq 4 | sed "c foo"
foo
foo
foo
foo
n.caillou
quelle
3

basierend auf dem, was @pike andeutete

für jedes Zeichen in der Zeichenfolge Echo-Zeichenfolge

echo ${target//?/$replace}

Ein Beispiel für eine mit =Zeichen unterstrichene Überschrift

export heading='ABCDEF'; 
export replace='='; 
echo -e "${heading}\n${heading//?/$replace}"

wird ausgegeben

ABCDEF
======

Dies scheint zwischen Linux und OS X zu portieren und das freut mich.

nJoy!

nickl-
quelle
3

Wenn Sie auf BSD sind, können Sie nur verwenden seq.

$ seq -f "Hello, world" 5
Hello, world
Hello, world
Hello, world
Hello, world
Hello, world
Qix
quelle
1
In seq (GNU coreutils) 8.25ergibt dies seq: format 'Hello, world' has no % directiveeine Formatierung Richtlinie zwingt anwesend zu sein. GNU-Coreutils werden zB in vielen Linux-Distributionen und in Cygwin verwendet. Einschließlich der Informationen hier für diejenigen, denen die Information fehlt, dass es nur in BSD-seq funktioniert.
Palec
2
line="==========================="
line=${line:0:10}
${line//"="/"ten "}

Ausgänge

ten ten ten ten ten ten ten ten ten ten
Hecht
quelle
Vielleicht ein ausführlicheres Beispiel: declare c = '-----'; c = $ {c // $ {c: 0: 1} / $ c}; echo $ c # druckt "-" 25 mal.
Stephen Niedzielski
2

Angenommen, Sie möchten so etwas wie den xOperator von Perl , bei dem Sie zwischen den Wiederholungen nicht automatisch einen Zeilenumbruch erhalten:

x() {
  # usage: x string num
  for i in $(seq 1 $2); do printf "%s" "$1"; done
  # print a newline only if the string does not end in a newline
  [[ "$1" == "${1%$'\n'}" ]] && echo ""
}

x Hi 10  # ==> HiHiHiHiHiHiHiHiHiHi

x $'Hello World!\n' 3

Ich habe explizit eine forSchleife verwendet, da Sie nicht {1..$n}in bash schreiben können : Die Erweiterung der Klammern erfolgt vor der Variablensubstitution.

Glenn Jackman
quelle
2

Nicht unbedingt in Linux integriert, aber wenn Sie Python installiert haben.

python
>>>var = "string"
>>>var*n

Oder in einer Zeile, wie vom Kommentator vorgeschlagen:

python -c 'print "This is a test.\n" * 10'
eqzx
quelle
4
Nicht wirklich nützlich, da es nicht einfach in Shell-Skripte usw. integriert werden kann. Und da es ungefähr eine Milliarde Möglichkeiten gibt, dies in der Shell selbst zu tun, sehe ich wenig Grund, die großen Guns (dh Python) dafür herauszubringen .
Adrian Petrescu
7
Ich stimme Ihrem zweiten Punkt zu, aber nicht dem ersten. Es ist einfach, in ein Shell-Skript zu integrieren: python -c 'print "Dies ist ein Test. \ N" * 10'
larsks
Ich mag die Lesbarkeit dieser Lösung, Grund genug für mich. ;)
Elias
2

Keine Magie hier:

seq 5 | awk '{print "Hello World"}'

brablc
quelle
1

Probier diese:

echo $(for i in $(seq 1 100); do printf "-"; done)

Wird erstellen (einhundert Bindestrich):


Alle Aldine
quelle