Schreiben von Shell-Skripten, die auf jeder Shell ausgeführt werden können (mithilfe mehrerer Shebang-Zeilen?)

Schreiben von Shell-Skripten, die auf jeder Shell ausgeführt werden können (mithilfe mehrerer Shebang-Zeilen?)

Ich habe gerade angefangen, mich intensiver mit Shell-Skripten zu beschäftigen, und ich habe mein Skript immer einfach in eine Datei geworfen, es markiert chmod +xund dann auf Fertig gestellt /path/to/script.shund den Standardinterpreter damit machen lassen, was ich für zsh hielt, weil ich das für meine Shell verwendete. Anscheinend ist das einfach /bin/shstandardmäßig so, selbst wenn ich das Skript von einer Zsh-Eingabeaufforderung aus ausführe, weil ich angefangen habe, Zsh-spezifisches Zeug in meine Skripte zu packen, und es schlägt fehl, wenn ich nicht ausführe zsh /path/to/script.sh.

Um auf den Punkt zu kommen, hier meine Fragen:

  1. #!/path/to/shellWelche Shell führt Skripte aus, wenn am Anfang keine Shebang-Zeile () steht ? Ich nehme es an /bin/sh, kann es aber nicht bestätigen.
  2. Was gilt als „Best Practice“ beim Schreiben von Shell-Skripten, die auf allen Plattformen ausgeführt werden können? (OK, das ist irgendwie offen)
  3. Ist es möglich, ein Skript zu schreiben, das versucht, zsh zu verwenden und auf bash zurückgreift, wenn zsh nicht verfügbar ist? Ich habe versucht, zwei Shebang-Zeilen einzufügen, wie unten, aber es tritt einfach ein Fehler bad interpreter: /bin/zsh: no such file or directoryauf, wenn ich es auf einem Computer ohne zsh versuche.

    #!/bin/zsh

    #!/bin/bash

Antwort1

Welche Shell führt Skripte aus, wenn am Anfang keine Shebang-Zeile (#!/Pfad/zur/Shell) steht? Ich nehme an /bin/sh, kann es aber nicht bestätigen.

Der Kernel weigert sich, solche Skripte auszuführen und gibt ENOEXEC zurück. Das genaue Verhalten hängt also von dem Programm ab, in dem Sie ein solches Skript ausführenaus.

  • bash 4.2.39 – verwendet sich selbst
  • busybox-ash 1.20.2 – verwendet sich selbst
  • dash 0.5.7 – führt /bin/sh aus
  • fish 1.23.1 – beschwert sich über ENOEXEC und gibt dann der falschen Datei die Schuld
  • AT&T ksh 93u+2012.08.01 – verwendet sich selbst
  • mksh R40f – führt /bin/sh aus
  • pdksh 5.2.14 – führt /bin/sh aus
  • sh-heirloom 050706 – verwendet sich selbst
  • tcsh 6.18.01 – führt /bin/sh aus
  • zsh 5.0.0 – führt /bin/sh aus
  • cmd.exe 5.1.2600 – sieht dich komisch an.

Inglibc, Funktionen execv()oder execve()geben einfach ENOEXEC zurück. Aber execvp()verbirgt diesen Fehlercode und ruft automatisch /bin/sh auf. (Dies ist dokumentiert inexec(3p).)

Was gilt als „Best Practice“ beim Schreiben von Shell-Skripten, die auf allen Plattformen ausgeführt werden können? (OK, das ist irgendwie offen)

Entweder Sie beschränken sich auf shPOSIX-definierte Funktionen oder Sie nutzen die volleSchlag(das weithin verfügbar ist) und erwähnen Sie es in Ihren Anforderungen, wenn Sie es verteilen.

(Wenn ich darüber nachdenke, wäre Perl – oder vielleicht Python – sogar noch portabler, ganz zu schweigen von der besseren Syntax.)

StetsFügen Sie die Shebang-Zeile hinzu. Wenn Sie Bash oder Zsh verwenden, verwenden Sie #!/usr/bin/env bashanstelle der Hardcodierung des Shell-Pfads. (Allerdings ist die POSIX-Shell garantiert unter /bin/sh, überspringen Sie es envin diesem Fall also.)

(Leider /bin/shist gerade nicht immer dasselbe. Die GNUautoconfProgramm muss sich mitviele verschiedene Macken.)

Ist es möglich, ein Skript zu schreiben, das versucht, zsh zu verwenden und auf bash zurückgreift, wenn zsh nicht verfügbar ist? Ich habe versucht, zwei Shebang-Zeilen einzufügen, wie unten, aber es gibt nur Fehler mitfehlerhafter Interpreter: /bin/zsh: keine solche Datei oder kein solches Verzeichnisaus, wenn ich es auf einer Maschine ohne zsh versuche.

Es kann nur eine Shebang-Zeile geben; alles nach dem Newline-Zeichen wird vom Kernel nicht einmal gelesen und von Shells als Kommentar behandelt.

Es istmöglichein Skript zu schreiben, das als ausgeführt wird #!/bin/sh, prüft, welche Shell verfügbar ist, und je nach Ergebnis exec zsh "$0" "$@"oder ausführt. Die von Bash und Zsh verwendete Syntax ist jedoch an verschiedenen Stellen so unterschiedlich, dass ichexec bash "$0" "$@"nicht empfehlen, dies zu tunfür Ihre eigene geistige Gesundheit.

Antwort2

1) Die aktuelle Shell, in der Sie ausgeführt werden. (welche Shell das auch sein mag)

2) Bleiben Sie beim gleichen Shell-Typ (bash/dash/ash/csh/was auch immer Sie bevorzugen) und stellen Sie sicher, dass Ihre „unterstützten Plattformen“ standardmäßig die Shell installieren, die Sie verwenden möchten. Versuchen Sie außerdem, allgemein verfügbare Befehle auf Systemen zu verwenden. Vermeiden Sie maschinenspezifische Optionen.

3) Es gibt nicht wirklich eine "Wenn-Dann-Sonst"-Logik interpreter directive. Sie sollten eine Shell angeben, die auf allen Systemen vorhanden sein sollte, die Sie unterstützen möchten, #!/bin/bashoder eine generische angeben, #!/bin/shsolange Ihr Skript für alle Shells einigermaßen generisch ist.

verwandte Informationen