it-swarm.com.de

Für Schleife mit Alphabet

Dies funktioniert perfekt unter 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 laufen lasse, erhalte ich die folgende Fehlermeldung.

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

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

12
denski

Vermutlich führen Sie das Skript aus als:

sh ForLoopAlphabetTest.sh

In Ubuntu ist sh mit dash verknüpft. Da dash kein Array-Konzept hat, wird der Syntaxfehler für ( angezeigt.

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

bash ForLoopAlphabetTest.sh

Jetzt haben Sie den Shebang bash im Skript, sodass Sie das Skript ausführbar machen (chmod u+x ForLoopAlphabetTest.sh) und es ausführen können als:

/path/to/ForLoopAlphabetTest.sh

oder aus dem Skriptverzeichnis:

./ForLoopAlphabetTest.sh

Beachten Sie auch, dass Ihr Skript die Klammererweiterung {a..z} und das Konstrukt for im C-Stil enthält: for (( ... )), die auch von dash nicht unterstützt werden; Wenn Ihr Ziel Portabilität ist, sollten Sie sich nur die Syntax POSIX sh ansehen.

25
heemayl

Ihr Skript verwendet drei Funktionen der Bash-Shell, die nicht von allen Bourne-Shells bereitgestellt werden. Wie heemayl sagt, können Sie dieses Skript einfach mit bash anstelle von sh ausführen. Ihre Hashbang -Zeile oben (#!/bin/bash) gibt bash an, ist jedoch nur wirksam, wenn Sie ausführen das Drehbuch, 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, dass , sobald Ihr Skript tatsächlich ausgeführt wird, die Hashbang-Zeile keine Wirkung hat .

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

  • Ein Array . Dies war der erste Schritt, weshalb der Fehler aufgetreten ist, als Sie versucht haben, Ihr Skript mit der Dash-Shell auszuführen. Der in Klammern gesetzte Ausdruck ( {a..z} ), den Sie chars zuweisen, erstellt ein Array, und ${chars[i]}, der in Ihrer Schleife angezeigt wird, indiziert es.
  • Klammererweiterung. In Bash und auch in vielen anderen Shells wird {a..z} zu a b c d e f g h i j k l m n o p q r s t u v w x y z erweitert. Dies ist jedoch keine universelle (oder standardisierte) Funktion von Bourne-Shells, und Dash unterstützt sie nicht.
  • Die C-artige alternative for- Schleifensyntax . Obwohl auf der arithmetischen Erweiterung basiert, die nicht spezifisch für Bash ist (obwohl einige sehr alt sind, Nicht POSIX-konforme Shells haben es auch nicht), die C-artige for-Schleife ist ein Bash-Ismus und ist nicht überall auf andere Muscheln übertragbar.

Bash ist weit verbreitet, insbesondere auf GNU/Linux-Systemen wie Ubuntu, und (wie Sie gesehen haben) auch auf macOS und vielen anderen Systemen verfügbar. In Anbetracht dessen, wie oft Sie Bash-spezifische Funktionen verwenden, möchten Sie diese möglicherweise nur verwenden und stellen Sie einfach sicher, dass Sie Bash (oder eine andere Shell, die die von Ihnen verwendeten Funktionen unterstützt) verwenden, wenn Sie Ihre Skripts ausführen.

Sie können sie jedoch durch portable Konstrukte ersetzen, wenn Sie möchten. Das Array und die for-Schleife im C-Stil können leicht ersetzt werden. Das Generieren des Buchstabenbereichs ohne geschweifte Klammern (und ohne festes Codieren in Ihrem Skript) ist der eine Teil, der ein wenig knifflig ist.


Hier ist ein Skript, das alle lateinischen Kleinbuchstaben ausgibt:

#!/bin/sh

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

Dies ist portierbar für die meisten Unix-ähnlichen Systeme und hängt nicht davon ab, welche Bourne-artige Shell Sie verwenden. Auf einigen Unix-ähnlichen Systemen ist jedoch seq nicht standardmäßig installiert (sie verwenden in der Regel jot , was auf den meisten GNU/Linux-Systemen standardmäßig nicht installiert ist). Sie können eine Schleife mit expr oder eine arithmetische Ersetzung verwenden, um die Portabilität weiter zu erhöhen, wenn Sie Folgendes tun müssen:

#!/bin/sh

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

Dabei wird eine while- Schleife mit dem Befehl [ verwendet, um die Schleife nur dann fortzusetzen, wenn $i in Reichweite 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 sich auf keine Bash-spezifischen Funktionen stützt und auf Dash funktioniert, jedoch seq erfordert:

#!/bin/sh

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

Durch Anpassen des Werts von n wird geändert, wie viele Buchstaben gedruckt werden, wie in Ihrem Skript.

Hier ist eine Version, für die seq nicht erforderlich ist:

#!/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 um eins höher als der Zeichencode des letzten Buchstabens, der gedruckt werden soll, daher verwende ich -lt (kleiner als) statt -le (kleiner als oder gleich) mit dem Befehl [. (Es hätte auch funktioniert, stop=$((i + n - 1)) zu machen und [ $i -le $stop ] zu verwenden).

10
Eliah Kagan