Sammlung von Kurzbeispielen

Auszüge aus Shell-Scripts für bsh

Hauptseite

CGI-Scripting mit der bsh

    catv 0,512,0 <\\.\C: ¦ tr '[\0-\31][\128-\255]' '[.*]'
    catv 512,512,0 <\\.\physicaldrive0 ¦ tr '[\0-\31][\128-\255]' '[.*]'

Das catv-Kommando liest hier den Bootblock von Laufwerk C: und den zweiten Sektor (Offset 512) der
ersten Festplatte.
Das tr-Kommando wandelt alle zur Ausgabe auf den Bildschirm problematischen Zeichen in einen '.' um.

Man kann also mit der bsh sämtliche Laufwerke und alle Festplatten binär lesen und schreiben.
Und zwar nicht nur mit dem oben gezeigten catv-Kommando.
Allerdings werden die speziellen Dateinamen  "\\.\L:"  nur unter WinNT anerkannt!

Bei den kostenlosen bsh-Versionen gibt es aber eine 2-GigaByte-Grenze,
jeweils vom Beginn der angegebenen Spezialdatei gerechnet;
der Blockmodus ( B< /dev/rhd00 ), mit dem man bis 1 TeraByte kommt,
ist nur in Vollversionen (Unix,bsh32) vorhanden.

    list -R c: ¦ sortl ¦ tee odatei ¦ wc
    list -R c: ¦ tr '[a-z][A-Z]' '[A-Z][a-z]' ¦ sortl ¦
    tr '[A-Z][a-z]' '[a-z][A-Z]' > odatei

Das list-Kommando listet rekursiv Laufwerk c: auf, sortl sortiert, tee schreibt alles in odatei und
gleichzeitig weiter in eine Pipe zum wc-Kommando, das Zeichen, Worte, Zeilen zählt.

Beim zweiten Beispiel wird die Sortierreihenfolge geändert, mit Hilfe des tr-Kommandos.

Das interne sortl kann mehr als die externen sort-Kommandos (Ausnahme: sort unter Unix).

    time to 50 repeat; do sort <datei.txt >NUL; done
    time to 50 repeat; do sortl -oNUL datei.txt; done

Liefern die Zeitdauern 18 Sekunden und 6 Sekunden bei einer 200KB-Datei und Celeron366 unter WinNT.
Das interne sortl ist hier also 3mal schneller, obwohl es komplexer ist und mehr kann.

Man beachte, daß man bei (solchen) Zeitmessungen eine Ausgabe auf den Bildschirm verhindern muß
und nicht mit Pipes (¦) arbeiten sollte, weil diese Dinge viel Zeit verbrauchen und das Meßergebnis verfälschten.

GetIDs mt $1 "$lz" | { nop && pop3 - $IP "$User" "$Pass"; }
Der Exit-Wert des Kommandos GetIDs (in Wahrheit eine Shell-Funktion) wird durch && ausgewertet.
Das ist in dieser Form und in Verbindung mit Pipes nur mit der bsh möglich.
set Buf:a100000000
Setzt die Variable Buf mit 100 Millionen Zeichen 'a'.   (Ab bsh v4.01)
local buf:a1000
Gleiches für lokale Variablen.
    DIR \ ¦ grep -i '^  *[0-9][0-9,.]* bytes fre' ¦ read free rest
    conv -d,d. free

Diese beiden Zeilen liefern die Anzahl Bytes, die auf dem aktuellen Laufwerk noch frei sind.

Beim DIR-Kommando lautet die letzte Textzeile ja so oder ähnlich:

        43,171,860 Bytes free

Und genau diese Zeile wird vom grep-Kommando herausgefiltert.
Kommas oder Punkte werden zum Schluß vom conv-Kommando gelöscht.
Die Variable 'free' enthält letztlich:  43171860

    namen='aaa  bbb,ccc    ddd,eee'
    for n  in  $(ifs="$IFS";IFS=,)  $namen  $(IFS="$ifs")
    do
    echo "--$n--"
    done
    --aaa  bbb--
    --ccc ddd--
    --eee--

Dies ist ein Trick.   Es wurden IFS-Zuweisungen in Kommando-Substitutionen gepackt, die als
unmaskierte Argumente keinerlei Argument-Wirkung haben, weil Zuweisungen nun mal nichts
ausgeben auf die Standard-Ausgabe.
Die vorübergehende Änderung von IFS hat hier nur Wirkung auf  '$namen' .

    Fmain()  {
    case "$1" in $(shift)
    abc) ... ;;
    ...
    ...
    esac
    return 0
    }

Hier konnte eine Variable als Zwischenablage vermieden werden, da  $(shift)  als Argument zu 'case'
nicht in Erscheinung tritt!
Innerhalb des 'case' ist  '$1'  das zweite Funktions-Argument!

    expr "$Zeile" :Zeile %
    "%(<${s}[ %t].*${bgc}[ %t]*=[ %t]*%"#%)......%"" %
    "%1$rgb%"" ¦¦ continue

Mit diesem Aufruf des expr-Kommandos werden die Farbeinträge in einer html-Datei überschrieben.
(siehe Script 'colors.bsh')
Die Variablen 's', 'bgc' und 'rgb' sind wegen Automatisierung in einer Schleife vorhanden.
's' und 'bgc' stehen in {}, da sie sonst (zwischen "") als Arrays (wegen [...) interpretiert würden.
In 'rgb' befindet sich der neue Farbwert als 3 Hexadezimalwerte:  z.B.:  f9aa62

Zur besseren Übersicht:

<TABLE   BORDER=2 BGCOLOR =  "#FF00FF" >
t='[ %t]'
expr "$Zeile" :Zeile "%(<$s$t.*$bgc$t*=$t*%"#%)......%"" "%1$rgb%""
Ohne $t:
expr "$Zeile" :Zeile "%(<$s.*$bgc=%"#%)......%"" "%1$rgb%""
Ohne Variablen:
expr "$Zeile" :Zeile '%(<TABLE .*BGCOLOR="#%)......"' '%1F0F0FA"'
Ersetze dies durch dies

Das aktuelle expr-Kommando hat die neuen Optionen '=' (=::) und %U %L %E :

expr "$Zeile" =:Zeile  '%(<Table .*BGcolor="#%)......"'  '%1%UF0f0Fa"'

Für Abschaltung der Unterscheidung zwischen Groß- und Kleinschreibung,
und im Ersatztext zur Umwandlung  toUpperCase und  toLowerCase  und deren Abschaltung.

Man sieht hier auch, daß Reguläre Ausdrücke eigentlich doch nicht so schwer zu begreifen sind,
denn man beginnt ja mit   ''    oder    ""  ...

    bgrep -g 'http://' topatch_datei > pos
    : > urls
    3< topatch_datei
    < pos
    while readl num
    do
    catv $num,256,3 ¦ tr '\0[\1-\31][\128-\255]' '\10[ *]' ¦
    catv =url:
    expr "$url" :url '^%([^%n]*%)'
    expr "$url" :: ' ' && continue
    [ "$url" == "http://" ] && continue
    echo "$num $url" >> urls
    done
    ><<

Diese beiden Abschnitte dienen dazu, in einer binären Datei bestimmte Zeichenketten durch andere
zu ersetzen.  Und zwar hier: URLs, die mit  'http://'  beginnen.

Zuerst hat man nur die Byte-Positionen, wo solche Zeichenketten beginnen (bgrep; Datei 'pos').
In der Schleife werden die URLs geholt, umgewandelt und unerwünschte ausgeschieden,
bis zum Schluß das echo-Kommando in die Datei 'urls' die Position und den bereinigten URL schreibt.
In diese Datei kann dann als drittes Wort der jeweils gewünschte Ersatztext hinzugefügt werden.


Der nächste Abschnitt zeigt, wie der Ersatztext geschrieben (gepatcht) wird:

    3<> topatch_datei
    < urls
    while read num url new
    do
    ifset new ¦¦ continue
    echo "$num $url $new"
    catv new /%0 =$num,,3
    done
    ><<

Das echo-Kommando informiert hier lediglich.

Man beachte, daß das externe Kommando bgrep auch durch interne bsh-Kommandos ersetzt
werden kann!
Beispielsweise die Kommandos  catv, conv, cmpv  arbeiten binär!
das erkennt man (auch) daran, daß sie 'name' entgegennehmen und nicht (nur) '$name' .
Diese Kommandos wenden sich mit den Variablennamen direkt an den Variablen-Manager, der binär arbeitet.

    conv -t b name
    conv -d name

Ersetzt in der Variablen 'name' alle NUL-Zeichen (\000) durch 'b';
löscht alle NUL-Zeichen.
Dies funktioniert, weil der Argumentspeicher folgendermaßen aussieht:

    "conv\000-t\000b\000name\000"
    "conv\000-d\000name\000"

Dadurch wird eine Digit-Syntax  -d%000  eingespart, die nur wegen der Null da wäre;
alle anderen Zeichen kann man nämlich direkt oder per Variable den Optionen hinzufügen.

Die bsh arbeitet nur an wenigen Stellen mit null-terminierten Strings.

    fehler()  { echo "%n $0:  '$1'%n"; exit 1; }

    stop() { read "-? <Enter> "; }

Zwei kleine Shell-Funktionen.
Aufrufe:  fehler "meldetext" ; stop

    frage()  {
    while echo "%n$1 [jne]: %c"
    do
    read rest
    case "$rest" in
    [jJ]) return 0 ;;
    [nN]) return 1 ;;
    [eE]) exit 0 ;;
    *) continue ;;
    esac
    done
    return 2
    }

Diese Frage-Funktion wird erst verlassen, wenn man eine der Antworten  jJnNeE  eingibt.
Aufrufe:
frage "fragetext" && ja-komandos

if frage "fragetext"
then ...
else ...
fi

    while echo "%r%n
    Zu testendes Verzeichnis: '$1'

    %tListendatei zur Liegenschaft : l
    %tLiegenschaft zur Listendatei : a
    %tHinweise : ?
    %tDieses Menü verlassen : v
    %tBeenden : e

    %t : %c"
    do
    read kdo rest
    case "$kdo" in
    l) tst_lst_lieg $1 ;;
    a) tst_lieg_lst $1 ;;
    v) return 0 ;;
    e) exit 0 ;;
    %?) echoh Keine Hinweise. ;;
    *) echo %a%c ;;
    esac
    done

Beispiel für ein Menü.
Die Bedingung der while-Schleife (echo "..."  von 'while' bis 'do') ist immer TRUE.
Die Schleife wird nur durch Eingabe von 'e' oder 'v' verlassen.
Bei falschen Eingaben piepst es (echo %a).

    j=1970
    repeat
    do
    (( cjsj=0,
    corr= SPT*365 + (j%4==0&&j%100¦¦j%400==0 ? (++cjsj,SPT) : 0),
    sec<corr )) && break
    (( sec-=corr, ++j ))
    done

    m=1
    repeat
    do
    (( corr=MA[m] + (m==2&&cjsj ? SPT : 0), sec<corr )) && break
    (( sec-=corr, ++m ))
    done

Dies sind zwei Schleifen mit mathematischen Berechnungen.
Sie laufen ewig weiter, bis sie durch 'break' verlassen werden.
Das break-Kommando wird aktiv, wenn  'sec<corr'  zutrifft.

    ifset -E S_DIR BSHTEMP ¦¦ {
    echo Sie haben dieses Script nicht mittels start.bat gestartet
    echo oder es liegt ein unerwarteter Fehler vor.
    exit
    }

Dieses Kommando prüft, ob die Umgebungsvariablen S_DIR und BSHTEMP beide existieren
und einen Inhalt haben.
Es wird nur in der Umgebung nachgeschaut (-E).

    whence -ep mem ¦¦ [ $? -eq 10 ] &&
    mem /d ¦ grep -iq '[^a-zA-Z]ansi[^a-zA-Z]*' &&
    whence -ep mode ¦¦ [ $? -eq 10 ] &&
    mode con ¦ grep -q '[^0-9]25[^0-9]' &&
    mode con ¦ grep -q '[^0-9]80[^0-9]' &&
    R='%e[2C' S='%e[0;30;46m%e[2;3H'

Die Shell-Variablen  R und S  werden nur gesetzt, wenn die Kommandos  mem und mode  vorhanden sind
und der ansi-Treiber geladen ist und 25 Zeilen und 80 Spalten eingestellt sind.

    ifset R && PS1='print -nu2 "%e[s%r%e[53C%e[40;36m"; prints su2-26- $PWD
    print -nu2 "%e[u%e[40;37m$:%e[1m#%e[0m "'

Es wird ein sehr aufwendiges Prompt in die Prompt-Spezialvariable PS1='...' gespeichert.
Das funktioniert nur, wenn ein ansi-Treiber aktiv ist.
Der Inhalt von PS1 wird quasi wie ein Shell-Script behandelt und ausgeführt!

    echo STRINGTABLE PURE
    echo BEGIN
    N=1
    echo "$N, %"$#%""

    for FN in $*
    do
    ((++N))
    NAM=`expr $FN : '.*/%(..*%)%.'`
    expr $FN :: '..*mn[a-zA-Z]$' && {
    rc=`expr $FN : '..*mn%(.%)$'`
    conv -u rc
    NAM="$NAM($rc)"
    }
    echo "$N, %"$NAM%""
    ((++N))
    NZ=`wc -l $FN`
    echo "$N, %"$NZ%""
    done

    ((++N))
    for FN in $*
    do
    cat $FN ¦ rcstr -$N
    NZ=`wc -l $FN`
    ((N+=NZ))
    done

    echo END

Dies ist das Haupt-Script dafür, um automatisch die String-Ressourcen und einige Steuerdaten
für das Win32-Programm manw.exe  zu erzeugen.
Aufruf:  rcstrings.bsh $manfiles > manw.str

    mkofname()  {
    local dir="$1" n=0 t=$T name of
    conv -F\F/ dir
    expr "$dir" :name '%([^/\]%{1,%}%)$' ¦¦ return
    expr "$dir" :dir '^%(.*%)'"$name"'$' ¦¦ return
    conv -F\F/ dir
    expr "$name" :name '^%(%.*[^.]*%)' ¦¦ return
    ifset dir ¦¦ t=''
    of=$dir$t$name.$2
    conv -F\F/ of
    while [ -e "$of" ]
    do
    let "++n>9" && return 1
    of=$dir$t$(catv 7,name)$n$(catv 8,,name).$2
    conv -F\F/ of
    done
    $3=$of
    return 0
    }

Der Aufruf dieser Shell-Funktion:  mkofname $idatei erw odatei_variablen_name

Die Funktion erzeugt einen Dateinamen mit einer Erweiterung 'erw', der ansonsten aber gleich demjenigen
Dateinamen ist, der in $idatei steht.
Wenn gleichnamige Dateien schon existieren, wird folgendermaßen weiterprobiert:
ddddddd1.erw
ddddddd2.erw
ddddddd3.erw
...
ddddddd9.erw
Der neue Name ist dann per  $odatei_variablen_name  erreichbar.
Der Name  odatei_variablen_name  darf nicht  'local'  sein !

      #dos_unix
tr -d '\26' < $2 ¦ {
> $2
while readl Line
do catv Line /%n; done
><
}

#unix_dos
cat $2 ¦ {
> $2
while readl Line
do catv Line /%r%n; done
><
}

Hier werden Text-Dateien vom DOS- zum UNIX-Format umgewandelt und umgekehrt.
Der Name der Ursprungsdatei steht in  $2  .
Eines fällt hier auf:  Die Datei wird gelöscht (> $2), bevor die Schleife erreicht ist.
Ein Trick:  An der Stelle  '¦'  wird die Datei in die bsh-interne Pipe-Datei kopiert,
und aus dieser liest ja das  readl-Kommando!
Man spart sich also das Anlegen einer temporären Datei.

      mkofname $2 uc OutFile ¦¦ return
tr '[a-z]äöü' '[A-Z]ÄÖÜ' < $2 > $OutFile

Hier wird ein neuer Dateiname erzeugt  'dddddddd.uc'  und die Kleinbuchstaben der Datei  $2
werden in Großbuchstaben umgewandelt und dies alles in  $OutFile  geschrieben.
Das  tr-Kommando  ist ideal für solche Zwecke - es kann noch viel mehr.

      grep -i 'SRC="[^"]%{1,%}"' $2 ¦
while readl Line
do
expr "$Line" :Line '[Ss][Rr][Cc]="%([^"]%{1,%}%)"'
catv Line /%j >> $OutFile
done

Aus einer html-Datei werden alle Grafikdatei-Namen herausgesucht und nach  $OutFile  geschrieben.

      OutFile=binstr.acc
echo ":::$2:::" >> $OutFile
tr -cs '[a-z][A-Z][0-9]äöüßÄÖÜ_.-@/\\:' '[\10*]' < $2 ¦
grep '^[^%r%n]%{2,%}$' >> $OutFile

Aus einer Binär-Datei werden alle lesbaren Zeichenketten herausgefischt
und mit automatischer Zeilenbildung durch  tr  nach  $OutFile  geschrieben.
Das grep-Kommando dient dazu, Einzelzeichen zu unterdrücken.
-c  bewirkt, daß alle nichtangegebenen Zeichen in Zeilenvorschübe (\10) umgewandelt werden, und
-s  bewirkt, daß nicht mehrere Zeilenvorschübe hintereinander in der Ausgabe vorkommen können.

    < $file
    SS=`catv $((446+0+8)),4,0 $((446+0+12)),4,0 %
    $((446+16+8)),4,0 $((446+16+12)),4,0 %
    $((446+32+8)),4,0 $((446+32+12)),4,0 %
    $((446+48+8)),4,0 $((446+48+12)),4,0 %
    ¦ base -l +10`
    ><

Hier werden Daten aus der Partitionstabelle einer Festplatte gelesen und aufbereitet,
um anschließend die Daten in LBA-Werte (255 Köpfe) umzuwandeln.
Die Variable  SS  enthält hiernach die Daten in lesbarer Form, als Digit-Strings, durch Leerzeichen getrennt.

    ziel=checksum.txt
    echo "Prüfsummen- und Zeitstempel-Liste:" > $ziel
    date >> $ziel
    echo %n >> $ziel

    for wc in "*.exe" "*.zip" "*.Z" "*.bin" "*.drv" "*.bsh"
    do
    : $wc
    [ "$]" -eq 0 ] && continue
    for file in $wc
    do
    [ -s "$file" ] ¦¦ continue
    echo "$file"
    prints s16s17s17s3s `sum -b < "$file"`"(sum)" %
    `crc "$file"`"(crc)" %
    `fsize "$file"`"(size)" %
    "" "$file" >> $ziel
    done
    done

Dieser Ausschnitt produziert den ersten Teil der Datei  'checksum.txt', die auf meiner Homepage ist.

    vor00()  {
    let "${{#1}==2" && $1=0${{1}
    let "${{#1}==1" && $1=00${{1}
    let "${{#1}==0" && $1=000
    }

Ein Aufruf  vor00 Vname  fügt zum Inhalt der Shell-Variablen Vname 0 bis 3 führende Nullen '0' hinzu.
Vname darf nicht 'local' erzeugt, sondern muß eine globale Variable sein!
Hier wird indirekter Zugriff  ${{  angewendet.

    < $Script
    while seek + 0 GWpos; readl Zeile
    do expr "$Zeile" :: '^#@g ' && break; done
    catv $((GWpos+=4)),10,0 =Gsel:
    echo GruppenGWposition=$GWpos

Dieser erste Teil stellt diejenige Dateiposition (GWpos) fest, wo  #@g  am Zeilenanfang zuerst vorkommt.
In der Datei ($Script) sieht das so aus:  #@g --2-4---8-
catv
liest die 10 Zeichen --2-4---8- und schreibt sie in die Variable Gsel.

    echo Inhalts-Test G...
    inp=0
    seek $GWpos 0
    while readl Zeile
    do expr "$Zeile" :: '^#@G ' && { let ++inp; continue; }
    let inp!=0 && break
    done
    ><
    let "inp!=100" && { echo "$inp:Script-Inhalt ungültig!"; exit 1; }

Der zweite Teil geht auf GWposition und sucht ab da Zeilen mit  #@G  am Anfang.
Es müssen genau 100 solche Zeilen sein, und sie müssen ununterbrochen als Block vorhanden sein.

    Gwahl()  {
    local g=00
    Gsel=----------
    for g from 0 by 1 to 9 repeat
    do
    expr "-$1" :: "$g" ¦¦ continue
    catv g =$g,1,Gsel
    done
    catv Gsel =$GWpos,10,0 <> $Script
    return 0
    }

Aufruf:  Gwahl 6318
Effekt:  Gsel  enthält nach der Schleife  -1-3--6-8-

Und catv schreibt den neuen Inhalt von Gsel sogleich in die Datei $Script auf Position $GWpos.

    GcopyG()  {
    local grp="$1" g=0 n=0
    <> $Script
    for g from 0 by 1 to 9 repeat
    do
    expr "$grp" :: $g ¦¦ continue
    for n from 0 by 1 to 9 repeat
    do
    catv $((n*20)),20,CN =$((Gpos+g*260+n*26+4)),,0
    done
    done
    ><
    return 0
    }

Aufruf:  GcopyG 346

Die Variable CN enthält 10 Zeichenfolgen mit je 20 Zeichen.
Diese werden in 10 aufeinanderfolgende Zeilen in Datei $Script geschrieben:

    #@G ....................\r\n
    #@G ....................\r\n
    #@G ....................\r\n
    ...

Und zwar hier 3-mal, je einmal für  346 , in 3 verschiedene 10-Zeilen-Blöcke hinein.
Es werden nur die je 20 Punkte .....  überschrieben.
Die Zeilenlänge inklusive Zeilenvorschub ist 26 (4+20+2).
Es sind 100 solche Zeilen in der Datei ununterbrochen vorhanden, die hier als Speicherfläche
benutzt werden.

    ShowF()  {
    local nf=-001 rgb=000000000000 nl=-001 sel nam inp
    3<&0
    grep '^#@[Ff] ' $Script ¦ Fconv ¦ {
    seek + 0 Pos
    while :
    do
    nf=-1 nl=-1
    seek $Pos 0
    while read nam rgb
    do
    let ++nf
    ifset inp && [[ "$nam" != "$inp" ]] && continue
    let ++nl
    prints s5s-20s4s4s4 $nf: $nam $rgb
    let "nl>0&&nl%20==0" && {
    echo "... Weiter:<Enter> %c"
    read -u3 inp
    [ "$inp" == e ] && break 2
    [ "$inp" == s ] && { inp=; continue 2; }
    }
    done
    read -u3 inp
    [ "$inp" == e ] && break
    done
    } #hier wird Pipe-Handle 0 zurückverknüpft, mit der Tastatur.
    >< #und hier Handle 3 mit ...
    return 0
    }

Hier gibt es zwei Besonderheiten:

grep  liest Zeilen aus einer Datei und schickt sie per Handle 1 in eine Pipe, wo diese Daten durch
die Shell-Funktion  Fconv  konvertiert werden und in der Pipe-Kette weitergereicht werden.
Das read-Kommando liest per Handle 0 aus der Pipe-Datei.
Die Pipe-Datei wird hier als Parkplatz benutzt und kann immer wieder vom Datenstart an gelesen werden,
weil der Datenstartpunkt mittels  seek  abgesichert wurde.

Bevor die Pipe Handle 0 belegt, wird Handle 3 mit Handle 0 verknüpft, also der Tastatur,
damit mit  read -u3  von der Tastatur gelesen werden kann.
read inp </dev/console
read inp t<CON
wären auch möglich gewesen, aber obige Lösung ist eleganter und portabel.

CGI-Scripting

    ConvFormData()  {
    local h z
    conv -'t+ ' $1
    while expr "${{1}" :h '%%%([a-fA-F0-9]%{2%}%)'
    do
    base -16 h +b z
    expr "${{1}" :$1 '%%'$h += "$z"
    done
    return 0
    }

Aufruf:   ConvFormData varname

Diese Funktion dekodiert die Daten, die von einem Formular (SUBMIT) gesandt werden.
Alter und neuer Inhalt sind in der globalen Shell-Variablen namens 'varname' enthalten.


    for 2 x y  in  name "$name" strasse "$strasse" plz "$plz" %
    ort "$ort" email "$email" %
    znum "$znum" kenn1 "$kenn1" kenn2 "$kenn2" %
    url1 "$url1" url2 "$url2" url3 "$url3" %
    submit "$submit" hidd "$hidd" %
    bsovw "$bsovw" %
    Kennwo1 "$Kennwo1" Kennwo2 "$Kennwo2"
    do
    expr "$htmlF" :htmlF "~$x~" = "$y"
    done

    catv Thtml html1 htmlF htmlH html2 htmlE

HTML-Quelltext befindet sich in der Variablen 'htmlF', mit Zeichenfolgen wie z.B.  ~name~ .
Die Schleife ersetzt paarweise diese Zeichenfolgen mit den zugehörigen Variableninhalten.
Danach wird mit dem  catv-Kommando  der gesamte Quelltext zum Server geschickt, der ihn
über's Netz an den Browser sendet.


znummer zwert [kommentar]
znummer,zwert
von-bis zwert
                $nam="$val"
    [ "$nam" == znum ] && { CkSetDat $znum ¦¦ return 6
    Lock; catv $((znum*4000)),4000,3 =Data: 3<$dat
    }
    continue
    }
    expr "$Z" :val "^$f*%%($d%%)-%%($d%%)$t%%($d%%).*%$" %
    '%1 %2 %3' &¦
    expr "$Z" :val "^$f*%%($d%%)$t%%($d%%).*%$" '%1 %2' ¦¦
    continue
    for 3 von bis val in $val; do done
    ifset val ¦¦ val=$bis bis=$von
    let "val<0¦¦val>999999999" && return 7
    let "von<0¦¦bis<0¦¦von>999¦¦bis>999¦¦bis<von" && return 8
    base -10 val +L val
    for o from $von to $bis repeat
    do catv 4,val =$((o<<2)),4,Data; done
    done
    ifset znum kenn1 ¦¦ ErrExit "Keine Identifikation!(1)"
    GetKunDat ¦¦ ErrExit "Keine Identifikation!(2)"
    Lock; catv Data =$((znum*4000)),4000,3 3<>$dat
    return 0
    }

Eine vom Browser hochgeladene Datei mit Nutzdaten für die Dateien auf dem Server
wird ausgewertet.

Ein vollständiges Download-Script

    
    #!/usr/bin/bsh
    
    
    set -f
    
    deroot="$DOCUMENT_ROOT/de"
    expr "$deroot" :deroot '/de/de' '/de'
    
    arg="$QUERY_STRING"
    ok=0
    expr "$arg" :zn '^%([0-9]%{1,2%}%.[0-9]%{1,3%}%):.' && {
       expr "$arg" :nam ':%(..*%)$' ¦¦ nam=
       expr "$nam" =:nam '%%2f' += '/'
       expr "$nam" :dir '^%(.*/%)[^/]*$' ¦¦ dir=
       expr "$nam" :nam '%([^/]*%)$' ¦¦ nam=
       expr "$nam" :erw '%.%([^/.]%{1,%}%)$' ¦¦ erw=
       pre=fjgklidzfhgsehfrherk
       [ -s "$dir$pre$nam" ] && ok=1
    }
    
    [ ok -eq 0 ] && {
       echo "Content-type: text/plain%n"
       exit 0
    }
    
    HTTP_REFERER="$HTTP_REFERER::$dir$nam"
    export HTTP_REFERER
    
    extern icnt.cgi $zn.i0
    
    ifset erw ¦¦ erw=bin
    conv -l erw
    
    case "$erw" in
      shtml¦html¦htm¦php3)  ctyp=text/html ;;
      txt¦bsh¦pl¦text)      ctyp=text/plain ;;
      exe¦bin¦zip¦gz¦tar¦drv¦z¦obj¦o)
                            ctyp=application/octet-stream ;;
      gif)                  ctyp=image/gif ;;
      jpg¦jpeg)             ctyp=image/jpeg ;;
      *)                    ctyp=text/plain ;;
    esac
    
    systime Time
    cd "$deroot"
    set +f
    for lkn in *[0-9][0-9]_[0-9]*
    do
       expr "$lkn" :time '^%([0-9]%{8,10}%)_[0-9]%{1,}_' ¦¦ continue
       let "Time-time>400" && remove "$lkn"
    done
    set -f
    cd -
    
    http_lkn="${Time}_$$_$nam"
    lkn="$deroot/$http_lkn"
    
    [ -e "$lkn" ] && remove "$lkn"
    link "$dir$pre$nam" "$lkn"
    
    clen=0
    fstat -sv clen "$dir$pre$nam"
    
    Out="Content-Type: $ctyp
    Location: ../$http_lkn
    Content-Length: $clen
    From: webmaster@schellong.com
    
    "
    
    #catv Out 0 =1  < "$dir$pre$nam"
    catv Out
    
    exit 0
    

.

Das wahnsinnig universelle Kommando  catv


    <>datei
    ...
    catv /%1 =:-1,,0.
    ...
    ><

Überschreibt das letzte Datei-Byte (:-1) mit einer 1
und stellt den Dateipointer wieder auf den Ursprungswert zurück (.) .

    catv /%0%0 =$((zn2<<1)),,3  3<>$fnamo

Schreibt zwei Null-Bytes mitten in eine Datei.
Datei wird nötigenfalls bis zur Schreibstelle mit Nullen erweitert/aufgefüllt.

    let "sz<=zn1" && catv /%0 =$zn1,,3  3<>$kunflg

Schreibt ein Null-Byte ...

    catv $zn1,1,0 =v: <$kunflg ¦¦ err=1

Liest ein Byte von Handle 0 (Datei $kunflg) und schreibt es (binär) in Variable 'v'.
'v' wird danach auf Länge 1 gebracht (:).
Das ist nötig, wenn andere Kommandos ohne MAX-Option anschließend aus 'v' lesen sollen.

    catv 0 =0,,3:

Liest von Handle 0 und schreibt auf 3 ab Offset 0, mit festlegen der Dateigröße bzw. des Dateiendes
hinter die letzte Schreibstelle.

    catv $((zn2<<1)),2,0 =v:  <$fnamo

Liest maximal 2 Bytes ab Offset  2*zn2  von 0 und schreibt diese in Variable 'v'.

    catv 2,n =$((zn2<<1)),2,3  3<>$fnamo

Liest 2 Bytes aus Variable 'n' und schreibt sie in Datei '$fnamo'.

    ifset HTTP_REFERER && catv 99,z /%n =$v,100,3  3<>$fnams

Liest 99 Bytes aus 'z' und schreibt dies und 1 NewLine ab Offset '$v' in Datei '$fnams'.

    catv 0,1,v =f:

Hier sind Variablen Quelle und Ziel.  Environment-Variablen sind nicht zugreifbar mit catv!

    catv 0,$n,$v =${f}r:

Liest aus einer Variablen, deren Name in der Variablen 'v' steht, $n Bytes,
und schreibt in eine Variable, deren Name teilweise in der Variablen 'f' steht
und deren letzter Buchstabe ein 'r' ist.

    ((v=[zn1+1]*4000-1, sz<=v))  &&  catv /%0 =$v,1,3  3<>$dat

Falls die Datei $dat kleiner-gleich 7999 Byte ist (bei zn1==1),
wird ein Null-Byte auf eben diesen Offset geschrieben, wodurch die Datei 8000 Byte groß wird.

    catv $offs1,4000,3 =$offs1,4000,4  3<$dat  4<>$datb

Aus Datei $dat werden 4000 Bytes gelesen und in Datei $datb geschrieben, auf gleichen Offset.

    catv "/Content-type: image/gif%n%n" =0,,Z:

Schreibt eine MIME-Typ-Zeile in die Variable Z.

    catv /GIF89a%%$sz%0%%$((height+2*rahm))%0%128%0%0 =:,,Z

Schreibt die Kopfzeile einer GIF-Datei hinter das bisherige Ende der Variablen Z.

    catv $((zn1*4000)),4000,0 =DAT  <$dat ¦¦ catv / =4000,,DAT

Schreibt 4000 Bytes aus Datei $dat in Variable DAT.
Falls weniger als 4000 lesbar sind, wird DAT mit 4000 Nullen gefüllt.

    while catv $((++o)),1,DAT =1,v:

Liest einzelne Bytes aus der Variablen DAT, bis deren Inhalt komplett gelesen wurde.
(Bei Dateien braucht kein Offset explizit mitgeführt werden.)

    catv $length,0 ¦

Liest maximal $length Bytes von Handle 0 und schreibt diese in eine Pipe.

    catv url1 /%n url2 /%n url3 /%n > $urltxt

Schreibt drei Variableninhalte und jeweils ein NL in die Datei $urltxt.

Zurück zur Hauptseite