Datei Zeilenweise auslesen
![](https://seccdn.libravatar.org/avatar/0d5a486c210a6d52dba8e8e9caee95e4.jpg?s=120&d=mm&r=g)
Hallo erstmal. Für die eingefleischten Linuxianer hier wird das sicherlich eine Lachnummer sein, ich komme da aber momentan nicht weiter. Deshalb frag ich hier mal an. Gegeben sei eine Liste mit e-Mail Empfängern im reinen ASCII Format, jede Zeile ein Empfänger. Desweiteren eine oder mehrere Dateien, die uuencoded an die Liste der Empfänger verschickt werden sollen. Die Empfängerliste heisst sinnigerweise 'empfaenger.txt' und liegt im selben Verzeichnis, in dem auch die zu versendenden Dateien sind. Den Teil mit dem uuencoden und verschicken an _einen_ Empfänger hab' ich ja schon fertig. ;-) Aber das zeilenweise Abarbeiten der Empfängerliste, da komm ich nicht weiter. Wie stellt man das am besten an? Das Problem scheint 'read' zu sein, der aus irgendwelchen Gründen nicht so recht aus der Datei lesen will. Der 'echo' Befehl zum debuggen meldet mir immer nur 'empty bekommt <Dateiname>'. Also wird $ADDRESSE zwar ausgelesen, erhält aber nie den Wert, den 'read' ihr eigentlich hätte zuweisen sollen. Ich schick hier mal meinen bisherigen Teil des Scriptes: -----Begin----- #!/bin/sh # Verteiler - Versenden der Files aus einem Verzeichis # # Wichtige Parameter INBOUND="/tmp/distri/vertreter" SUBJECT="Automatische_Mitteilung" LISTE="./empfaenger.txt" ADDRESSE="empty" # Verwendete Programme UUENCODE="/usr/bin/uuencode" MAIL="/usr/bin/mail" LS="/bin/ls" # vvv--- In der Endfassung durch "/bin/rm" ersetzen!! RM="/bin/ls" TEST="/usr/bin/test" # Der Code cd $INBOUND while $TEST $ADDRESSE != EOF; do read $LISTE; if test $ADDRESSE = EOF ; then exit; fi for i in $($LS -I $LISTE); do echo "$ADDRESSE bekommt $i"; $UUENCODE $i $i | $MAIL -s $SUBJECT $ADDRESSE ; $RM $i; done done -----End----- mfg Günther Behrendsen -- ------------------------------------------------------------------- Petersen Buchimport GmbH Tel.: +49-40-71003-282 Meessen 10 Fax : +49-40-71003-281 22113 Oststeinbek www.petersen-buchimport.com e-mail: guenther.behrendsen@petersen-buchimport.com -------------------------------------------------------------------
![](https://seccdn.libravatar.org/avatar/4e9a8c604df1eb89f2b4a2cf588cc40b.jpg?s=120&d=mm&r=g)
Guenther Behrendsen wrote:
Hallo erstmal.
Für die eingefleischten Linuxianer hier wird das sicherlich eine Lachnummer sein, ich komme da aber momentan nicht weiter. Deshalb frag ich hier mal an.
Gegeben sei eine Liste mit e-Mail Empfängern im reinen ASCII Format, jede Zeile ein Empfänger. Desweiteren eine oder mehrere Dateien, die uuencoded an die Liste der Empfänger verschickt werden sollen. Die Empfängerliste heisst sinnigerweise 'empfaenger.txt' und liegt im selben Verzeichnis, in dem auch die zu versendenden Dateien sind.
Den Teil mit dem uuencoden und verschicken an _einen_ Empfänger hab' ich ja schon fertig. ;-) Aber das zeilenweise Abarbeiten der Empfängerliste, da komm ich nicht weiter. Wie stellt man das am besten an?
Das Problem scheint 'read' zu sein, der aus irgendwelchen Gründen nicht so recht aus der Datei lesen will. Der 'echo' Befehl zum debuggen meldet mir immer nur 'empty bekommt <Dateiname>'. Also wird $ADDRESSE zwar ausgelesen, erhält aber nie den Wert, den 'read' ihr eigentlich hätte zuweisen sollen.
Ich schick hier mal meinen bisherigen Teil des Scriptes:
-----Begin----- #!/bin/sh # Verteiler - Versenden der Files aus einem Verzeichis # # Wichtige Parameter INBOUND="/tmp/distri/vertreter" SUBJECT="Automatische_Mitteilung" LISTE="./empfaenger.txt" ADDRESSE="empty"
# Verwendete Programme UUENCODE="/usr/bin/uuencode" MAIL="/usr/bin/mail" LS="/bin/ls" # vvv--- In der Endfassung durch "/bin/rm" ersetzen!! RM="/bin/ls" TEST="/usr/bin/test"
# Der Code cd $INBOUND while $TEST $ADDRESSE != EOF; do read $LISTE; if test $ADDRESSE = EOF ; then exit; fi for i in $($LS -I $LISTE); do echo "$ADDRESSE bekommt $i"; $UUENCODE $i $i | $MAIL -s $SUBJECT $ADDRESSE ; $RM $i; done done -----End-----
hm, so ganz steig ich da nicht durch, was ist EOF soll das eine Variable oder ein text sein? Der Einfachkeit halber mal das Grundgerüst für read: while read p1 p2 do echo "Param1: $p1 , Param2: $p2" done < deine_datei So, read kann also auch mehrere Parameter trennen. Die Trennzeichen werden in der Shellvariablen IFS festgelegt. Das Dateiende erkennt read automatisch. Noch'n Tip: Du solltest (musst) alle Variablen die Text enthalten bei der Übergabe an ein Commando, quoten. Dein Code test $ADDRESSE = EOF geht in die Hose wenn $ADDRESSE leer ist oder ein Leerzeichen enthält. korrekt wäre: test "X$ADDRESSE" = XEOF oder besser test "X$ADDRESSE" = "XEOF" Das X verhindert, dass ADDRESSE leer ist, die Quotes bewirken, dass test ADDRESSE als _ein_ Parameter behandelt wird. Das gilt für Textvariablen. Zahlen checkt man am besten, weil übersichtlicher und kompatibler via test 1234 -lt 5678 -lt = lower than -gt = greater than -eq = equal -ne = not equal usw. siehe man test Und das obligatorische man bash, man read, usw... darf natürlich nicht fehlen ;) so long... bernd
![](https://seccdn.libravatar.org/avatar/0d5a486c210a6d52dba8e8e9caee95e4.jpg?s=120&d=mm&r=g)
Bernd Obermayr schrieb:
so ganz steig ich da nicht durch, was ist EOF soll das eine Variable oder ein text sein?
EOF ist der letzte Eintrag in der Datei mit den Empfängeraddressen. Sozusagen als Ende Kennzeichen. Scheint bei 'read' aber nicht erforderlich zu sein.
Der Einfachkeit halber mal das Grundgerüst für read:
while read p1 p2 do echo "Param1: $p1 , Param2: $p2" done < deine_datei
Die letzte Zeile war der springende Punkt. 'read' muss hier die Eingabe aus einer Umleitung beziehen. Klar. Jetzt wo Du das schreibst. Danke, das war der entscheidende Hinweis.
Noch'n Tip: Du solltest (musst) alle Variablen die Text enthalten bei der Übergabe an ein Commando, quoten.
[Viel interessantes gelöscht] Das ist doch mal etwas ordentliches. Das wird sofort ausgedruckt und in Sichtweite aufgehängt. Danke für soviel Information.
Und das obligatorische man bash, man read, usw... darf natürlich nicht fehlen ;)
Was meinst Du, was ich den halben Nachmittag gemacht habe? 8-) mfg Günther Behrendsen -- ------------------------------------------------------------------- Petersen Buchimport GmbH Tel.: +49-40-71003-282 Meessen 10 Fax : +49-40-71003-281 22113 Oststeinbek www.petersen-buchimport.com e-mail: guenther.behrendsen@petersen-buchimport.com -------------------------------------------------------------------
![](https://seccdn.libravatar.org/avatar/735ea797d876adb026ae955e8adbf597.jpg?s=120&d=mm&r=g)
On Die, 03 Jul 2001 at 18:15 (+0200), Bernd Obermayr wrote: [60 Zeilen Fullquote entfernt] [...]
Noch'n Tip: Du solltest (musst) alle Variablen die Text enthalten bei der Übergabe an ein Commando, quoten.
solltest, nicht _musst_! Muss nur dann, wenn die Variable leer sein kann _und_ wenn das Kommando an der Stelle zwingend etwas erwartet _und_ wenn die Variable Leerzeichen enthalten kann, aber als ein Argument dienen soll: v="`ls *.txt`" # "", weil sonst in $v nur die erste Datei steht for i in $v; do ... done # kein "", weil die Dateien in $v Einzelargumente sind FINDOPT="-mtime +7" # "", weil sonst in $FINDOPT nur -mtime steht find / $FINDOPT -print # kein "", weil FINDOPT auch wegbleiben kann
test "X$ADDRESSE" = XEOF
oder besser
test "X$ADDRESSE" = "XEOF"
Das X verhindert, dass ADDRESSE leer ist, die Quotes bewirken, dass test ADDRESSE als _ein_ Parameter behandelt wird.
Das ist doppelt gemoppelt. test "$Variable" = "Wert" reicht völlig aus - auch bei leerer Variable. Du kannst problemlos leere Inhalte abfragen: test "$Variable" = "" && ... oder test -n "$VARIABLE" && ... oder test -z "$VARIABLE" || ... Jan
![](https://seccdn.libravatar.org/avatar/4e9a8c604df1eb89f2b4a2cf588cc40b.jpg?s=120&d=mm&r=g)
Jan Trippler wrote:
On Die, 03 Jul 2001 at 18:15 (+0200), Bernd Obermayr wrote: [60 Zeilen Fullquote entfernt] [...]
Noch'n Tip: Du solltest (musst) alle Variablen die Text enthalten bei der Übergabe an ein Commando, quoten.
solltest, nicht _musst_! Muss nur dann, wenn die Variable leer sein kann _und_ wenn das Kommando an der Stelle zwingend etwas erwartet _und_ wenn die Variable Leerzeichen enthalten kann, aber als ein Argument dienen soll:
v="`ls *.txt`" # "", weil sonst in $v nur die erste Datei steht
for i in $v; do ... done # kein "", weil die Dateien in $v Einzelargumente sind
FINDOPT="-mtime +7" # "", weil sonst in $FINDOPT nur -mtime steht
find / $FINDOPT -print # kein "", weil FINDOPT auch wegbleiben kann
test "X$ADDRESSE" = XEOF
oder besser
test "X$ADDRESSE" = "XEOF"
Das X verhindert, dass ADDRESSE leer ist, die Quotes bewirken, dass test ADDRESSE als _ein_ Parameter behandelt wird.
Das ist doppelt gemoppelt. test "$Variable" = "Wert" reicht völlig aus - auch bei leerer Variable. Du kannst problemlos leere Inhalte abfragen: test "$Variable" = "" && ... oder test -n "$VARIABLE" && ... oder test -z "$VARIABLE" || ...
jaajjjjeiin... Ich habe Shellprogrammierung mit SCO 3.0 gelernt, da gabs diese netten switches bei test nicht und test hat auf alle Faelle bei einer leeren Variable gemeckert. Was Du vorschlaegst ist "programmiertechnisch" sauber, ok, aber erfordert eben mehrere Schritte. Wenn ich weiss, dass $Var nicht leer sein darf, muss ich das testen, wenn $Var aber leer sein darf, ist test "X$Var" = "X" sauber, elegant... und laeuft auch noch mit SCO 3.0 ;) Es spricht nichts dagegen alles zu quoten, ausser den Dingen bei denen man explizit weiss, dass man einzelne Parameter braucht. Nach meiner Erfahrung spart das eine Menge Sucharbeit. just my 10c so long... bernd
![](https://seccdn.libravatar.org/avatar/735ea797d876adb026ae955e8adbf597.jpg?s=120&d=mm&r=g)
On Die, 03 Jul 2001 at 23:10 (+0200), Bernd Obermayr wrote:
Jan Trippler wrote: [...]
test "$Variable" = "" && ... oder test -n "$VARIABLE" && ... oder test -z "$VARIABLE" || ...
jaajjjjeiin...
Ich habe Shellprogrammierung mit SCO 3.0 gelernt, da gabs diese netten switches bei test nicht und test hat auf alle Faelle bei einer leeren Variable gemeckert.
Oje, so alt? ;-) Ich weiss nicht, ob man da die Kompatibilität nicht ein wenig zu weit treibt. Bei allen *nixen, die mir in den letzten Jahren über den Weg gelaufen sind, funktioniert das (mindestens die erste Variante).
Was Du vorschlaegst ist "programmiertechnisch" sauber, ok, aber erfordert eben mehrere Schritte.
Nö, die obigen test's machen alle das Gleiche wie Dein test auch.
Wenn ich weiss, dass $Var nicht leer sein darf, muss ich das testen, wenn $Var aber leer sein darf, ist test "X$Var" = "X" sauber, elegant... und laeuft auch noch mit SCO 3.0 ;)
Wie gesagt - Deine Version und die von mir oben genannten machen keinerlei Unterschied (mit Ausnahme von SCO 3.0 ;-)
Es spricht nichts dagegen alles zu quoten, ausser den Dingen bei denen man explizit weiss, dass man einzelne Parameter braucht. Nach meiner Erfahrung spart das eine Menge Sucharbeit.
ACK, mich hat nur das _muss_ gestört. Jan
![](https://seccdn.libravatar.org/avatar/1a1fdd4c61344a41238e1f95e9cfeece.jpg?s=120&d=mm&r=g)
Hallo Guenther, On Tuesday, 3. July 2001 17:47, Guenther Behrendsen wrote: [...]
Den Teil mit dem uuencoden und verschicken an _einen_ Empfänger hab' ich ja schon fertig. ;-) Aber das zeilenweise Abarbeiten der Empfängerliste, da komm ich nicht weiter. Wie stellt man das am besten an?
als Ansatz: #! /bin/bash while read adresse; do test "$adresse" != "EOF" && echo $adresse done < empfaenger.txt Gruß, Stephan -- Stephan Hakuli | mailto: stephan@hakuli.de | * GnuPG/PGP-Key * | callto: 01 71 - 651 89 43 | available, please | surfto: http://www.hakuli.de | visit my homepage
![](https://seccdn.libravatar.org/avatar/1462b00a7216f64e9d0c4976a1170402.jpg?s=120&d=mm&r=g)
Hi, schau Dir mal mpack an (ist leider nicht bei SuSE dabei). Damit geht das einfach. for rcpt in `cat $rcpts.text|xargs` do mpack -s Subject datafile $rcpt done oder als eine mail (dann stehen aber alle Empfänger im Header): mpack -s Subject datafile `cat $rcpts.text|xargs` Hier die Hilfe zu mpack: mpack version 1.5 usage: mpack [-s subj] [-d file] [-m maxsize] [-c content-type] file address... mpack [-s subj] [-d file] [-m maxsize] [-c content-type] -o file file mpack [-s subj] [-d file] [-m maxsize] [-c content-type] -n groups file Wie man sieht, läßt sich sogar der Mime-Typ angeben (manchmal praktisch). -- _, Regards, (_ ,_)ven Hansen. +----------------------------------------------------------+ | Sven Hansen Celo Communications GmbH | | Dipl.-Chem. a Gemplus Company | | Senior Software Engineer Weissenfelser Strasse 46a | | mailto:Sven.Hansen@gemplus.com D-06217 Merseburg | | http://www.gemplus.com/ | | Phone: +49 (0)3461/3318-24 Fax: +49 (0)3461/415072 | +----------------------------------------------------------+ Unix _IS_ user friendly - it's just selective about who its friends are !
![](https://seccdn.libravatar.org/avatar/1462b00a7216f64e9d0c4976a1170402.jpg?s=120&d=mm&r=g)
Sven Hansen wrote:
Hi, schau Dir mal mpack an (ist leider nicht bei SuSE dabei). Damit geht das einfach.
for rcpt in `cat $rcpts.text|xargs` do mpack -s Subject datafile $rcpt done
oder als eine mail (dann stehen aber alle Empfänger im Header):
mpack -s Subject datafile `cat $rcpts.text|xargs`
Sorry, die '$'-Zeichen vor rcpts.text müssen weg. -- _, Regards, (_ ,_)ven Hansen. +----------------------------------------------------------+ | Sven Hansen Celo Communications GmbH | | Dipl.-Chem. a Gemplus Company | | Senior Software Engineer Weissenfelser Strasse 46a | | mailto:Sven.Hansen@gemplus.com D-06217 Merseburg | | http://www.gemplus.com/ | | Phone: +49 (0)3461/3318-24 Fax: +49 (0)3461/415072 | +----------------------------------------------------------+ Unix _IS_ user friendly - it's just selective about who its friends are !
![](https://seccdn.libravatar.org/avatar/735ea797d876adb026ae955e8adbf597.jpg?s=120&d=mm&r=g)
On Die, 03 Jul 2001 at 18:46 (+0200), Sven Hansen wrote: [...]
for rcpt in `cat $rcpts.text|xargs` ^^^^^
Was hat das xargs für einen Sinn? Ohne Argumente macht es doch einen echo, also Ausgabe nach stdout - und das macht der cat auch schon. Du leitest also per Pipe stdout von cat nach xargs um, welches das Argument nach stdout ausgibt. *useless use of xargs award* ;-) Jan
![](https://seccdn.libravatar.org/avatar/1462b00a7216f64e9d0c4976a1170402.jpg?s=120&d=mm&r=g)
Jan Trippler wrote:
On Die, 03 Jul 2001 at 18:46 (+0200), Sven Hansen wrote: [...]
for rcpt in `cat $rcpts.text|xargs` ^^^^^
Was hat das xargs für einen Sinn? Ohne Argumente macht es doch einen echo, also Ausgabe nach stdout - und das macht der cat auch schon. Du leitest also per Pipe stdout von cat nach xargs um, welches das Argument nach stdout ausgibt. *useless use of xargs award* ;-)
Das xargs packt die Werte in eine Zeile, ersetzt also das Zeilenende durch ein Leerzeichen. Ist in dem Falle aber wirklich überflüssig, da das for auch so ginge (gerade getestet). -- _, Regards, (_ ,_)ven Hansen. +----------------------------------------------------------+ | Sven Hansen Celo Communications GmbH | | Dipl.-Chem. a Gemplus Company | | Senior Software Engineer Weissenfelser Strasse 46a | | mailto:Sven.Hansen@gemplus.com D-06217 Merseburg | | http://www.gemplus.com/ | | Phone: +49 (0)3461/3318-24 Fax: +49 (0)3461/415072 | +----------------------------------------------------------+ Unix _IS_ user friendly - it's just selective about who its friends are !
![](https://seccdn.libravatar.org/avatar/735ea797d876adb026ae955e8adbf597.jpg?s=120&d=mm&r=g)
Hi Günther, On Die, 03 Jul 2001 at 17:47 (+0200), Guenther Behrendsen wrote: [Datei zeilenweise lesen]
-----Begin----- #!/bin/sh # Verteiler - Versenden der Files aus einem Verzeichis # # Wichtige Parameter INBOUND="/tmp/distri/vertreter" SUBJECT="Automatische_Mitteilung" LISTE="./empfaenger.txt" ADDRESSE="empty"
# Verwendete Programme UUENCODE="/usr/bin/uuencode" MAIL="/usr/bin/mail" LS="/bin/ls" # vvv--- In der Endfassung durch "/bin/rm" ersetzen!! RM="/bin/ls" TEST="/usr/bin/test"
TEST ist unnötig, das ist ein Shell-Builtin; /usr/bin/test gibts AFAIK nur aus Kompatibilitätsgründen.
# Der Code cd $INBOUND while $TEST $ADDRESSE != EOF; do read $LISTE; if test $ADDRESSE = EOF ; then exit; fi for i in $($LS -I $LISTE); do echo "$ADDRESSE bekommt $i"; $UUENCODE $i $i | $MAIL -s $SUBJECT $ADDRESSE ; $RM $i; done done
Zuerst mal: Das Semikolon am Zeilenende ist in der Shell unnötig.
Dein read liest von stdin, wenn er eine andere Datei lesen soll,
dann musst Du die Eingabe mit < umleiten. Den Dateiende-Schalter EOF
kenne ich in der Shell nicht.
Die Syntax für read lautet:
read variable
wobei dann in variable der Inhalt steht.
Der rm ist IMHO an der falschen Stelle, die Datei wird ja schon beim
ersten Mail-Versand gelöscht. Der erste Empfänger kriegt alle
Mails, der zweite schon keine mehr.
Ich würde das so machen:
participants (5)
-
Bernd Obermayr
-
Guenther Behrendsen
-
Jan.Trippler@t-online.de
-
Stephan Hakuli
-
Sven Hansen