Die csh kam einige Jahre nach der Bourne-Shell (sh)
auf die Unix-Systeme und ist seit Jahrzehnten
die zweite der heute drei Unix-Standard-Shells: sh, csh, ksh.
Sie ist bei interaktivem Arbeiten wegen ihrer history- und alias-Funktionalitäten
wesentlich besser als sh,
hat jedoch beim Scripting tatsächlich einige heftige Nachteile und Fehler,
die teils schon im Konzept liegen.
Ich habe seit etwa 1989 Scripting-Erfahrungen mit den drei Unix-Standard-Shells
und den DOS-Shells gesammelt.
Diese Erfahrungen haben mich 1994 dazu motiviert, eine eigene Shell -diebsh-
zu entwickeln (ab 1995),
weil ich letztlich doch reichlich unzufrieden war mit den Möglichkeiten,
Leistungen und sonstigen Merkmalen
all dieser Shell-Programme, bei denen ich zudem auch (allerdings nur ein paar)
häßliche Fehler entdeckte.
Im unteren Fenster ist eine Datei sichtbar,
die einen repräsentativen Querschnitt aus über 5000
gesammelten, thematisch passenden Newsgroup-Artikeln zeigt, bestehend aus
etwa 100 Artikeln,
die Probleme bei der Shell-Programmierung aufzeigen und/oder Programmierhilfe
erbitten.
Unix Shell Programming Considered Harmful?:
Anhand dieser Artikel ist überdeutlich erkennbar, daß es ein wahrhaft
gigantisches, 119,120,121,122
nahezu unentwirrbares Durcheinander gibt, hinsichtlich Unterschieden bei:
Echte Bourne-Shell / Bourne-Shell-Kompatible / So-als-ob-Bourne-ShellIch bin jedenfalls zu folgender Erkenntnis gelangt: Unix Shell Programming Considered Sceptical
/bin/sh als Link auf ...
Plattform / Betriebssystem
BS-, Shell- und Tool-Versionen / -Varianten
Shell-Extensions per Option
Shell-Tools / Zugehörige Werkzeuge
Spezifische Optionen und Merkmale
Shell- und tool-relevante Manual-Dokumentationen
Shell-Standards / POSIX-Standards
Man kann für die Bourne-Shell große und größte Scripts
programmieren, die gut und sicher funktionieren
und zusätzlich portabel sind.
Aber, dies nur, wenn man sich dabei auf den kleinsten gemeinsamen Nenner einigt!
Das bedeutet, es muß so programmiert werden, wie vor 30 Jahren!:
Um diesen Mangel abzustellen, habe ich einen konsequenten Schnitt vorgenommenentweder: Anspruchslos, simpel und klein. oder aber: Umständlich, aufgeblasen, unübersichtlich und langwierig. Oft mit aberwitzigen, krampfhaften Not-Konstruktionen. Unter Zuhilfenahme sehr vieler externer Werkzeuge. Mit Erzeugung sehr vieler neuer Prozesse (fork()). Ressourcenverschlingend und sehr, sehr laufzeitlangsam.
Die Größen der statisch
gelinkten Executables ca.: 120, 130, 170, 200, 220, 340 KB
(Je nach BS und Variante.)
Das sind angesichts der enormen Anzahl von Buildins vorzügliche Werte.
Die Arbeitsgeschwindigkeit ist im Vergleich extrem gut.
Sie erreicht manchmal sogar das Tempo des kompilierenden(!) perl-Interpreters
[1] (der keine Shell ist).
Nachfolgend wurde die Geschwindigkeit der 'internen Maschine' der Shells
gemessen:
Oben sind als Besonderheit die sehr schlechten Werte der sh auffallend.Test-Quellen
=========================================================================
T A B E L L E über Arbeitstempo und zugehörige Zeitfaktoren
=========================================================================
bsh ************************************************************
ksh *******************************************
zsh *****
bash ***
csh **
4dos *
sh -
-------------------------------------------------------------------------
Script bsh ksh zsh bash csh sh 4dos.com
-------------------------------------------------------------------------
loop 1 1.11 11.4 19.4 39.0 205. 37.2 u+s
loop 1 1.07 9.1 19.3 30.6 33.9 27.0 u
s70 1 1.64 12.9 ---- 29.3 265. 52.2 u+s
s70 1 1.64 12.7 ---- 29.1 51.8 47.2 u
-------------------------------------------------------------------------
======================================================================
Mit Ausnutzung der bsh-Buildins:
======================================================================
bsh ************************************************************
ksh ***
zsh -
bash -
csh -
4dos -
sh - ('-': nicht mehr darstellbar)
----------------------------------------------------------------------
bsh -E |
#bsh:K |
#!/usr/bin/perl |
[1] perl ist ein Interpreter, den ich wegen
seiner Mächtigkeit und Leistung bewundere.
Seine Syntax ist allerdings oft implizit, knapp und kryptisch.
Beispielsweise sind Funktionsaufrufe
innerhalb (!) von Regulären Ausdrücken möglich
und üblich.
An anderen Stellen ist die Syntax wiederum recht umständlich
- man muß viel schreiben.
Es fehlt eine harmonische Gleichstimmung, ein roter Faden
(ähnl. bei 4dos.com), so als ob
der Autor nach jeweils langen Pausen mit immer wieder anderem
Syntax-Gefühl entworfen hätte.
Und über perl wird nachhaltig berichtet, daß
er Speicher-Lecks erzeugt!
Desweiteren ist er natürlich ressourcen-hungrig.
Ich hatte deshalb nie richtig Lust, mich mit perl
intensiver zu beschäftigen.
Die unten gezeigte bsh-Funktion ist ein Grenzfall, ein Scheidepunkt.
Bei intensivem Einsatz sollte sie nicht mehr als bsh-Funktion verwendet
werden, denn sie benötigt
etwa 0.3 Sekunden pro KByte Datenmenge.
Dennoch ist das relativ schnell, da jedes Bit aufwendig einzeln bearbeitet
wird.
# SLE<-- Buf $offs $len |
Die Größe von Scripten und Syntax-Konstruktionen
darf vom bsh-Konzept her beliebig sein!
Das Limit kommt vom Betriebs-/Datei-System, nicht von
der bsh.
bsh64 UnixWare7/OpenUnix8 hat hier ein Limit
von 2^63-1 Byte.
Ich habe bsh auch auf ein Embedded-Multitasking-DOS auf Basis 80186-Prozessor 20 MHz portiert.
Es handelt sich um den Beck@IPC SC12-Chip, kleiner als eine Streichholzschachtel,
mit Speicher-Ressourcen, die jeweils 'nur' bei etwa 200 KB netto liegen.
Es wurden dazu die Kommandos com,ext,sem und eine eigene Handle-Verwaltung zusätzlich implementiert.
bsh.exe wurde auf etwa 50 KB komprimiert, mit einem Exe-Packer ähnlich PKLITE.Realisiert wurde ein Verbindungsmanager, der per Modem und Telefonnetz mehrere Hundert elektronische
Einheiten verwalten, steuern, überwachen und konfigurieren kann, von beliebigen Browser-Arbeitsplätzen aus.
Von den Anforderungen an das fertige Produkt her war dieses Projekt überhaupt nur mit bsh realisierbar!Ein weiterer Verbindungsmanager wurde realisiert, der eine mehrere tausendfach größere Datenbasis unterhält
und daher unter Unix mit Apache-WebServer und einer Unix-bsh realisiert wurde.
Dabei konnten große Script-Teile zu 97-100% unverändert übernommen werden!Und auf meinem gemieteten WebSpace läuft ebenfalls bsh -unter Linux- als alleiniger CGI-Interpreter
seit Jahren und bedient mein 1000-fach-WebCounter-System. Neuerdings auch mit Referrer-Listing.bsh ist, wie sie ist, war immer so, wie sie ist, wird immer so bleiben, wie sie ist.
(Ausnahme: neue, hinzugefügte Merkmale, die die alten nicht ändern.)
Ein schädliches Mammut-Durcheinander, wie oben angesprochen, gibt es nicht und wird es nie geben.
Datum, Uhrzeit, Dateizeit, Dateigröße: A B C D E F G H Isystime sec; echo $sec # dezimal
systime -t dati # JJJJMMTTssmm.ss
systime $sec # Setzen
ctime J M T st mi se $sec # Einzeln
tz -1 # Zeitzone
fstat -smv size mtime $File
fstat -mvT mTime $File # JJJJMMTTssmm.ss
fstat -shv size $Handle
fstat +m $sec $File # Setzen
# usw. usw. usw.Datei-Listings: A Blist [-fdoecpRF0] dir file ...
Die Optionen -fdo: file directory other
gestatten eine unmittelbare Selektion.
Option -F gestattet eine Selektion aus einem Wildcard-Resultat.
Eine störende Blocksumme und . .. werden nicht ausgegeben.
Option -0: '\0' als Zeilenende! (siehe auch readl)fstat [-|+FitfplugJNsamcnhTv] [name...|wert...] file...|handle...
prints [[v]format[-]] [vname] [arg ...]
ermöglichen ein beliebig ausführliches (formatiertes) Listing.sleep: A Bsleep $sec
sleep -m $millisecGlobale Handle-Verknüpfungen: A B C D E1.) exec ist (als Krücke) nicht notwendig.
2.) Eine vorherige Duplizierung ist nicht notwendig.
3.) Rückverknüpfung ist einfacher.
In der bsh ganz einfach so:
< file
...
><
Auch verschachtelt; das auch mit ein und demselben Handle.Zeilenorientierte Reguläre Ausdrücke: A B C Dbsh-BREs arbeiten mit einem terminierenden NULL-Zeichen;
Sonderzeichen sind per %t %r %n %z definierbar.
Das $ schaut über eine Folge \n bzw. \r\n hinweg.
Alle Zeichen 1...255 sind testbar.
[Zusammenarbeit von readl und expr]Dateinamen, die Zeilenvorschübe enthalten: manchmal ein Problem!sind identifizierbar und verarbeitbar!:
# list -p ../u/../u
../u/../u/cie
../u/../u/bsh
# _
Der redundante Vorsatz ../u/../u fehlt zu Anfang, wenn ein \n
in einem vorher gelisteten Dateinamen vorkam.
Noch besser ist Option -0 bei list und readl.
Dabei wird mit dem '\0'-Zeichen als Zeilenende gearbeitet.
Somit sind in Dateinamen alle Zeichen 1..255 verarbeitbar!Exit in Pipelines: Acmd1 | e=$? cmd2 | { cmd3; [ e -eq 0 ]; } || echo cmd1_fail
GetIDs mt $1 "$lz" | { nop && pop3 - $IP "$User" "$Pass"; }eval-Kommando: A Bgibt es auch in bsh, man braucht es aber in bsh kaum,
weil es massenhaft andere 'preiswertere' Möglichkeiten gibt.Upper case / Lower case: Aconv -u name1 name2 ... # arbeitet binär
catv name | tr '[a-z]' '[A-Z]' | catv =name:
expr "$var" ...... + '%U%1%L%2%E&'
# usw. usw.Externes dd in anderen Shells: A Bbsh: catv 1,0 =key:
catv 792,$((178*64*1024)),0 =1 <infile >extract.datDateinamen manipulieren: Aconv '-t _' datei1 datei2 ...Zahlenbasis: A Becho $((16#4f))
79
echo $((16#, 79))
4f
base -10 dez +16 hex
echo $dez : $hex
catv $offs,1,0 <$file | base -b +16 hex # binär, -b: byte
typeset
# usw. usw. usw.Manipulation Variableninhalt: A B Cecho $tnam
test01082001_0711.jpg
catv 6,2,tnam 4,2,tnam 8,,tnam =0,,tnam:
echo $tnam
08012001_0711.jpgvar="12.45-"
expr "$var" :var '^%([0-9.]%{1,}%)-$' '-%1'
echo $var
-12.45Veränderung von Dateizeilen: A B< datei
while readl line
do
catv '.#' line '/ -1000%n'
done
><
23ste Zeile löschen:
line +23-23 datei | cat >datei
line [ {-|+}a[-[e]] ] [ datei ... ]Pipes und stderr: A Bprint -u2 abc |2 catv =2
Tja, so einfach ist das mit bsh.Führende Nullen: An=1
prints sf03 $n
001
prints vsf05 n $n
echo $n
00001
prints [[v]format[-]] [vname] [arg ...]
format: [v]s[.][u[d]][-:][{ +}][fx|Fddd][feldlänge][{btn}]...Indirekte Zugriffe: AMessage() { local ca=variable$1; command ${{ca}; }
Message 1
Message 2Dateiinhalt binär --> Variable: Acatv $doffs,$max,0 =$voffs,,var: <dateiVariablenleere, -existenz und -test: Aifset VAR ...
ifdef VAR ...
usw. usw.a='='
[ = = $a ] && echo gleich
[ -z $a ] && nop
So etwas ist in bsh kein Fehler!
Nur erste Fundzeile mit grep + Broken Pipe: A B
grep -m1 ...
grep -m4 ...
Broken Pipe (SIGPIPE):
Dieses Problem kann es in bsh nicht geben.
Verschachteltes Sortieren: A
sortl -f2,1n -odatei datei
Mittels -r und -f2,1rn kann verschachtelt 'reverse'
sortiert werden.
350000 Symlinks schneller herstellen: A
Das bsh-interne 'link -s ...' ist schon mal etwa 10-fach schneller.
Durcheinander bei impliziten Shell-Subprozessen: A
In bsh gibt es gar keine impliziten Subshells!
Diverse Shell-Probleme - kein Problem für bsh: A B C D
readl Zeile [Z2 ...]
fstat +s ... Datei um 1 kürzen.
catv :-1,1,0 =C: <datei Eventuell vorher prüfen.
echo $((2910865710+2910865710))
5821731420 Mit bsh64-Varianten kein Problem.
Null-Zeichen in Variablen sind für bsh absolut gar kein Problem.
Es gibt da soviel Möglichkeiten, daß ich hier nichts extra nenne.
Logfile-Problem: A
<logfile
while readl Z
do
expr "$Z" :p '%<proto=%([^ ]%{1,}%)' || continue
expr "$Z" :r '%<rcvd=%([0-9]%{1,}%)' || continue
expr "$Z" :s '%<sent=%([0-9]%{1,}%)' || continue
conv -u p
expr "$P" :: "[rs]_$p" || P="$P r_$p s_$p"
let "r_$p+=r" "s_$p+=s"
done
><
for pname in $P; do echo $pname: ${{pname}}; done
Mit bsh sind solche Algorithmen plötzlich ganz einfach und übersichtlich;
und: 0 Subprozesse, 0 falscher Namespace, 10..50mal schneller.