Mailinglist Archive: opensuse-de (4684 mails)

< Previous Next >
Re: bash: mehrface for-Schleife
  • From: Thomas Michalka <Thomas.Michalka@xxxxxx>
  • Date: Fri, 02 May 2003 17:09:17 +0200
  • Message-id: <3EB28A1D.7080307@xxxxxx>
Hallo,

danke für den Kommentar auf mein Skript!
Hätte ich gar nicht erwartet ...

Ich möchte vorab nur bemerken, daß _mein_ Skript ganz ausgezeichnet
funktioniert. 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. 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.
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.

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.

On Son, 27 Apr 2003 at 21:48 (+0200), Thomas Michalka wrote:

Manfred Tremmel schrieb:
> Sorry, 2. Versuch, die erste Mail war noch nicht fertig ...
>
> Am Samstag, 26. April 2003 13:59 schrieb Thomas Michalka:
>
> [...]
> Also wenn die Werte zusammengehören und Du die auch in eine Variable
> legen kannst, tuts vielleicht ein:
>
> VAR="A|0|Z B|1|Y C|2|X D|3|W E|4|V F|5|U"
>
> for param in $VAR ; do
> parm_v=`echo $param | awk -F \| '{print $1}'`
> parm_n=`echo $param | awk -F \| '{print $2}'`
> parm_t=`echo $param | awk -F \| '{print $3}'`
> echo $param_v $param_n $param_t
> done

Ich würde dafür nur keinen awk nehmen, ein einfacher
cut -f1 -d\|

Ganz gut, das habe ich anläßlich eines anderen Skripts erst
danach herausgefunden.

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?


awk '{print $'$position'}' # hier darf außer zw. 'print' und '$' KEIN Leerraum
enthalten sein!!!


Unsinn, wo hast Du das denn her?
jan@k500:~/tmp> pos=2
jan@k500:~/tmp> echo "1 2 3" | awk ' { print $'$pos' } '
2

Lediglich das Konstrukt $'$pos' muss zusammen geschrieben werden.

So ist es! Eigentlich wollte ich mich nur auf das Statement
innnerhalb der Klammer beziehen, aber ich habe das nicht
korrekt ausgedrückt.

BTW:
jan@k500:~/tmp> echo "1 2 3" | cut -f$pos -d" "
2

funktioniert genauso gut.

Auch sehr schön!

[...]

# The mount point directory
MP_DIR=/mnt

#
------------------------------------------------------------------------
POS_NUM=" 1 2 3 4 5 6 7 8 9"
#
------------------------------------------------------------------------
DEV_NUM=" 2 5 6 7 8 9 10 11 12"
MPT_LST=" 02 05 06 07 08 09 10 11 12"
SRC_LST=" /boot / /root /tmp /opt /usr /usr/local /var
/home"
NME_LST=" BOOT_FS ROOT_FS ADMIN_FS TMP_FS OPT_FS USR_FS USRLOCAL_FS VAR_FS
HOME_FS"


# Let's sync the filesystems now!
for position in $POS_NUM ; do

devnum=$(echo -n $DEV_NUM | awk '{print $'$position'}')
mpoint=$(echo -n $MPT_LST | awk '{print $'$position'}')
source=$(echo -n $SRC_LST | awk '{print $'$position'}')
fsname=$(echo -n $NME_LST | awk '{print $'$position'}')


Finde ich ziemlich umständlich, jetzt wo ich sehe, was Du damit
machen willst. Wie wäre es so:

echo "2 02 /boot BOOT_FS
5 05 / ROOT_FS
6 06 /tmp TMP_FS" |\
while read devnum mpoint source fsname; do
...
done

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.
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'.
Überhaupt hält die bash wohl noch viel überraschendes für mich bereit ...


# 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 ;-)

Wen meinst Du? Ich habe von keinem David in diesem Thread gelesen, oder
ist das so ein Insider-Witz?

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 ;-)


mount /dev/hdb$devnum $MP_DIR/$mpoint &
PID_MOUNT=$!
wait $PID_MOUNT 2> /dev/null


Was hat das für einen Sinn? Du schickst den Prozess in den
Hintergrund und anschließend wartest Du doch auf ihn. Warum dann
nicht gleich
mount /dev/hdb$devnum $MP_DIR/$mpoint

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.

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 :-) )

rsync $RSYNC_OPTS $source/ $MP_DIR/$mpoint/ &
PID_RSYNC=$!
wait $PID_RSYNC 2> /dev/null ; echo "done (process $PID_RSYNC)."


Auch hier wieder: Was hat es für einen Sinn, das Kommando in den
Hintergrund zu schicken, wenn Du doch auf die Beendigung wartest?

Das hier hat den historischen Grund, daß nach dem Start von rsync noch
andere Jobs parallel laufen sollten, aber sichergestellt werden mußte,
daß der nächste rsync-Job _nach_ dem vorherigen gestartet würde.
Die Teile zwischen PID_RSYNC=$! und dem wait-Kommando wurden gelöscht,
aber der Rest sollte erhalten bleiben, falls es sich wieder einmal anders
ergeben würde.

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.

Gruß,
Thomas


< Previous Next >