Ressourcen für die portable Shell-Programmierung

65

Welche Ressourcen gibt es für die portable Shell-Programmierung? Die ultimative Antwort ist das Testen auf allen Zielplattformen, aber das ist selten praktikabel.

Die POSIX / Single UNIX-Spezifikation ist ein Anfang, gibt jedoch weder Aufschluss über den Grad der Unterstützung für die einzelnen Implementierungen noch über die gängigen Erweiterungen. Sie können die Dokumentation jeder Implementierung lesen, dies ist jedoch sehr zeitaufwendig und nicht vollständig korrekt.

Mir scheint, dass ein ideales Format eine von der Community kommentierte Version der POSIX-Spezifikation wäre, bei der jedes Feature durch seine Unterstützungsstufe zwischen den verschiedenen Implementierungen kommentiert wird. Gibt es so etwas? Oder gibt es andere nützliche Ressourcen?

Zum Beispiel gibt es Sven Maschecks Shell-Portabilitätsseiten , aber es geht nur um syntaktische Elemente und einige eingebaute Elemente und es werden nur alte Shells behandelt. Ich suche nach einer umfassenderen Ressource.

Gilles
quelle
2
Bitte antworten Sie hier nicht nur, um das Konformitätsdokument einer bestimmten Implementierung zu zitieren. Wenn Sie eines davon haben, ist das entsprechende Tag-Wiki ein guter Ort.
Gilles
1
Jemand muss das Revisionsprotokoll für autoconfund Metaconfig(Perl, rn) abrufen und alle Tricks und ihre erklärenden Kommentare an einem Ort sammeln.
Geekosaurier
@geekosaur: Guter Vorschlag. Ich habe mir noch nie die Interna von autoconf angesehen. Gibt es etwas, das man als Leitfaden beim Schreiben eigener Skripte verwenden kann? Wenn ja, wäre dies eine gute Antwort auf meine Frage, auch wenn es keine endgültige ist.
Gilles
5
Ich bin mir sicher, dass Sie beide es leicht finden können, aber für andere, die diesem Thread folgen, ist hier ein Link zu einer relevanten Seite aus dem Autoconf-
J. Taylor

Antworten:

32

Das Autoconf-Handbuch enthält einen Abschnitt zur portablen Shell-Programmierung .

Obwohl dies nicht speziell auf POSIX abzielt, handelt es sich wahrscheinlich um die umfassendste Auflistung von Maßnahmen, die beim Versuch, portablen Shell-Code zu schreiben, zu treffen und nicht zu ergreifen sind.

Riccardo Murri
quelle
3
Das ist eine der besten Ressourcen und wurde beim Schreiben von Code in M4 erstellt, der Shell-Code erzeugen musste, der über so viele Shells wie möglich portierbar war.
Tim Post
6

Zusätzlich zu dashund poshgibt es bournesh(oder bsh) die Heirloom Bourne Shell , mit der Bashisms erkannt werden können .

Zum Heirloom-Projekt gehört auch "The Heirloom Toolchest", eine Sammlung von mehr als 100 Standard-Unix-Dienstprogrammen (die als Ausgangspunkt für den Vergleich von Befehlszeilenoptionen dienen können).

ralf
quelle
2
Beachten Sie, dass die Bourne-Shell keine POSIX-Shell ist. Wenn Sie Ihr Skript auf die Bourne-Shell portieren, müssen Sie die Syntax Ihres Skripts von der Standard-POSIX-Sprache sh auf den gemeinsamen Nenner zwischen dieser und der Syntax der Bourne-Shell zurückstufen. Es lohnt sich nicht, diese Ansicht zu vertreten, es sei denn, Sie möchten auf ältere Systeme portierbar sein (oder Solaris 10 und früher und Sie haben nicht die Wahl, die Standard-sh zu verwenden, die sich dort in / usr / xpg4 / bin befand).
Stéphane Chazelas
5

Versuchen Sie, ähnlich wie bei dieser Antwort , Ihr Skript in eleganter Form auszuführen .

Vergessen Sie auch nicht, die POSIXLY_CORRECTUmgebungsvariable auf true zu setzen, da dies dazu führt, dass sich viele Programme (nicht nur die Shell) strenger an die POSIX-Standards halten.

Philomath
quelle
4

Das Schreiben Ihrer Skripte mit dem Bindestrich könnte ein Anfang sein.

Glenn Jackman
quelle
3
Das Testen mit dash ist das absolute Minimum, um zu vermeiden, dass man sich versehentlich auf ksh / bash-Funktionen verlässt, aber ich bin nach mehr strebend: über Mängel in anderen Shells (z. B. schlechtes Trap-Handling von zsh) und vor allem in Shell-Dienstprogrammen (z. B. noch OpenBSDs) findinformiert hat nicht implementiert -exec +).
Gilles
FWIW, OpenBSD findmacht das -exec utility {} +heutzutage.
Kusalananda
2

Bis zu einem gewissen Grad können Sie das checkbashismsDebian / Ubuntu- devscriptsPaket ausprobieren .

Es ist nicht perfekt, aber es hat den Vorteil, ein existierender Ausgangspunkt zu sein. Zum Beispiel sieht es nicht die klassischen Störungen mit sed/ in findBezug auf die GNU vs BSD / andere Unterschiede.

Standardmäßig ist es Debian + Bindestrich-orientiert, die -pFlagge kann in Ihrem Fall nützlich sein.

Shellholic
quelle
2

Heutzutage finden Sie normalerweise eine POSIX-Shell auf einem System, und dies bedeutet im Allgemeinen, dass Sie Skripte in der POSIX-Sprache ausführen können (modulo führt zu Compliance-Fehlern).

Das einzige Problem ist, dass /bin/shes manchmal keine POSIX-Shell gibt. Und Sie müssen die #!Zeile in Skripten fest codieren, die sich als nette ausführbare Dateien verhalten sollen. Sie können den Benutzer nicht einfach auffordern, das Problem zu untersuchen und dann Ihr Skript als aufzurufen /path/to/posix/shell myscript.

Der Trick besteht also darin, POSIX-Funktionen in Ihrem Skript zu verwenden, das Skript jedoch automatisch die POSIX-Shell finden zu lassen. Eine Möglichkeit ist wie folgt:

#!/bin/sh

# At this point, we may be running under some old shell
# we have to tread carefully.

# note how we use test rather than [ ] syntax and avoid
# depending on test with no argument producing a failure;
# i.e. "test $posix_shell".

if ! test x$posix_shell = x ; then
  # the three possible shell paths are just an example;
  # please extend as necessary.

  for shell in /usr/xpg4/bin/sh /bin/bash /usr/bin/bash ; do
    if test -x $shell ; then
       posix_shell=$shell
    fi
  done
  if test x$posix_shell = x ; then
    echo "no POSIX shell found"
    exit 1
    # or we could avoid bailing here and just fall back on /bin/sh:
    # echo "falling back on /bin/sh: cross your fingers that it works"
    # posix_shell=/bin/sh
  fi
  export posix_shell

  # plain "$@" is broken in ancient shells! 
  # I seem to recall ${@+"$@"}: not sure if that's the right trick.

  exec $posix_shell $0 ${@+"$@"}  # can we count on exec in legacy shells? 
fi

# phew, at this point in the script we have been re-executed and are
# being interpreted by some reasonably modern shell. We can use $(...)
# command substitution, and other features.

Es gibt andere Ansätze, beispielsweise die Codegenerierung. Boostrapen Sie Ihre Skripte mit einem kleinen Skript, das eine Reihe von Skriptdateien ohne ein # enthält! Zeile und fügt eine hinzu.

Das Schlimmste, was Sie tun können, ist, ganze Skripte so zu schreiben, dass sie ab 1981 auf einer Bourne-Shell ausgeführt werden. Dies ist nur erforderlich, wenn Sie für ein System schreiben müssen, das wirklich keine andere Shell hat .

Kaz
quelle