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 bashanstelle von ausführen sh. Ihre Hashbang- Zeile oben ( #!/bin/bash) gibt an, bashaber sie ist nur wirksam, wenn Sie das Skript ausführen , wie er es erklärt hat . Wenn Sie den Namen des Skripts übergeben sh, shwird das Skript nicht automatisch aufgerufen bash, sondern nur ausgeführt. Dies liegt daran, dass, sobald Ihr Skript ausgeführt wird, die Hashbang-Zeile keine Auswirkung mehr hat .
Wenn Sie vollständig portable Skripte schreiben müssen , die nicht von den Bash-Funktionen abhängen, können Sie Ihr Skript auch so ändern, dass es ohne sie funktioniert. Die von Ihnen verwendeten Bash-Funktionen sind:
- Ein Array . Dies war der erste Schritt. Daher ist dies der Grund, warum Sie versucht haben, Ihr Skript mit der Dash-Shell auszuführen . Der Ausdruck in Klammern
( {a..z} ), den Sie zuweisen chars, erstellt ein Array und ${chars[i]}indiziert es, das in Ihrer Schleife angezeigt wird.
- Klammererweiterung. In Bash, und auch in vielen anderen Schalen,
{a..z}wird darauf erweitert 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. Dies ist jedoch keine universelle (oder standardisierte) Funktion von Bourne-Shells, und Dash unterstützt sie nicht.
- Die alternative
forSchleifen-Syntax im C-Stil . Obwohl die C- Schleife auf einer arithmetischen Erweiterung basiert , die selbst nicht spezifisch für Bash ist (obwohl einige sehr alte, nicht POSIX-konforme Shells diese auch nicht haben), ist sie ein Bash-Ismus und nicht weit verbreitet andere Muscheln.for
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 C-förmige forSchleife können leicht ausgetauscht 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
- Der
seqBefehl generiert numerische Sequenzen. $( )Führt eine Befehlssubstitution durch und $(seq 97 122)wird durch die Ausgabe von ersetzt seq 97 122. Dies sind die Zeichencodes für athrough z.
- Mit dem leistungsstarken
printfBefehl können Zeichencodes in Buchstaben umgewandelt werden (z. B. printf '\141'Ausdrucke a, gefolgt von einem Zeilenumbruch ). Die Codes müssen jedoch in Oktalform vorliegen , während sie seqnur in Dezimalform ausgegeben werden . So ich verwendet habe , printfzweimal: die innere printf %o $iwandelt Dezimalzahlen (vom seq) zu oktale und ist substituiert in den äußeren printfBefehl. (Obwohl es auch möglich ist , hexadezimal zu verwenden , ist es nicht einfacher und scheint weniger portabel zu sein .)
printfinterpretiert \gefolgt von einer Oktalzahl als das Zeichen mit diesem Code und \nals eine neue Zeile. Aber die Schale verwendet auch \als Escape - Zeichen. Eine \vor $wird verhindert , dass $von verursacht eine Expansion auftreten (in diesem Fall Befehl Substitution ), aber ich möchte nicht , dass verhindern, so habe ich es mit einem anderen entkommen \; das ist der grund dafür \\. Die zweite , \bevor nnicht entkommen werden müssen , weil, im Gegensatz zu \$, \nhat keine besondere Bedeutung für den Shell in einer Strings in doppelten Anführungszeichen.
- Weitere Informationen zur Verwendung von Anführungszeichen und Backslash in der Shell-Programmierung finden Sie im Abschnitt über Anführungszeichen im internationalen Standard . Siehe auch 3.1.2 Zitieren im Bash-Referenzhandbuch , insbesondere 3.1.2.1 Escape-Zeichen und 3.1.2.3 Anführungszeichen . (Hier ist der gesamte Abschnitt im Kontext.) Beachten Sie, dass einfache Anführungszeichen (
') ebenfalls ein wichtiger Bestandteil der Shell-Zitiersyntax sind. Ich habe sie nur zufällig nicht in diesem Skript verwendet.
Dies ist für die meisten Unix-ähnlichen Systeme portierbar und hängt nicht davon ab, welche Bourne-Shell Sie verwenden. Einige Unix-ähnliche Systeme sind jedoch nicht seqstandardmäßig installiert (sie verwenden in der Regel jotstattdessen die meisten GNU / Linux-Systeme, die standardmäßig nicht installiert sind). Sie können eine Schleife mit exproder eine arithmetische Substitution 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
Das verwendet eine while-loop mit dem [Befehl , um die Schleife nur fortzusetzen, wenn sie $isich in Reichweite befindet.
Anstatt das gesamte Alphabet zu drucken, definiert Ihr Skript eine Variable nund druckt die ersten $nKleinbuchstaben. Hier ist eine Version Ihres Skripts, die sich auf keine Bash-spezifischen Funktionen stützt und auf Dash funktioniert, jedoch Folgendes erfordert seq:
#!/bin/sh
n=3 start=97
for i in $(seq $start $((start + n - 1))); do
printf "\\$(printf %o $i)\n"
done
Das Anpassen des Werts nändert, wie viele Buchstaben gedruckt werden, wie in Ihrem Skript.
Hier ist eine Version, die nicht benötigt wird seq:
#!/bin/sh
n=3 i=97 stop=$((i + n))
while [ $i -lt $stop ]; do
printf "\\$(printf %o $i)\n"
i=$((i + 1))
done
Es $stopgibt einen höheren Code als den Zeichencode des letzten Buchstabens, der gedruckt werden soll, daher verwende ich für den Befehl -lt(weniger als) und nicht -le(weniger als oder gleich) [. (Es hätte auch funktioniert, um zu machen stop=$((i + n - 1))und zu verwenden [ $i -le $stop ]).