Seit einiger Zeit hat die Newsgroup de.comp.os.unix.shell mit Postings
eines gewissen Helmut Schellong zu tun, in denen er sein Programm »bsh«
ungebeten anpreist. Da sich herausstellte, daß dieses Programm nach
Ansicht vieler Teilnehmer fragwürdige, aber laut Autor gewollte Eigenheiten
hat, habe ich sie hier zusammengestellt.
> Sehr übertriebene Darstellung zu Postings
über eine 100%-OnTopic-Shell.
> In 5-10% aller Postings gibt es möglicherweise
einen werbenden Tonfall von mir - mehr steckt nicht dahinter.
> In Antworten (innerhalb von Diskussionen) kann
man die Nennung positiver Merkmale meist nicht vermeiden;
> das kann nicht einfach als "anpreisen" dargestellt
werden.
> Verfolgt man die NG-Postings, stellt man ein
riesiges Tohuwabohu fest, was hinter einem tradionellen Pfad
> wie beispw. /bin/sh an Unterschiedlichkeit
steckt - je nach Unix-System. Man könnte offenbar Bücher darüber
füllen...
> Auch von vielen Shell-Bugs ist die Rede.
> Alle Shells (csh,ksh,bash,tcsh,ash,zsh,pdksh)
haben ihre eigene, proprietäre Syntax bzw. proprietäre
> Erweiterungen gegenüber der 'sh', und
das sogar untereinander gemischt und auch noch plattformabhängig.
> Für bsh gilt das ebenso, jedoch ist sie
bei weitem plattformunabhängiger als die anderen Shells.
> bsh enthält weitgehend die Syntax der ksh,
mit gleicher oder nahezu gleicher Semantik, wobei die ksh wiederum
> die Syntax der Bourne-Shell (sh) enthält.
Der Autor der »bsh« behauptet, seine Shell verfüge über eine ähnliche Syntax. Bei oberflächlicher Betrachtung mag man das hinnehmen, es werden z.B. dieselben Namen für Kontrollkonstrukte (for - do - done, if - then - fi) und Befehle (break, expr) verwendet. Sieht man jedoch genauer hin, ergeben sich gravierende Unterschiede.
> if then else elif fi case esac Schlüsselwort-Kommandos > for while until do done time Schlüsselwort-Kommandos > in from by to repeat Schlüsselwort-Argumente > { } {{ }} Schlüsselwort-Kdo-Paare > [ ] [[ ]] Kommandos mit Schlußarg > break continue goend Programmier-Kommandos > return goto Programmier-Kommandos> Unterschiede sind gar nicht oder kaum vorhanden.
So haben viele Kommandos zwar denselben Namen, aber andere Optionen
oder sonstige Änderungen. expr z.B. wird unter Unix vornehmlich
für simple arithmetische Operationen genutzt. Das expr-Kommando der
»bsh«
kennt sie nicht, stattdessen aber eine Reihe von Erweiterungen im Umfeld
regulärer Ausdrücke. Hier weist das Unix-expr lediglich den Operator
:
auf, der einen String mit einem regulären Ausdruck vergleicht. Letzterer
ist auf den Anfang des Strings fixiert, auch das ist bei »bsh«
nicht der Fall. Die äußere Ähnlichkeit der Syntax täuscht
also, tatsächlich weist das expr-Kommando der »bsh«
massive Unterschiede zum Unix-Kommando auf.
> Original: expr "string" : RE
> bsh: expr "string" : ^RE > bsh: /bin/expr "string" : RE > bsh: extern expr "string" : RE> Einziger Unterschied: bsh-expr gestattet eine Wahl zwischen mit ^ und ohne ^.
> Daß per :: Erweiterungen aktiviert werden, ist gewiß kein Nachteil.
Im Widerspruch zur allgemeinen Praxis auf Unix-Systemen wird von »bsh« nicht der Backslash \, sondern das Prozentzeichen % zum Quoten einzelner Zeichen benutzt. Das heißt, daß zunächst fast jeder String einschließlich regulärer Ausdrücke auf diese Zeichen untersucht und ggf. geändert werden muß; ferner wird % auf Unix-Systemen an so vielen Stellen verwendet, daß es zu Problemen mit dem echo-Kommando der »bsh« kommen kann, das dieses Zeichen zum Einleiten von Escapesequenzen nutzt.
> Das stimmt nicht. bsh gestattet eine Wahl zwischen % und \ :
> aktivieren \ .> bsh -B > set -B > #!/u/bin/bsh -B
Die Kontrollkonstrukte der »bsh« weisen gegenüber denen der Unix-Shell funktionale Beschränkungen auf. Insbesondere ist es nicht möglich, die Ausgabe einer Schleife
while get-some-input do process-one-line done | postprocessoder einer Kommandogruppe gemeinsam unzulenken:
{ echo foo; echo bar; } > output-file> Das stimmt zwar -und ist dokumentiert-, aber als flexibleren Ersatz gibt es hierfür globale Umlenkungen,
> Dies folgt dem Konzept open() ... close() in der Sprache C.<file >>file2 ... >file3 ... ><< ... ><
Schleifen können nicht asynchron ausgeführt werden, das &-Zeichen bleibt in diesem Fall schlicht wirkungslos:
while some-condition do background-processing done &> Letztlich stimmt das nicht. Kommando fork "..." "..." ... gestattet das prinzipiell, mit anderer Syntax
Operationen, für die die Shell gemeinhin eingesetzt wird, lassen sich also mit »bsh« nicht oder nur über Umwege durchführen. Aber selbst wenn die Funktionalität im Prinzip vorhanden ist, ergeben sich Probleme, denn gängige Konstrukte der Unix-Shell werden von »bsh« nicht akzeptiert. So darf break nicht im ersten Kommandoabschnitt einer Schleife stehen:
while { check-this && break; } || check-that do work done> Ab Version 3.40 dürfen break,continue,goend bei while,if,elif stehen.
Funktionsdefinitionen dürfen nicht allein mit ; enden:
foo() { bar; }; foo> Das stimmt, ist dokumentiert und ist Absicht. Das ist IMO grauselige Syntax.
Das Dollarzeichen darf nicht unmaskiert am Ende eines Wortes stehen:
grep foo$ bar> Das stimmt und ist Absicht. $ ist unmaskiert nun mal ein Spezialzeichen, hinter dem Bestimmungsgemäßes folgen muß.
Wenn eine Einflußnahme auf Variablen, Arbeitsverzeichnis, offene Dateien usw. der ausführenden Shell nicht erwünscht ist, kann der Programmierer einen Skriptabschnitt in einer exakten Kopie der Shell (Subshell) ausführen, indem er ihn in Klammern ( ... ) setzt. Auch »bsh« bietet ein solches Konstrukt, jedoch sind Syntax wie Semantik verschieden. So ist es nicht möglich, innerhalb von Subshell-Listen mit Anführungszeichen zu quoten;
( echo '$name' )müßte mit »bsh«
( echo %%%$name )> Hier wird die Variable weder von der aufrufenden Shell noch von der SubShell ausgewertet.
geschrieben werden, um die Auswertung als Variable zu verhindern. Die Subshell der »bsh« ist keine exakte Kopie ihres Vorgängers, denn der Einsatz ihrer Shell-Funktionen ist darin nicht möglich:
foo() { bar; } ( foo )schlägt also fehl.
> Hier kann man sich trefflich streiten:
Variablen, CWD, etc. soll die SubShell nicht übernehmen, Funktionen
aber doch.
> Weder die Unix-Shell-SubShell noch die bsh-SubShell
ist eine exakte Kopie!
> Die Funktion fork() auf C-Ebene erzeugt hingegen
eine fast perfekte Prozeß-Kopie...
> Desweiteren besitzt bsh datei-lokale, funktions-lokale
und -lokal-statische Variablen, Aliase und goto,
> weshalb die SubShell-Einrichtung in der bsh
weitgehend ihre Bedeutung verliert.
> Diese ausgebaute Lokalität der bsh ist
einer ihrer vielen großen Vorteile.
Die Erkennung von Schlüsselworten ist in der Unix-Shell unterbunden, wenn sie mit Quotingzeichen versehen sind oder der entsprechende String aus einer Variablensubstitution entstanden ist. Nicht so in »bsh«:
# "if" true; then echo foo; fi foo # foo=if; $foo true; then echo bar; fi barIn der Unix-Shell läßt sich das, falls gewünscht, mit eval erreichen; das Verhalten der »bsh« kann hingegen dazu führen, daß eine Stelle in einem Skript abhängig von externen Einflüssen als Syntaxfehler gewertet wird.
> Das ist (pauschale) Absicht, um einfache und
schnelle Indirektionen zu ermöglichen.
> bsh gestattet es mittels ifdef -seEf,
ifset -seEf, ifenv genaue Prüfungen vorzunehmen.
> Auch diese 'Ortungsfähigkeit' ist ein
Vorteil der bsh.
Die Verwendung der »bsh« wird von arbiträren Limits eingeschränkt, so gibt es eine feste Obergrenze für Länge und Anzahl von Variablen wie Funktionen. Selbst bei internen Kommandos sind sowohl die Zahl als auch der gesamte Zeichenumfang der Argumente begrenzt.
> Das stimmt primär für die kostenlosen
bsh-Varianten.
> Die Limits sind aber hoch genug gesteckt, um
vieles zu ermöglichen, was durch die öffentlichen Beispiel-Skripte
> bewiesen ist.
Die regulären Ausdrücke in den Kommandos der »bsh« sind ebenfalls proprietär. So gibt es %A für Buchstaben, %U für Großbuchstaben usw. POSIX.2 schreibt dafür nicht nur eine andere Syntax ([:alpha:], [:upper:]) vor, sondern insbesondere auch, daß Umlaute und ähnliche sprachgebundene Zeichen abhängig von der Locale-Einstellung des Systems einbezogen werden; in »bsh« fehlt diese Eigenschaft.
> Das gilt genauso und noch 'viel schlimmer' für
fast alle Programme, die RAs anbieten: z.B.
> perl, vim, JavaScript, diverse GNU-Proprietarismen,
usw.
> Da ist fast das ganze \Alphabet in dieser Weise
besetzt.
Folglich ist es unmöglich, mit »bsh« ein nicht vollkommen triviales Unix-Shellskript auszuführen, ohne in größerem Rahmen Anpassungen vorzunehmen. Die Subtilität der Differenzen macht diesen Prozeß zudem schwer durchschaubar. Wer sowohl Unix-Shells als auch »bsh« einsetzt, wird ständig durch falsche Freunde irritiert.
> bsh ist keine POSIX.2-Shell. bsh ist nun
mal proprietär wie z.B. auch zsh. bsh ist dokumentiert und funktioniert
auch
> entsprechend ihrer Dokumentation einwandfrei.
# if { then; }; fi bsh: Syntaxfehler: 'vermisse ;} ' # while break; do true; done > beseitigt; war und ist dokumentiert. bsh: Syntaxfehler: 'vermisse do' # echo $/ bsh: Parametername zu lang: ''Der Umgang mit der Syntax wird dadurch noch zusätzlich erschwert.
> Auch wenn der Wortlaut nicht immer perfekt paßt,
sind es dennoch hinreichende Hinweise.
> Zumal in Scripten Zeilennummern und ggf. Funktionsnamen
mit angegeben werden.
Fehlerhafte Konstrukte werden mitunter ohne jede Fehlermeldung oder Warnung ausgeführt:
while true && do break | done while true; echo | do; false && done> Bei solchen abenteuerlich 'abgebrochenen' Syntax-Konstruktionen kann das passieren - na und.
Wird eine Datei in ein unvollständiges Kontrollkonstrukt geleitet, führt »bsh« u.U. den Inhalt der Datei aus:
1# echo uname -s | if 1> Linux 1> bsh: Syntaxfehler: 'vermisse then' bsh: Umlenkungsr ckf hrung! 1# echo 'rm -ri /' > foo 2# while < foo 2> rm: examine files in directory / (yes/no)? 2> bsh: Syntaxfehler: 'vermisse do' bsh: Umlenkungsr ck hrung!Die Gefährlichkeit dieses Vorgangs liegt auf der Hand. Gängige Konstrukte der Bourne-Shell sind nicht nur nicht implementiert, ihre Verwendung kann zur Ausführung von Dateiinhalten führen, die niemals als Shellskript vorgesehen waren.
> Diese potentielle Gefahr ist beseitigt ab Version
3.40, obwohl deren Wahrscheinlichkeit extrem gering ist.
> Außerdem: die Doku benennt und benannte
solche Konstruktionen im interaktiven Modus explizit als problematisch.
> Eine Bearbeitung dieser Multizeilen-Konstruktionen
bei Eingabe im interaktiven Modus ist schlicht nicht implementiert.
Eines der wichtigsten Mittel der Shellprogrammierung ist die Pipe, ein Kommunikationskanal, der sich an beiden Enden als Datei präsentiert. Was in das eine Ende der Pipe geschrieben wird, wird am anderen Ende gelesen, wobei das Lesen und u.U. auch das Schreiben blockiert wird, bis die entsprechende Aktion auf der anderen Seite stattfindet. Eine Pipe wird laut POSIX-Standards mit dem Systemaufruf pipe() erstellt, sie kann in der Shell mittels write_cmd | read_cmd zum Einsatz kommen. Das syntaktische Konstrukt heißt Pipeline.
Die »bsh« belegt dieselbe Syntax mit einer anderen Semantik. Statt der Pipe werden reguläre Dateien verwendet, deren Inhalt von einem Programm an das nächste weitergegeben wird; das entspricht in etwa
write_cmd > /tmp/$$; read_cmd < /tmp/$$in der Unix-Shell. Da Zugriffe auf eine solche Datei nicht blockieren, muß »bsh« mit dem Starten jeden Gliedes der Pipeline so lange warten, bis der vorhergehende Prozeß beendet ist. Das führt zunächst dazu, daß der Vorgang durch den Verlust der Parallelität langsamer abläuft; ferner müssen die Daten, die durch eine echte Pipe transparent laufen, hier im Dateisystem abgelegt werden, was leicht zu Platzproblemen führen kann.
Anders als bei einer echten Pipe muß zudem jeder Prozeß von selbst terminieren, damit es nicht zu einer Blockadesituation kommt. Das heißt, daß eine Befehlsfolge wie
tail -f /var/log/messages | egrep 'warning|error|fatal|panic'zum überwachen einer Logdatei mit der »bsh« nicht verwendbar ist.
>Flexibles und ausbaubares Monitoring mit bsh:
>size=0 offs=0 st=100 >while sleep -m $st; true >do > fstat -sv size $file > [ size -eq offs ] && st=500 continue > catv $offs,$((size-offs)),0 =Data: < $file > offs=$size > print -rn "$Data" >done
Viele Unix-Utilities prüfen, ob ihre Ein- oder Ausgabe mit
einer Pipe verbunden ist und passen sich daran an. Das ist erwünscht,
da sich eine Pipe in Details anders verhält als eine reguläre
Datei. So ist es nicht möglich, die Position des nächsten Zugriffs
zu ändern; Daten werden beim Schreiben ans Ende angehängt und
stets von vorne gelesen.
Zudem sind Schreibzugriffe in eine Pipe bis zu einer gewissen Größe atomic, das System garantiert also, daß eine bestimmte Datenmenge in einem Zug geschrieben wird. Das ist z.B. relevant, wenn mehrere Prozesse zeilenweise in eine Pipe schreiben, weil so garantiert werden kann, daß eine einzelne Zeile immer aus einer einzigen Quelle stammt. Bei der Simulation einer Pipe mittels regulärer Dateien ist das nicht der Fall.
> Doch, zumindest ist das herstellbar, weil ein einzelner write()-Aufruf in diesem SInne atomic ist.
Wenn eine Pipe aus irgendwelchen Gründen nicht in Frage kommt, kann man in der Unix-Shell von Hand reguläre Dateien anlegen. Daher ist die Simulation von Pipes in der »bsh« ein minderwertiges Verfahren, das die Shellprogrammierung einer ihrer wesentlichen Möglichkeiten beraubt.
> Die bsh-Pipelines arbeiten mit temporären Dateien, genau: mit seek-baren, > verschachtelten Dateiendabschnitten, nicht mit der Funktion pipe(). > Das hat mehr Vorteile als pipe() Vorteile hat: > o Funktioniert mit allen Betriebssystemen. > o Man erhält eine temporäre Datei 'on the fly'. > o Diese Datei kann mittels 'seek' mehrfach gelesen werden. > o Es gibt keine (Lese-)Probleme mit Kommandos, die bei > 'echten' pipe()s versagen. > (Kommandos, die keine ausdrücklichen Filterkommandos sind.) > o Die Prozesse werden nacheinander gestartet, > o sie können sich nicht gegenseitig stören, > o die momentane Prozeßlast ist geringer, > o der Exit ist von jedem in der Kette eindeutig erhältlich. > Vorteile von pipe(): > o Der Datenstrom darf beliebig groß sein. > o Müßte prinzipiell (meist) schneller arbeiten. > o Permanentes Monitoring ist möglich. > Es ist angedacht, per -U/+U und set -/+U 'echte' pipe()-Pipelines > schaltbar zu machen - natürlich nicht in der DOS-Version. > Grundsätzlich kann man in der bsh jede andere vorhande Shell > aufrufen, falls man deren Spezifika mal benötigt.> Die bsh-Datei-Pipes sind nicht minderwertig - sie sind lediglich anders.
> Demnach dürfte ab sofort weltweit keinerlei
Software mehr verkauft werden und es keine ClosedSource geben, denn
sowas
> ist automatisch 'brandgefährlich'
und niemals ernsthaft verwendbar ... ?!
> Die weitaus meiste Software ist proprietär,
nicht kostenlos und ClosedSource!
> Freie OpenSource-Software ist mengenmäßig
die absolute Ausnahme.
> Das stimmt nur halbwegs:
> Jedes beliebige Shell-Script ist nur lauffähig,
wenn eine dazu passende Shell installiert ist.
> Keine neue Shell war sofort nach Erscheinen
auf allen Plattformen mitgeliefert oder vorinstalliert.
> Bei der modernsten mittlerweile verbreiteten
Shell, der ksh, hatte es bis zu 10 Jahre gedauert, bis sie weitgehend
> vorinstalliert war. Unter Linux ist sie bis
heute nicht vorinstalliert, ja ksh93 noch nicht einmal verfügbar.
> bsh gibt es kostenlos für alle wichtigen
Intel-x86-Plattformen, deren Exemplaranzahl bekanntlich immens ist.
> Die deutschen Texte erschweren den Einsatz
außerhalb des deutschen Sprachraumes, machen ihn aber keineswegs
unmöglich.
> Eine Verbreitung über das persönliche
Umfeld hinaus ist zwar nicht wahrscheinlich, jedoch durchaus möglich.
> Dem persönlichen Nutzen tut das keinen
Abbruch.
> Das stimmt überhaupt gar nicht.
> bsh ist mit ihren etwa 100 internen Kommandos
die mit Abstand leistungsfähigste Shell und funktioniert
> einwandfrei gemäß ihrer Dokumentation
und unübertroffen schnell zur Laufzeit.
In diesen Text flossen Beobachtungen von Jürgen Ilse, Jürgen
P. Meier und Matthias Andree ein. Das Konzept lehnt sich an "Csh Programming
Considered Harmful" von Tom Christiansen an. Jürgen Ilse stellt unter
<http://members.pop-hannover.de/~ilse/bsh-programming-harmful.html>
eine aktuelle HTML-Fassung dieses Dokumentes zur Verfügung.
Hier steht dieser Text auch Textdatei zur Verfügung:
bsh-programming-harmful.txt
Gunnar Ritter Version 1.3 01/08/18
> Gegendarstellung: Helmut Schellong, 22./23.08.2001