For Schleife mit Alphabet

11

Dies funktioniert perfekt auf OSX

#!/bin/bash
chars=( {a..z} )
n=3
for ((i=0; i<n; i++))
do
  echo "${chars[i]}"
done

Aber wenn ich es auf Ubuntu ausführe, erhalte ich den folgenden Fehler.

ForLoopAlphabetTest.sh: 2: ForLoopAlphabetTest.sh: Syntax error: "(" unexpected

Ich kann das Problem nicht lösen. Irgendwelche Vorschläge?

    
denski 18.01.2017, 13:22
quelle

2 Antworten

25

Vermutlich führen Sie das Skript wie folgt aus:

sh ForLoopAlphabetTest.sh

In Ubuntu ist sh mit dash verknüpft; Da dash kein Array-Konzept hat, erhalten Sie den Syntaxfehler für ( .

Das Skript funktioniert perfekt auf bash , es wäre also in Ordnung, wenn Sie es als bash 's Argument ausführen:

bash ForLoopAlphabetTest.sh

Nun haben Sie das bash shebang im Skript, damit Sie das Skript ausführbar machen können ( chmod u+x ForLoopAlphabetTest.sh ) und es als:

ausführen
/path/to/ForLoopAlphabetTest.sh

oder aus dem Skriptverzeichnis:

./ForLoopAlphabetTest.sh

Beachten Sie auch, dass Ihr Skript die geschweifte Erweiterung {a..z} und das C-style for -Konstrukt: for (( ... )) enthält, die auch von dash nicht unterstützt werden. Wenn Ihr Ziel also Portabilität ist, sollten Sie nur POSIX sh Syntaxen betrachten.

    
heemayl 18.01.2017, 13:31
quelle
8

Ihr Skript verwendet drei Funktionen der Bash-Shell, die nicht von allen Bourne-Shells bereitgestellt werden. Wie heemayl sagt , können Sie das Skript einfach mit bash anstelle von sh ausführen. Ihre Hashbang -Zeile oben ( #!/bin/bash ) gibt bash an, ist aber nur wirksam, wenn Sie Führe das Skript aus, wie heemayl erklärt . Wenn Sie den Namen des Skripts an sh übergeben, ruft sh nicht automatisch bash auf, sondern führt das Skript einfach aus. Dies liegt daran, sobald Ihr Skript ausgeführt wird, hat die Hashbang-Zeile keinen Effekt .

Ihre andere Alternative, wenn Sie vollständig portable Skripts schreiben müssen, die nicht davon abhängen Bei Bash-Funktionen ändern Sie Ihr Skript so, dass es ohne sie funktioniert. Die von Ihnen verwendeten Bash-Funktionen sind:

Bash ist weit verbreitet, besonders auf GNU / Linux-Systemen wie Ubuntu, und (wie Sie gesehen haben) auch auf macOS und vielen anderen Systemen verfügbar. Wenn Sie wissen, wie stark Sie Bash-spezifische Funktionen verwenden, möchten Sie sie vielleicht nur verwenden und sicherstellen, dass Sie Bash (oder eine andere Shell, die die von Ihnen verwendeten Funktionen unterstützt) verwenden, wenn Sie Ihre Skripts ausführen / p>

Sie können sie jedoch durch tragbare Konstrukte ersetzen, wenn Sie möchten. Das Array und C-style for loop ist einfach zu ersetzen; Das Erstellen des Buchstabenbereichs ohne Klammererweiterung (und ohne sie in Ihrem Skript hart zu codieren) ist der eine Teil, der ein wenig schwierig ist.

Zuerst ein Skript, das alle lateinischen Kleinbuchstaben ausgibt:

#!/bin/sh

for i in $(seq 97 122); do
    printf "\$(printf %o $i)\n"
done

Dies ist portabel zu meisten Unix-ähnlichen Systemen und hängt nicht davon ab, welche Bourne-Shell Sie verwenden. Bei einigen Unix-ähnlichen Systemen ist jedoch standardmäßig seq nicht installiert (sie verwenden in der Regel jot statt, welches nicht standardmäßig bei den meisten GNU / Linux-Systemen installiert ist). Sie können eine Schleife mit expr oder arithmetischer Substitution verwenden, um die Portabilität weiter zu erhöhen, wenn Sie Folgendes benötigen:

#!/bin/sh

i=97
while [ $i -le 122 ]; do
    printf "\$(printf %o $i)\n"
    i=$((i + 1))
done

Das verwendet einen while -loop mit dem Befehl [ , um mit dem Schleifen fortzufahren nur wenn $i im Bereich ist.

Anstatt das gesamte Alphabet zu drucken, definiert Ihr Skript eine Variable n und gibt die ersten $n Kleinbuchstaben aus. Hier ist eine Version Ihres Skripts, die auf keine Bash-spezifischen Funktionen angewiesen ist und auf Dash funktioniert, aber seq benötigt:

#!/bin/sh

n=3 start=97
for i in $(seq $start $((start + n - 1))); do
    printf "\$(printf %o $i)\n"
done

Wenn Sie den Wert von n anpassen, ändert sich die Anzahl der gedruckten Buchstaben wie in Ihrem Skript.

Hier ist eine Version, die nicht seq benötigt:

#!/bin/sh

n=3 i=97 stop=$((i + n))
while [ $i -lt $stop ]; do
    printf "\$(printf %o $i)\n"
    i=$((i + 1))
done

Dort ist $stop eins höher als der Zeichencode des letzten zu druckenden Buchstabens, also verwende ich -lt (kleiner als) und nicht -le (kleiner als oder gleich) mit dem Befehl [ . (Es hätte auch funktioniert, stop=$((i + n - 1)) zu machen und [ $i -le $stop ] zu benutzen).

    
Eliah Kagan 18.01.2017 17:02
quelle

Tags und Links