Michael Bäuerle <
michael....@gmx.net> in der Gruppe
«de.comm.software.newsreader»:
[Es geht um ein Wrapper‐Skript, das vom newsreader «flnews»
gestartet werden soll, um einen externen Editor – hier
«/usr/pkg/bin/xnedit» – zu starten.]
> Ich hatte gerade folgendes Script getestet:
>
> -----------------------------------------------------------------------
> #! /bin/sh
>
> /usr/pkg/bin/xnedit -geometry 70x50+0+85 -- $@
> -----------------------------------------------------------------------
>
> Das hat auch funktioniert.
>
Aber bitte in Shell‐Skripten «$@» immer in Anführungszeichen
setzen – es sei denn, man will, dass die Werte des Parameters «@»
nach dem Auswerten noch überall da zerbrochen werden, wo sie ein
in der Shell‐Variablen «IFS» enthaltenes Zeichen enthalten, und,
dass anschließend auch noch in den Bruchstücken zufällig
enthaltene (aber hier nicht so gemeinte) Dateinamensmuster («?»,
«*», «[…]») durch entsprechende gefundene Dateinamen ersetzt
werden.
Des weiteren empfiehlt es sich, bei Wrapper‐Shell‐Skripten das
gewrappte Programm, das am Ende gestartet werden soll, mittels
«exec» zu starten, damit es in der Prozess‐Baum‐Struktur den
Platz des Wrapper‐Skripts einnimmt und nicht etwa einen weiteren
Prozess erzeugt.
Beispielsweise könnte es ja sein, dass «flnews» in gewissen
Fällen gewisse Signale (beispielsweise ein Hangup‐, Interrupt‐
oder Stop‐Signal) an den von ihm gestarteten Editor schicken
möchte. Würde das Wrapper‐Skript einen eigenen Prozess
spendieren, würden diese Signale nur das Wrapper‐Skript statt den
von ihm gestarten Editor erreichen. (Dass Signale an einen
Prozess auch dessen Prozess‐Kinder erreichen, ist ein Märchen,
das sich leider hartnäckig hält.)
Die erste Zeile
#! /bin/sh
in einer lesbaren und ausführbaren Shell‐Skript‐Datei ist für den
Shell «/bin/sh», der die Datei lesen und interpretieren wird, nur
ein Kommentar (denn sie beginnt mit einem «#»). Ihre
Sonderbedeutung erhält sie erst von den in der
Laufzeitfunktionsbibliothek enthaltenen Funktionen der
«exec»‐Familie:
Wenn so eine Funktion eine Datei, die kein echtes
(Maschinen‐)Programm ist, als Programm zu starten versucht,
scheitert das zunächst, weil ein Shell‐Skript kein
Maschinen‐Programm ist. Die Funktion unternimmt dann einen
zweiten Versuch: Sie öffnet das Shell‐Skript zum Lesen und
schaut nach, ob die erste Zeile mit der Zeichenfolge «#!»
beginnt. Ist das der Fall, liest sie den Rest der Zeile. Sie
erwartet in dieser Zeile den Namen eines Shells und optional noch
einen Parameter. Dann startet sie den Shell und übergibt ihm den
optionalen Parameter (falls vorhanden) und den Namen des
Shell‐Skripts als (weiteren) Parameter.
Der gestartete Shell liest das Shell‐Skript und arbeitet den in
ihr stehenden Text als Shell‐Kommandos ab.
Sollte der Dateiname dieses Shell‐Skripts mit einem Minuszeichen
(«-») oder einem Pluszeichen («+») beginnen, würde der Shell den
Namen nicht als Dateinamen sondern als Shell‐Aufruf‐Option
missverstehen. Um das zu verhindern, empfiehlt es sich, in die
«#!»‐Zeile als optionalen Parameter den Parameter «-» (ein
einzelnes Minuszeichen) zu stellen. Er sorgt dafür, dass die
Funktion aus der Laufzeitbibliothek dem Shell als ersten
Parameter «-» und erst als zweiten Parameter den Namen des
Shell‐Skripts mitgibt. Der Parameter «-» teilt dem Shell mit,
dass alle weiteren Parameter keine Shell‐Optionsparameter sind,
auch wenn sie mit einem Minus‐ oder Plus‐Zeichen beginnen
sollten.
In der Summe würde ich das Shell‐Skript so formulieren:
#! /bin/sh -
exec /usr/pkg/bin/xnedit -geometry 70x50+0+85 -- "$@"
Wenn «flnews» es dann beispielsweise mit dem Parameter
«ein Dateiname» startet, bewirkt das, dass «/bin/sh» mit den
Parametern «-», «das_Shell‐Skript» und «ein Dateiname» gestartet
wird. «/bin/sh» liest dann das Shell‐Skript ein, ignoriert die
Kommentarzeile und interpretiert die zweite Zeile, nachdem er den
Parameter «@» durch den übergebenen Parameter «ein Dateiname»
ersetzt hat, so, als hätte man die Kommandozeile
exec /usr/pkg/bin/xnedit -geometry 70x50+0+85 -- \
'ein Dateiname'
ins Shell‐Skript geschrieben.
Das hat denselben Effekt, als hätte man «flnews» mitteilen
können, das Programm «/usr/pkg/bin/xnedit» mit (neben dem
Dateinamen noch) den zusätzlichen Parametern «-geometry»,
«70x50+0+85», «--» zu starten: Das Shell‐Skript bewirkt in der
Summe nur eine Hinzunahme der Parameter «-geometry», «70x50+0+85»
und «--». Es entsteht kein weiterer Prozess, und es wird auch
nichts am übergebenen Dateinamen herumgefummelt – genau das, was
hier gewünscht ist.
Merksätze für Wrapper‐Skripte:
Man verwendet zum Weiterreichen der Parameter, die das
Wrapper‐Skript vom Aufrufer erhalten hat, den Parameter «@»,
nicht etwa «*», und man verwendet ihn in Anführungszeichen, also
«"$@"», damit die vom Aufrufer dem Wrapper‐Skript übergebenen
Parameter unverfälscht an das gewrappte Programm weitergereicht
werden.
Das gewrappte Programm, das vom Wrapper‐Skript schließlich
gestartet werden soll, startet man mit dem Shell‐Kommando «exec»,
damit der Wrapper‐Skript‐Prozess keinen neuen Prozess erzeugt, um
das gewrappte Programm zu starten, sondern jetzt das gewrappte
Programm selber ausführt. So sorgt man dafür, dass das gewrappte
Programm im Prozess‐Baum genau dort steht, wo der Aufrufer (hier:
«flnews») das Wrapper‐Skript hingestellt hatte.
Mein Vorschlag wäre, Wrapper‐Shell‐Skripte in der Gruppe
«de.comp.os.unix.shell» zu diskutieren. Deshalb mache ich 'mal
ein Crossposting mit Followup‐To dorthin. Bei Bedarf bitte
seinerseits anpassen.
--
Hat man erst verstanden, wie Unix funktioniert, ist auch
das Shell-Handbuch kein Buch mit sieben Siegeln mehr.