Wie kann ich ein Skript erstellen, um bis fünf zu zählen?

10

Ich habe versucht, ein sehr einfaches Bash-Skript zu erstellen, um alle Vielfachen von fünf zwischen 375 und 3500 (375, 380, 385 ...) aufzulisten. Eine Sache, die ich versucht habe und die nicht funktioniert hat, ist:

for i in {375..3500}
do
        echo $i
        (($i += 5))
done

Ich gab nach einer Weile auf und schrieb dies in ungefähr 15 Sekunden in BASIC:

10 count = 375
20 print count
30 count = count+5
40 if count < 3500 then goto 20

Wie kann ich mein BASIC-Programm in einem Bash-Skript erstellen?

aswine
quelle
Dies ist besser bei Stapelüberlauf - Bei Unix und Linux geht es um das Betriebssystem, nicht um das Codieren. Die Codierung dient zum Stackoverflow.
noɥʇʎԀʎzɐɹƆ

Antworten:

20

Alternativ kann eine traditionelle C-förmige for-Schleife verwendet werden:

for ((i=375; i<=3500; i+=5)); do
    echo $i
done

Dies ist vielleicht weniger klar als die Verwendung von seq, aber es entstehen keine Unterprozesse. Obwohl ich mit C vertraut bin, hätte ich keine Schwierigkeiten, dies zu verstehen, aber YMMV.

Muzer
quelle
1
Nachteil dieser Methode ist, dass sie weniger portabel ist. Die seq-Methode funktioniert in POSIX sh.
Wouter Verhelst
Oh, gibt es in POSIX sh keinen C-Stil für Schleifen? Sie lernen jeden Tag etwas Neues ...
Muzer
2
@WouterVerhelst Nun, außer wenn Sie auf POSIX sh beschränkt sind, werden Sie wahrscheinlich keine seq haben, die Teil von GNU coreutils ist. Busybox hat eine eingeschränktere Implementierung, aber abgesehen davon werden viele eingebettete Systeme sie wahrscheinlich überhaupt nicht haben.
Chris Down
1
@ Muzer - dashunterstützt es zumindest nicht. @ChrisDown - Es gibt keinen Grund , warum „POSIX sh“ hat „keine seq“ bedeuten. Aber ja, zugegeben, ich hatte die Tatsache übersehen, dass seq nicht von POSIX spezifiziert wird.
Wouter Verhelst
27

Da Sie die Klammererweiterung ohnehin verwenden, sollten Sie die Funktion voll ausnutzen:

echo {375..3500..5}

Sie können diese Technik auch verwenden, um jede Zahl in einer separaten Zeile mit optionalem Text zu drucken, indem Sie printfanstelle von echobeispielsweise Folgendes verwenden:

$ printf "Number %s is generated.\n" {375..3500..5}
Number 375 is generated.
Number 380 is generated.
Number 385 is generated.
...

Bearbeiten

Wie von @kojiro im Kommentar hervorgehoben, verwendet Mac OS Bash 3 als Standard-Shell, die keine Erhöhung des Sequenzausdrucks der Klammererweiterung unterstützt. Sie müssen auf Bash Version 4 aktualisieren oder eine andere Shell verwenden, die dies unterstützt (z. B. aktuelles zsh).

jimmij
quelle
2
Dies funktioniert bei mir unter Mac OS 10.10.3 nicht. Es gibt '{375..3500..5}' aus.
Aswine
6
@aswine deshalb solltest du immer dein Betriebssystem erwähnen, wenn du fragst . Zumal OSX eine Reihe von Unterschieden sowohl zu anderen UNICEs als auch zu Linux aufweist.
Terdon
2
Dies ist an sich kein Unterschied im Betriebssystem. Es ist ein Versionsunterschied. OS X hat nur BASH 3 OOTB. Sie können einen BASH aus diesem Jahrhundert mit fast jedem OS X-Paketmanager installieren. Zum einen benutze ich Home Brew.
Kojiro
2
Die Tatsache, dass die Erweiterungen fehlschlagen, direkt ausgeführt werden, aber bash -cso gut wie erfolgreich sind, garantiert, dass zwei verschiedene Shells beteiligt sind. Sagt $SHELL --version, es ist Bash 3?
Dhag
3
@mikeserv Die Antwort ist sehr einfach - ich habe das nicht geschrieben, weil ich keine Ahnung hatte, in welcher Version bashdieser Funktion eingeführt wurde. Ich habe es selbst aus dem Kojiro-Kommentar gelernt. Und bitte vergleichen Sie mich nicht mit SC, ich kenne wirklich nicht alle Details und die Geschichte aller Muscheln seit Ende 1970. Noch einmal - Wenn Sie das erwarten, stimmen Sie einfach ab.
Jimmyij
17

Verwenden von SEQ (1)

for i in $(seq 375 5 3500)
do
    echo $i
done

Oder einfach:

seq 375 5 3500
Emeric
quelle
4
Noch einfacher wäre es, die Schleife fallen zu lassen und einfach zu verwenden seq 375 5 3500.
Dhag
11

Ihr For-Loop-Snippet hat aus zwei Gründen nicht wie gewünscht funktioniert:

  • (($i += 5))- hier $iwird das auf den Wert von erweitert i. Daher wird die Erweiterung so etwas wie etwas sein ((375 += 5)), was keinen Sinn ergibt (der Versuch, einer anderen Literalzahl eine Literalzahl zuzuweisen). Dies würde normalerweise erreicht werden mit ((i += 5))(nein $, um die Variable zu erweitern)
  • Das {375..3500}wird vor der ersten Iteration der Schleife erweitert. Es wird die Liste der Zahlen sein 375 376 ... 3499 3500. iWird für jede Iteration der Schleife jeder dieser Nummern einzeln zugewiesen. Somit wird zu Beginn jeder Iteration ider nächste Wert in dieser Liste neu zugewiesen, wobei in Schritten von 1 ((i += 5))hochgezählt wird. Das macht effektiv nichts - es addiert 5 zu i, aber dann wird i einfach zu Beginn der Iteration neu zugewiesen nächste Iteration.

Ich denke, die for (( ; ; ))Antwort gefällt mir am besten, aber hier sind einige Alternativen, die Sie zum Nachdenken anregen:


Da es sich um ein Vielfaches von 5 handelt und die {a..b..i}Erweiterung in Bash-Version 3.2.57 (1) (in OS X) nicht unterstützt wird, können wir stattdessen diese etwas arkane Sache tun:

for i in 375 {38..349}{0,5} 3500; do
    echo $i
done

Dies zeigt, wie mit Bash ein kartesisches Produkt erstellt werden kann.


Ich denke, im Allgemeinen ist eine for-Schleife der bequemste Weg, dies zu tun, aber wenn Sie interessiert sind, können Sie ein while-Schleifenprogramm (etwas näher an Ihrem BASIC) verwenden:

count=375
while (( count <= 3500 )); do
    echo $count
    (( count += 5 ))
done
Digitales Trauma
quelle
1
@jimmij ... was ist ein kartesisches Produkt? Sie können den Kommentar ablehnen, wenn Sie möchten, und es ist mir egal, ob Sie es mir sagen. Ich bin neugierig.
Mikeserv
1
@mikeserv Sie können den Kommentar nicht herabstimmen: en.wikipedia.org/wiki/Cartesian_product
jimmij
@jimmij - es ist immer noch in Ordnung mit mir, wenn du das tust.
Mikeserv
@jimmij Der Teufel redest du? Ein kartesisches Produkt ist eine Menge von Tupeln jeder möglichen Kombination von Elementen aus zwei Mengen (die dieselbe Menge sein können oder nicht). Umgangssprachlich sind es nur "alle möglichen Kombinationen" aus zwei Gruppen von Dingen. Ich sehe nur einen Satz. Wie gibt es hier ein kartesisches Produkt?
jpmc26
1
@ jpmc26 Sie haben Recht, es sind "alle möglichen Kombinationen", also lassen Sie uns zwei Achsen zeichnen - schreiben Sie zuerst alle Zahlen von 38bis 349. Auf der zweiten Seite nur zwei Zahlen: 0und 5. Nun können geordnete Paare dieser alle Kombinationen erstellen - man kann sie als Sätze schreiben: {38,0}, {38,5}... {349,5}, oder einfach nur redundante Symbole entfernen {, ,und }und bekommen ... neue Zahlen 380... 3495.
Jimmyij
5

Natürlich gibt es dafür eine App ( seq 375 5 3500), aber es gibt verschiedene Möglichkeiten, dies über die Befehlszeile zu tun. Während die schnellste und einfachste nur verwendet wird seq, sind hier einige andere Optionen:

for i in {375..3500}; do [[ (($i % 5)) -eq 0 ]] && echo $i; done

i=370; while [ $i -le 3500 ]; do printf "%s\n" $((i+=5)); done

perl -le '$i=shift;while($i<=$ARGV[0]){print $i; $i+=5; }' 375 3500
perl -le 'map{print $_ + 5} 370..3495'

awk 'BEGIN{ for(i=375;i<=3500;i+=5){print i}}'
terdon
quelle
Nit pick: $(($i % 5))kann geschrieben werden $((i % 5)).
G-Man sagt "Reinstate Monica"
4

POSIXly:

i=370
while [ 3500 -gt "$i" ]
do    echo "$((i+=5))"
done

...oder...

echo 'for(x=370;x<=3500;x+=5)x' |bc

Ich weiß nicht, warum du es anders machen würdest. Außer natürlich ...

seq 375 5 3500

... oder mit dc:

echo '370[5+pd3500>p]splpx'|dc
mikeserv
quelle
Ich bin gespannt, wie der dcCode funktioniert. Es ist sicherlich faszinierender als die Verwendung seq.
Dhag
1
@dhag - es schreibt eine kleine Schleife. es sAves die [Zeichenfolge ]an den oberen Rand des pArray, dann lOADS es zurück auf die Oberseite des Stapels und e xecutes es als ein Makro. Im Makro drücken wir 5auf den Stapel dann Pop und die zweite von oben und +sie ersetzen die beiden Stapel Werte mit deren Summe, welche printed und dvor uplicated 3500auf den Stapel geschoben wird , wenn wir es knallen und die Betrogene wir gerade gemacht für Vergleich >. Wenn 3500größer ist, laden wir die im pArray (unserem aktuellen Makro) gespeicherte Zeichenfolge und führen sie als Makro aus , oder wenn nicht, brechen sie.
Mikeserv
3

Wenn Sie auf Bash 3 stecken:

echo {375..3500} | tr ' ' '\n' | sed -n 'p;n;n;n;n'

und wenn Sie es vorziehen awk:

echo {375..3500} | tr ' ' '\n' | awk '!((NR-1)%5)'

Ich wusste nichts über Zahnspangenerweiterung - das ist wirklich cool.

Bonh
quelle