["gelöst"] Versenden von Dateianhängen per bash-Skript

Mornsgrans

Help-Desk
Teammitglied
Registriert
20 Apr. 2007
Beiträge
71.955
Eine Lösung habe ich dank oder trotz Gockel nicht gefunden. Entweder gingen die Antworten an der Fragestellung vorbei oder es gab unsaubere Workarounds, die nur in Spezialfällen (ohne Leerzeichen) funktionierten.

Beliebige variierende PDF-Dateien, die überwiegend Leerzeichen im Dateinamen enthalten, werden bei Rechnungserstellung in ein temporäres Verzeichnis geschrieben.
Ein bash-Skript soll diese Dateien im temp-Verzeichnis als Mailanhang an einen Empfänger verschicken, bevor diese wieder gelöscht werden.

Da einige unserer Kunden ZIP-Dateien als Anhang blockieren, müssen die PDF-Dateien einzeln an die Mail angehängt werden.
das Skript soll am Schluss via
Code:
...
echo kurzer Text|mutt -s "Rechnung xyz" user@domain.com -a blabla.pdf -a bla bla.pdf...
die Rechnung versenden.

Der Anweisungsteil "-a blabla.pdf -a bla bla.pdf" ändert sich bei jeder Rechnung, muss also in einer Variablen übergeben werden.
Die Crux sind die Leerzeichen im Dateinamen und dass die Dateinamen dynamisch hinzugefügt werden müssen.

Mein Gedankenansatz war gewesen, die Anweisung zum Versand der Mail als starren Befehl zu "bauen"
Code:
echo Anbei die Rechnung Ihrer letzten Bestellung |mutt -s "Rechnung 4711" user@domain.tld  $anhang

echo $anhang
-a 9262_mueller.pdf
-a Produkt1.pdf
-a Produkt2.pdf
-a Produkt3.pdf
in o.a. Code eingefügt funktioniert
Sind aber Leerstellen in den Dateinamen enthalten, funktioniert es nicht, selbst wenn ich die Dateinamen in Anführungszeichen setze.


Code:
#!/bin/sh 
ls *pdf >erg
while read "FILE";do
        f=`echo  $FILE| sed -e s/" "/"\\\\\ "/g`
        anhang=$anhang" "-a" "$f
done < erg

echo test| mutt -s "Rechnung xyz" user@domain.tld  $anhang

Meesage sent

Mit Leerstellen im Dateinamen erhalte ich z.B.:
Code:
 mutt -s 'Rechnung xyz' user@domain.tld -a '9262\' mueller.pdf -a Produkt1.pdf -a Produkt2.pdf -a Produkt3.pdf
Can't stat 9262\: No such file or directory
9262\: unable to attach file.
dass das 9262\ in Hochkommata steht, macht mich schon stutzig, aber ich bekomme es nicht weg.

Ändere ich das Skript, dass die Dateinamen in Anführungszeichen stehen, wird das Ergebnis auch nicht besser:
Code:
#!/bin/sh 
ls *pdf >erg
while read "FILE";do
        anhang=$anhang" "-a" " \"$FILE\"
done < erg
echo test| mutt -s "Rechnung xyz" user@domain.tld  $anhang

 mutt -s 'Rechnung xyz' user@domain.tld -a '"9262' 'mueller.pdf"' -a '"Produkt1.pdf"' -a '"Produkt2.pdf"' -a '"Produkt3.pdf"'
+ echo test
No recipients specified.
"No recipients specified.", obwohl dieser klar angegeben ist. Einzige Änderung gegenüber dem Beispiel oben ist ein etwas anderer Inhalt er Variablen $anhang.

Meine Fragen:
Habe ich einen Denkfehler gemacht?
Wer hat eine funktionierende Lösung parat oder kennt einen Link zu einer solchen?
 
Zuletzt bearbeitet:
Wie wäre es, wenn man die Leerzeichen im Dateinamen maskiert, etwa mit "%20" oder "_"?
 
Ohne die weiteren Anforderungen zu kennen, würde ich das so machen:
Code:
#!/bin/bash

for FILE in /tmp/*.pdf; do
    FILE=$(echo $FILE | sed 's/ /\\ /g')
    anhang+="-a $FILE"
done
echo $anhang

Wie wäre es, wenn man die Leerzeichen im Dateinamen maskiert, etwa mit "%20" oder "_"?
Siehe mein Beispiel: einfach nur escapen. Mehr braucht man nicht.
 
Wie wäre es, wenn man die Leerzeichen im Dateinamen maskiert, etwa mit "%20" oder "_"?
Die Dateinamen wollte ich nicht verändern. - Die Bash MUSS das können!

@buddabrod:
gleiches Ergebnis wie oben in meinem Beispiel:
Code:
+ for FILE in '*.pdf'
++ echo 9262 mueller.pdf
++ sed 's/ /\\ /g'
+ FILE='9262\ mueller.pdf'
+ anhang+=' -a 9262\ mueller.pdf'
+ for FILE in '*.pdf'
++ echo Produkt1.pdf
++ sed 's/ /\\ /g'
+ FILE=Produkt1.pdf
+ anhang+=' -a Produkt1.pdf'
+ for FILE in '*.pdf'
++ echo Produkt2.pdf
++ sed 's/ /\\ /g'
+ FILE=Produkt2.pdf
+ anhang+=' -a Produkt2.pdf'
+ for FILE in '*.pdf'
++ echo Produkt3.pdf
++ sed 's/ /\\ /g'
+ FILE=Produkt3.pdf
+ anhang+=' -a Produkt3.pdf'
+ echo -a '9262\' mueller.pdf -a Produkt1.pdf -a Produkt2.pdf -a Produkt3.pdf
-a 9262\ mueller.pdf -a Produkt1.pdf -a Produkt2.pdf -a Produkt3.pdf
+ echo test
+ mutt -s 'Rechnung xyz' user@domain.tld -a '9262\' mueller.pdf -a Produkt1.pdf -a Produkt2.pdf -a Produkt3.pdf
Can't stat 9262\: No such file or directory
9262\: unable to attach file.

Ich kann mir ehlich gesagt nicht vorstellen, dass die Linux Bash das nach 25 Jahren Entwicklung nicht hinbekäme. Das kann eigentlich nur auf einen Syntax-Fehler beruhen.
 
Zuletzt bearbeitet:
Was ist denn das für ein Output? oO
Edit: argh, da war ja was mit 'set -x' :)

Ich bash-e nur noch selten..

Sei sehr vorsichtig, was einfache und doppelte Anführungszeichen angeht. Außerdem sind die Backticks veraltet und dein Shebang sollte explizit auf die Bash verweisen.

Kannst du nochmal das reine, angepasste Skript posten?

Btw. solltest du das mal ohne Debugging testen. Das fügt am Ende diese einfachen Anführungszeichen ein. Warum das so ist, kann ich nicht sagen.

Beispiel:

Code:
 for NUMBER in {1..5}; do touch /tmp/$NUMBER\ .pdf; done
Skript:
Code:
#!/bin/bash

for FILE in /tmp/*.pdf; do
        FILE=$(echo $FILE | sed 's/ /\\ /g' )
        anhang+=" -a $FILE"
done
echo Anhang: $anhang
Ausführen:
Code:
bash -x test.sh 
+ for FILE in /tmp/*.pdf
++ echo /tmp/1 .pdf
++ sed 's/ /\\ /g'
+ FILE='/tmp/1\ .pdf'
+ anhang+=' -a /tmp/1\ .pdf'
+ for FILE in /tmp/*.pdf
++ echo /tmp/2 .pdf
++ sed 's/ /\\ /g'
+ FILE='/tmp/2\ .pdf'
+ anhang+=' -a /tmp/2\ .pdf'
+ for FILE in /tmp/*.pdf
++ echo /tmp/3 .pdf
++ sed 's/ /\\ /g'
+ FILE='/tmp/3\ .pdf'
+ anhang+=' -a /tmp/3\ .pdf'
+ for FILE in /tmp/*.pdf
++ echo /tmp/4 .pdf
++ sed 's/ /\\ /g'
+ FILE='/tmp/4\ .pdf'
+ anhang+=' -a /tmp/4\ .pdf'
+ for FILE in /tmp/*.pdf
++ echo /tmp/5 .pdf
++ sed 's/ /\\ /g'
+ FILE='/tmp/5\ .pdf'
+ anhang+=' -a /tmp/5\ .pdf'
+ echo Anhang: -a '/tmp/1\' .pdf -a '/tmp/2\' .pdf -a '/tmp/3\' .pdf -a '/tmp/4\' .pdf -a '/tmp/5\' .pdf
Anhang: -a /tmp/1\ .pdf -a /tmp/2\ .pdf -a /tmp/3\ .pdf -a /tmp/4\ .pdf -a /tmp/5\ .pdf

Liefert das richtige Ergebnis.
 
Zuletzt bearbeitet:
Ist hier vielleicht mutt das Problem? Nimm mal etwas anderes zum Mailversand, etwa das (etwas altmodische) mailx.

Guido
 
Ist hier vielleicht mutt das Problem? Nimm mal etwas anderes zum Mailversand, etwa das (etwas altmodische) mailx.

Guido
Nicht unbedingt mutt, sondern eher die pipe -> daran habe ich eben nicht gedacht.

Code:
echo Anhang: $anhang
echo Anhang: $anhang | xargs echo
liefert:
Code:
bash test.sh 
Anhang: -a /tmp/1\ .pdf -a /tmp/2\ .pdf -a /tmp/3\ .pdf -a /tmp/4\ .pdf -a /tmp/5\ .pdf
Anhang: -a /tmp/1 .pdf -a /tmp/2 .pdf -a /tmp/3 .pdf -a /tmp/4 .pdf -a /tmp/5 .pdf

Lösungswege dafür gibt es dann beispielsweise hier:
https://stackoverflow.com/questions/301039/how-can-i-escape-white-space-in-a-bash-loop-list

Einfach arrays nehmen :)


Edit:
Ich hatte das tatsächlich auch mal, sehe ich gerade. Bin damals aber über den Weg der Funktionen gegangen:
Code:
#!/bin/bash

for FILE in /tmp/*.pdf; do
        FILE=$(echo $FILE | sed 's/ /\\ /g')
        anhang+="-a $FILE "
done


send_mail () {
        echo hallo | mutt -s Test admin@domain.tld "$1"
}

send_mail "$anhang"

Test:
Code:
bash -x test.sh 
+ for FILE in /tmp/*.pdf
++ echo /tmp/1 .pdf
++ sed 's/ /\\ /g'
+ FILE='/tmp/1\ .pdf'
+ anhang+=' -a /tmp/1\ .pdf'
+ for FILE in /tmp/*.pdf
++ echo /tmp/2 .pdf
++ sed 's/ /\\ /g'
+ FILE='/tmp/2\ .pdf'
+ anhang+=' -a /tmp/2\ .pdf'
+ for FILE in /tmp/*.pdf
++ echo /tmp/3 .pdf
++ sed 's/ /\\ /g'
+ FILE='/tmp/3\ .pdf'
+ anhang+=' -a /tmp/3\ .pdf'
+ for FILE in /tmp/*.pdf
++ echo /tmp/4 .pdf
++ sed 's/ /\\ /g'
+ FILE='/tmp/4\ .pdf'
+ anhang+=' -a /tmp/4\ .pdf'
+ for FILE in /tmp/*.pdf
++ echo /tmp/5 .pdf
++ sed 's/ /\\ /g'
+ FILE='/tmp/5\ .pdf'
+ anhang+=' -a /tmp/5\ .pdf'
+ send_mail ' -a /tmp/1\ .pdf -a /tmp/2\ .pdf -a /tmp/3\ .pdf -a /tmp/4\ .pdf -a /tmp/5\ .pdf'
+ echo hallo
+ mutt -s Test admin@domain.tld ' -a /tmp/1\ .pdf -a /tmp/2\ .pdf -a /tmp/3\ .pdf -a /tmp/4\ .pdf -a /tmp/5\ .pdf'
 
Zuletzt bearbeitet:
Code:
#!/bin/bash

for FILE in /tmp/*.pdf; do
        FILE=$(echo $FILE | sed 's/ /\\ /g' )
        anhang+=" -a $FILE"
done


send_mail () {
        echo hallo | mutt -s Test admin@domain.tld "$1"
}

send_mail "$anhang"
Bei mir kommt nur "Müll" raus:

Header der Mail:
Code:
An: user@domain.tld; -a9262mueller.pdf-aProdukt1.pdf-aProdukt2.pdf-aProdukt3.pdf@domain.tld
Alle Blanks wurden eliminiert.


Code:
echo Anhang: $anhang
-a 9262\ mueller.pdf -a Produkt1.pdf -a Produkt2.pdf -a Produkt3.pdf
echo Anhang: $anhang | xargs echo
-a 9262 mueller.pdf -a Produkt1.pdf -a Produkt2.pdf -a Produkt3.pdf
also wohl das Piping daran Schuld.

"#!/bin/bash" bringt keine Änderung


=====================================================
Edit:
Ich habe jetzt diese Lösung erfolgreich getestet:
Wie wäre es, wenn man die Leerzeichen im Dateinamen maskiert, etwa mit "%20" oder "_"?
Code:
#!/bin/bash
for FILE in *.pdf; do
    datei=$(echo $FILE | sed 's/ /_/g')
    mv "$FILE"  $datei
    anhang=$anhang" -a "$datei
done
echo test| mutt -s "Rechnung xyz" user@domain.tld  $anhang

Danke für Deine Mühen, buddabrod, aber ich möchte Dich nicht über-strapazieren. Darum mache ich es, wie oben alternativ vorgeschlagen wurde.
 
Zuletzt bearbeitet:
Mit
Code:
xargs -n1 echo
kann man schön das tokenizing der bash sehen

Code:
#!/bin/bash

for FILE in ./*.pdf; do
        FILE=$(echo $FILE | sed 's/ /\\ /g' )
        anhang+=" -a $FILE"
done


send_mail () {
        echo hallo | echo -s Test admin@domain.tld "$1" | xargs -n1 echo
}

send_mail "$anhang"

Output wie gewünscht:
Code:
-s
Test
admin@domain.tld
-a
./foo bar111.pdf
-a
./foo bar11.pdf
-a
./foo bar1.pdf
-a
./foo bar.pdf

Somit scheint es für mich als komme mutt mit leerzeichen im Dateinamen nicht klar.
 
Danke für Deine Mühen, buddabrod, aber ich möchte Dich nicht über-strapazieren. Darum mache ich es, wie oben alternativ vorgeschlagen wurde.
Sehr gerne, habe ja auch dabei gelernt. Weiter wüsste ich jetzt auch nicht :)
 
Das wissen wir, nur eben bereiten Dateinamen mit Leerstellen Probleme.
 
Blöde Frage:
Warum so komplizeit? Laut http://www.mutt.org/doc/mutt.1.txt kann man der -a option mehrere Dateien mitgeben...

Aha. Du meinst, statt

Code:
-a File1 -a File2 -a File3
usw. kann man auch
Code:
-a file1 file2 file3
scheiben?

Nebenbei: der Hinweis, die Option -a ans Ende der Kommandotzeile zu stellen, steht da sicher nicht ganz ohne Grund.
 
Zuletzt bearbeitet:
Bei neueren Mutt-Versionen müssen Dateianhänge zwingend am Ende der Befehlszeile stehen, ältere Versionen waren da toleranter Bei letzteren musste vor jeden Dateinamen ein "-a" ergänzt werden und ein Parameter ohne "-irgendwas" war automatisch eine Mailadresse.
Da es hier jedoch um eine etwas ältere Mutt-Version geht, will Mutt vor jedem Dateinamen ein "-a".
 
Zuletzt bearbeitet:
An der Manpage von mutt waren ja auch Spaßvögel am Werk:

Code:
BUGS
       None.  Mutts have fleas, not bugs.

;)
 
  • ok1.de
  • ok2.de
  • thinkstore24.de
  • Preiswerte-IT - Gebrauchte Lenovo Notebooks kaufen

Werbung

Zurück
Oben