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 ausführen sh
. Ihre Hashbang- Zeile oben ( #!/bin/bash
) gibt an, bash
aber sie ist nur wirksam, wenn Sie das Skript ausführen , wie er es erklärt hat . Wenn Sie den Namen des Skripts übergeben sh
, sh
wird 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
for
Schleifen-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 for
Schleife 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
seq
Befehl 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 a
through z
.
- Mit dem leistungsstarken
printf
Befehl 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 seq
nur in Dezimalform ausgegeben werden . So ich verwendet habe , printf
zweimal: die innere printf %o $i
wandelt Dezimalzahlen (vom seq
) zu oktale und ist substituiert in den äußeren printf
Befehl. (Obwohl es auch möglich ist , hexadezimal zu verwenden , ist es nicht einfacher und scheint weniger portabel zu sein .)
printf
interpretiert \
gefolgt von einer Oktalzahl als das Zeichen mit diesem Code und \n
als 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 n
nicht entkommen werden müssen , weil, im Gegensatz zu \$
, \n
hat 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 seq
standardmäßig installiert (sie verwenden in der Regel jot
stattdessen die meisten GNU / Linux-Systeme, die standardmäßig nicht installiert sind). Sie können eine Schleife mit expr
oder 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 $i
sich in Reichweite befindet.
Anstatt das gesamte Alphabet zu drucken, definiert Ihr Skript eine Variable n
und druckt die ersten $n
Kleinbuchstaben. 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 $stop
gibt 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 ]
).