* Thomas Michalka schrieb am 02.Mai.2003:
Ich möchte vorab nur bemerken, daß _mein_ Skript ganz ausgezeichnet funktioniert.
VORSICHT! Ich habe den thread nicht verfolgt, kann also durchaus sein, daß Dein Skript funktioniert, aber das kann man nicht durch einfaches probieren herausfinden. Es muß sichergestellt werden, daß Dein Skript immer so funktioniert, wie es soll, nicht nur manchmal. Das immer kann man aber nicht durch probieren testen. Häufig gemachte Fehler: - Ein Skript funktioniert zwar immer, wenn es soll, aber leider auch manchmal, wenn es nicht soll. - Ein Skript verhält sich im Feherfall, merkwürdig. - Ein Skript bekommt Schwierigkeiten bei Dateinamen, die ein Leerzeichen oder gar ein Zeilenumbruch im Namen haben. Wohlgemerkt, ich weiß nicht, ob es bei Deinem Skript der Fall ist.
Deshalb nehme ich Deinen Kommentar mal einfach als Beitrag zur ästhetischen Verbesserung, d.h. um das Skript eleganter (= meistens einfacher) zu machen, und das kann ja durchaus ebenso lehrreich sein.
Es ist immer lehrreich sich auf Jan und David einzulassen.
Ich bin schon ganz gespannt, wie meine persönlichen Fortschritte im bash-scripting sind, denn eigentlich wollte ich es vermeiden und stattdessen lieber Python verwenden.
Um bash wirst Du nicht herum kommen. Aber das eine schließt das andere nicht aus.
Aber ich sehe schon jetzt, daß zumindest für kleine Angelegenheiten - wenn keine komplexen Abläufe oder umfangreiche Textverarbeitung gefragt sind - bash-Skripte fast unausweichlich sind.
So ist es. Ich kenne Python nicht, kann mir aber gut vorstellen, daß es für umfangreiche Textverarbeitung Sinnvoll ist. Dafür verwende ich perl. Für andere umfangreiche, besonders Zeitkritische Angelegenheiten ist C das geeignetere. Oder auch C++
Jan Trippler schrieb:
Thomas, Deine Zeilen sind zu lang - die Lesbarkeit leidet deutlich!
Ja, das war mir klar, als ich vorübergehend den automatischen Zeilenumbruch auf 100 Zeichen erhöht habe. Der Grund war, daß sonst mein Skript fast unlesbar geworden wäre. Leider war ich auch zu faul, um manuell <Enter> zu drücken nach ungefähr 70 - 80 Zeichen. Das werde ich jetzt beherzigen. Aber bei Skripten habe ich, ehrlich gesagt, nichts gegen eine Zeilenlänge bis 100 Zeichen. In normalem Text habe ich auch 70 - 80 Zeichen *viel* lieber.
Skripte kann man meist umbrechen, wenn das letzte, aber wirklich letzte Zeichen vor dem Zeilenumbruch ein \ ist. Insbesondere darf kein Leerzeichen mehr folgen. Natürlich darf sowas nicht mitten in einem Wort geschehen und auch nicht in irgend was gequotetem. Auf der Standardkonsole werden nur 80 Zeichen angezeigt.
tuts auch. awk ist dafür deutlich oversized und auch etwas ressourcenfressender. jan@k500:~/tmp> ls -l /bin/gawk /usr/bin/cut -rwxr-xr-x 1 root root 209420 Mär 25 2002 /bin/gawk -rwxr-xr-x 1 root root 18968 Mär 23 2002 /usr/bin/cut
Aber sei mal ehrlich, sollte mich das bei 1 GB Hauptspeicher wirklich jucken?
Bei einem einzelnen Skript, daß nur ab und an aufgerufen wird sicherlich nicht. Aber man sollte es sich zur Gewohnheit machen ressourcensparend zu programmieren. Spätestens wenn ein Teil in einer Schleife steckt, kann es eng werden.
Man könnte auch eine Konfigurationsdatei aufbauen, die den gleichen Aufbau wie der echo haben kann, und dann geht es einfach mit:
cat datei | while read devnum mpoint source fsname; do ...
Schaut auch recht schön aus. Für mich war es nur alles andere als selbstverständlich, daß read einmal von stdin und von einer Zeichenkette so liest, daß nach jedem Whitespace quasi neu begonnen wird mit dem Lesevorgang.
Nicht nach jedem Whitespace, sondern nach jedem Zeilenumbruch. Aber dann hast Du noch was ganz entscheidendes der bash noch nicht verstanden. read ließt von stdin, immer. Nur wurde hier stdin durch den | umgelenkt. Die Standardeingabe des Befehls nach dem | ist die Standardausgabe des Befehls vor dem | Jeder Befehl, der nach dem | steht und von stdin ließt, ließt an dieser Stelle die Standardausgabe des Befehls vor dem | Wenn Du ein Skript schreibst, und jemand lenkt die Standardeingabe um, sei es durch < oder durch einen | so ließt Dein Skript nicht mehr vom Bildschirm, sondern aus einer Datei oder aus einem anderen Befehl. Dafür brauchst Du Dich in Deinem Skript nicht anzustrengen, daß macht die shell für Dich. Allerdings gibt es eine Möglichkeit dies zu umgehen, wenn man nicht von der Standardeingabe ließt, sondern von /dev/tty, so wird immer von der kontrollierende Konsole gelesen. passwd macht das bei Paßworteingabe. Aber wehe, wenn man dann kein kontrollierendes Terminal hat. Dies ist bei Dämonen der Fall, oder bei Einträgen in der crontab oder in ip-up Wenn man /dev/tty verwendet, sollte man genau wissen, was man tut. Fast immer ist es richtig von der Standardeingabe zu lesen und dort hinein zu schreiben.
Ich habe mir 'man bash' natürlich auch angesehen, aber das Ding ist ja sooo lang, und nicht gerade didaktisch gegliedert (was wohl auch nicht beabsichtigt war), und da wußte ich als Bash-Unerfahrener noch nichts von 'read'.
Die manpages sind ganz allgemein nicht als Tutorial gedacht. Es ist ein Nachschlagewerk für Leute, die grundsetzlich den jeweiligen Befehl kennen. Ok, bei einfachen Befehlen kann man aus der man lernen, aber bei man bash sicherlich nicht.
Überhaupt hält die bash wohl noch viel überraschendes für mich bereit ...
Die bash ist immer für eine Überraschung gut.
# Is the file system already mounted? if [ 0 -eq $(mount | grep -c "\/dev\/hdb$devnum") ] ; then
David würden sich jetzt wieder die Fußnägel aufrollen ;-)
Ja. ;)
Wen meinst Du? Ich habe von keinem David in diesem Thread gelesen, oder ist das so ein Insider-Witz?
David Haller. Neben Jan derjenige, der immer um korrekte Skripts bemüht ist. An dieser Stelle mal einen dicken Dank an den beiden. Ich finde es enorm wichtig, daß der geneigte Newbie frühzeitig lernt korrekte Skripts zu schreiben und nicht irgendwelche irgendwie funktionierende. Warum habe ich schon weiter oben aufgeführt. Natürlich schreibe ich auch selber schon mal schlampige Skripts für den Moment. Aber ich bin mir dessen bewußt. Ich weiß, daß das Skript nicht für Dateinamen mit Umbrüchen drin funktioniert, aber wenn im Verzeichnis auf dem ich es loslasse, keine solche Dateien gibt, ist es ja gut. Vorrausgesetzt ich lösche das Skript anschließend wieder. Will ich ein solches Skript behalten, so muß ich mir manigfaltige Gedanken machen. Was ist, wenn ich einen Dateiname durch * abkürze und die shell ersetzt das nicht mit einem sondern mit zwei oder mehere Namen? Funktioniert mein Skript auch dann anständig. Was ist, wenn meine I-Nodes ausgegangen sind? Wie soll ich auf ein CTRL-C reagieren? Einfach beenden lassen, oder nicht doch lieber ein paar Aufräumarbeiten machen. Was ist, wenn der aufrufende User den Pfad total verändert hat, oder ...
if ! mount | grep -q /dev/hdb$devnum; then
Du meine Güte, es geht wohl immer noch irgendwie einfacher? Aber ich habe nun mal nicht die Zeit, immer noch etwas päpstlicher als der Papst zu sein ;-)
Dahinter steckt aber wieder mal das allgemeine Unverständnis einer if-Entscheidung. Zwischen if und then, gehört ein beliebiger Befehl, besser gesagt Befehlsliste. Wenn diese den Exitcode 0 hat, so wird der then-Teil ausgeführt. Wenn diese Befehlsliste einen Exitcode ungleich 0 hat, so wird, falls vorhanden, der else-Teil ausgeführt. Der häufigst gewählte Befehl hinter einem if ist test. [...] ist ein Synonym für test und nicht etwa ein Teil der bash-Syntax. Wenn Du [...] sagst, so rufst Du genauso einen Befehl auf, als ob Du mount oder grep sagst. Wichtig ist zu verstehen, daß auch grep, wie jeder andere Befehl auch, einen Exitcode hat. Der ist 0 falls es eine Übereinstimmung gab, 1 falls es keinen gab und 2 falls es einen Syntaxfehler gab. Letzteres sollte in einem Skript nicht vorkommen. Und auf diesen Exitcode hin testet if
Habe ich zuerst auch versucht, aber aus mir unerfindlichen Gründen bekam ich eine Meldung, wonach das Device schon gemountet sei, obwohl das *definitiv* nicht der Fall war. Das konnte ich reproduzieren, aber mir ist bis heute schleierhaft, was die Ursache ist. Leider habe ich gerade nicht genug Zeit, dem auf den Grund zu gehen.
Vielleicht war der Mountpoint schon gemoutet?
und ich würde den Status abfragen! if ! mount /dev/hdb$devnum $MP_DIR/$mpoint; then echo Fehler beim mount exit 1 fi
Ist natürlich viel sauberer. Aber wenn das Gerät schon gemountet ist, ergibt 'echo $?' -> 32. In dem Fall soll das Skript weitermachen. Deshalb ist Deine Lösung hier auch etwas zu einfach. (Keine Angst, damit komme ich klar :-) )
Das wäre dann einer der ganz seltenen Fälle, wo man $? tatsächlich braucht. Meist reicht eine if-Abfrage oder noch einfacher || bzw. &&
Danke nochmals für die nützlichen Hinweise. Kannst Du mir vielleicht ein Buch über die Bash empfehlen? Ich habe da eher an ein Nachschlagewerk gedacht, als an ein klassisches Lehrbuch, was man von vorne bis hinten durcharbeiten muß. Ich brauche eigentlich auch keine Hinweise über das Programmieren als solches, eher schon weitergehende Tips über effizientes Scripting mit der bash. Und das wichtigste: Einen guten und ausführlichen Index sollte es haben.
Ich kann Dir leider keins nennen, aber schau Dich doch mal in einer Bücherei um. Es ist sowieso besser, wenn Du ein wenig in einem Buch blätterst, bevor Du es kaufst. Es muß vielleicht nicht explizit bash sein. ksh tut es auch, bash ist mehr oder weniger eine Obermenge von ksh und das wiederum eine Obremenge von sh Bernd -- ROTFL = Rolling On The Floor, Laughing = Auf dem Boden wälzen, lachend. SCNR = Sorry, Could Not Resist = Sorry, Ich konte nicht widerstehen. AFAIK = As Far As I Know = So weit ich weis|BTW = By The Way = Nebenbei bemerkt IMHO = In My Humble Opinion = meiner bescheidenen Meinung nach |Zufallssig. 9