ubuntuusers.de

[inotifywait] automatischer Download mit Überwachung einer URL-Liste

Status: Ungelöst | Ubuntu-Version: Ubuntu 8.04 (Hardy Heron)
Antworten |

ingo2

Avatar von ingo2

Anmeldungsdatum:
15. Juni 2007

Beiträge: 2145

Wohnort: wo der gute Riesling wächst

Ich habe mir die 'inotify-tools' installiert und ein kleines Script gebastelt, welches:

a) eine Textdatei auf Veränderungen überwacht, da kommen die URL's zum Download rein.

b) bei Änderungen an der Datei diese zunächst sperrt (chmod 444)

c) die Liste mit URL's in der Datei mit wget abarbeitet

d) die Liste löscht und eine neue leere erzeugt.

Hier das Script:

#!/bin/sh

# Script "download-watch" waits for changes in the
# download-list 'URLLIST' and if detected, downloads
# all files in the list using wget into 'WORKDIR'.

WORKDIR=/home/ingo/download
URLLIST=$WORKDIR/url.list
LOGFILE=$WORKDIR/wget.log

while inotifywait -e modify $URLLIST >/dev/null 2>&1; do
  echo "Change detected"
  # Protect list against modifications
  chmod 444 $URLLIST
  # Delay to wait for changes to become effective
  sleep 2
  wget -N -w 2 -P $WORKDIR -a $LOGFILE -i $URLLIST
  echo "List downloaded"
  rm -f $URLLIST && touch $URLLIST && chmod 666 $URLLIST
  echo "$URLLIST cleared"
done

So, das klappt auch alles ganz prima und ich kann meine Downloadliste auf mehrere Arten befüllen:

1. mit 'nano': beim Speichern mit Ctrl+o beginnt der Download → ok!

2. echo <URL> >> $URLLIST → klappt ebenso ok!

3. nur, wenn ich $URLLIST mit 'gedit' abspeichere, passiert entweder garnix oder beim 2tem Versuch beendet sich das Script einfach. 😢 habe dabei mal den Output von 'inotifywait' beobachtet, sieht so aus:

ingo@nas:~/download$ ./download-watch
Setting up watches.  
Watches established.
/home/ingo/download/url.list IGNORED 

Meine Idee: 'gedit' benennt erst die original-Datei um und speichert die neue dann unter dem alten Namen. Somit ist die Datei für einen Moment verschwunden und 'inotifywait' steigt einfach aus.

Was könnte man da tun??

Viele Grüße, Ingo

Pommes

Avatar von Pommes

Anmeldungsdatum:
23. Februar 2008

Beiträge: 53

Wenn deine Theorie stimmt und ich dein Skript richtig verstanden habe - läuft es die ganze Zeit durchgängig? - könntest du um deine while-Schilfe einer weitere while-Schleife setzen

1
2
3
4
5
6
7
while [ -f ${URLLIST} ]; do
  while inotifywait -e modify $URLLIST >/dev/null 2>&1; do
    ...
  done
  # Warte 5 Sek falls Datei nur für kurze Zeit nicht vorhanden ist.
  sleep 5
done

ingo2

(Themenstarter)
Avatar von ingo2

Anmeldungsdatum:
15. Juni 2007

Beiträge: 2145

Wohnort: wo der gute Riesling wächst

läuft es die ganze Zeit durchgängig?

Ja, wenn inotifywait eine Änderung bemerkt, meldet es die und beendet sich. Durch die 'while'-Schleife wird es aber nach erfogtem Download wieder neu gestartet.

Die 2te Schleife drum rum habe ich gleich getestet:

1. das Download-Verhalten ist immer noch genau das gleiche. beim 1. Mal speichern aus Gedit passiert garnix, beim 2. Mal kommt die bekannte Meldung

Setting up watches.  
Watches established.
/home/ingo/download/url.list IGNORED 

und ein Download mit wget findet nicht statt.

2. Einen kleinen Schritt weiter geht es allerdings, durch die 2te Schleife wird 'inotify' wieder neu gestartet. Somit ist das Script jetzt zumindest schon mal gegen die Gedit-Schweinereien resistent 😉.

Ich könnte zwar jetzt in die äußere Schleife die ganze Download-Aktion nochmals schreiben, dann bleibt aber immer noch das Problem, daß ich mit 'Gedit' die URLLIST 2x abspeichern muß bis er dann wirklich arbeitet.

So eine Frickelei kann's ja nicht sein- oder?

Ingo

Sid_Burn

Anmeldungsdatum:
23. Oktober 2004

Beiträge: 2159

ingo2 schrieb:

2. Einen kleinen Schritt weiter geht es allerdings, durch die 2te Schleife wird 'inotify' wieder neu gestartet. Somit ist das Script jetzt zumindest schon mal gegen die Gedit-Schweinereien resistent 😉.

Das sind keine Gedit Schweinereien sondern so behandelt man korrekt das Speichern von Dateien ohne bei einen aprupten Ausfall des PCs Daten zu verlieren (Obwohl das alleine nicht ausreicht wenn man die Buffer nicht synct). Das Problem liegt nicht an Gedit das es das macht, sondern an deiner verkorksten Methode eine Datei auf änderungen zu prüfen und dann immer wieder das als Trigger zu nutzen um eine Aktion auszuführen.

Anstatt etwas in eine Datei zu schreiben könntest du anfangen dein Programm so zu schreiben das es auf einem Socket läuft das du Programme schreibst die sich mit diesem verbinden die dann eine URL übergeben etc. Dann rennst du auch nicht in Probleme die du nur deswegen hast, weil du versuchst etwas zu realisieren was mit deinem Weg eben nicht möglich ist.

ingo2

(Themenstarter)
Avatar von ingo2

Anmeldungsdatum:
15. Juni 2007

Beiträge: 2145

Wohnort: wo der gute Riesling wächst

Sid Burn schrieb:

ingo2 schrieb:

2. Einen kleinen Schritt weiter geht es allerdings, durch die 2te Schleife wird 'inotify' wieder neu gestartet. Somit ist das Script jetzt zumindest schon mal gegen die Gedit-Schweinereien resistent 😉.

Das sind keine Gedit Schweinereien sondern so behandelt man korrekt das Speichern von Dateien ohne bei einen aprupten Ausfall des PCs Daten zu verlieren (Obwohl das alleine nicht ausreicht wenn man die Buffer nicht synct). Das Problem liegt nicht an Gedit das es das macht, sondern an deiner verkorksten Methode eine Datei auf änderungen zu prüfen und dann immer wieder das als Trigger zu nutzen um eine Aktion auszuführen.

Anstatt etwas in eine Datei zu schreiben könntest du anfangen dein Programm so zu schreiben das es auf einem Socket läuft das du Programme schreibst die sich mit diesem verbinden die dann eine URL übergeben etc. Dann rennst du auch nicht in Probleme die du nur deswegen hast, weil du versuchst etwas zu realisieren was mit deinem Weg eben nicht möglich ist.

Danke für die Aufklärung, aber das hilft mir persönlich nich weiter, da:

1. ich bin Newbie im schreiben von Scripten, Deinen Lösungsvorschlag kann ich nicht umsetzen.

2. ich möchte nicht nur eine einzige URL an wget übergeben, sondern bei Bedarf eine ganze Liste.

3. Das Script soll (wenn es denn mal tut) per cron-Job nachts die Liste abarbeiten und dann wieder beendet werden.

Vielleicht benutze ich ja inotify falsch - wie kann man sowas denn noch monitoren (Dateiveränderungen)???

Das dürfte ja nix exotisches sein, jedes RAID1 oder RAID5, ... sollte so etwas ja implementiert haben.

Viele Grüße, Ingo

Pommes

Avatar von Pommes

Anmeldungsdatum:
23. Februar 2008

Beiträge: 53

Ich glaube nicht, dass sich gedit da optimal verhält, wenn es der Fall ist, wie von dir beschrieben.

Meine Idee: 'gedit' benennt erst die original-Datei um und speichert die neue dann unter dem alten Namen. Somit ist die Datei für einen Moment verschwunden und 'inotifywait' steigt einfach aus.

Dass eine eigentlich existierende Datei für kurze Zeit nicht existent ist, weil sie gelöscht und umkopiert wird ist nie gut. Besser wäre es hier während des Editierens in eine temporäre Datei zu speichern, und damm beim Speichern diese in die Originaldatei zu "moven". Move ist unter Unix atomar, es gibt also keine Lücke, in die ein anderes Programm hineinfallen kann während gemoved wird. So macht es z.B. "vi". Nano vielleicht auch.

Nun du könntest auch gänzlich auf dieses inotify verzichten und selbst prüfen, ob sich eine Datei geänder hat. Da gibt es viele Möglichkeiten. Simpel ist z.B. ein "ls -la <datei> >/tmp/tmpdatei" Und dann bei jedem Start erneut ein "ls -la" machen und diese mit dem Inhalt in /tmp/tmpdatei vergleichen (diff). Falls eine Änderung vorliegt, hat sich die Datei geändert und du hast deinen Einstiegspunkt. Nach der Abarbeitung musst du dann wieder die tmp-Datei aktualisieren.

Was ich aber gerade lese, wenn das nur einmal nachts per CRON laufen soll, warum brauchst du dann überhaupt so einen komplizierten Mechanismus? Ich hatte es zuvor so verstanden, dass das Skript immer läuft...

Wenn du nur nachts die Liste abarbeiten willst, dann machst du ein:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11

# IFS auf Zeilenumbruch setzem, damit "for" nicht bei Leerzeichen
# trennt, sondern nur bei Zeilenumbruch.
IFS="
"

for url in `cat ${FILE}`; do
  wget ${url}
done

unset IFS

Und am Ende löscht du die Datei ${FILE}.

ingo2

(Themenstarter)
Avatar von ingo2

Anmeldungsdatum:
15. Juni 2007

Beiträge: 2145

Wohnort: wo der gute Riesling wächst

Danke für die Background-Info Pommes,

das mit nachts nur 1x per cron laufen war so eine Idee weil ich sowieso mit Abstürzen gerechnet habe und nicht in einer 2ten Schleife prüfen wollte, ob das Script noch lebt. Letzlich soll das Script auch noch auf ein NAS für automatisierte Downloads. Da kann ich dann per ssh die Liste sowieso nur mit nano (oder vi) bearbeiten und das Problem wäre weg. Das Download-Verzeichnis habe ich aber auch auf dem PC per nfs4 gemountet und da bietet es sich ja an, auch mal mit 'Gedit' die Liste zu bearbeiten.

Das mit dem cron-job war eigentlich nur eine Behelfslösung, fernes Endziel wäre sogar mal eine Download-Zeit mit der URL anzugeben.

Aber jetzt zurück zum aktuellen Thema:

habe inzwischen mal viele 'inotifywait'-Optionen für die EVENTS ausprobiert:

wenn ich statt 'modify' das event 'close_write' benutze, klappt es störungsfrei sowohl mit nano, cat >> und gedit:

Setting up watches.  
Watches established.
/home/ingo/download/url.list CLOSE_WRITE,CLOSE 
Change detected
List downloaded
/home/ingo/download/url.list cleared
Setting up watches.  
Watches established.

Dann muß ich wohl auf 'modify' verzichten, d.h. auch beim speichern einer leeren Datei läuft das Script 1x durch.

Dank deines Tips mit der 2tem while-Schleife habe ich aber jetzt noch ein Sicherheitsnetz und ich lasse das Script einfach Tag + Nacht durchlaufen.

Beste Grüße, Ingo

Sid_Burn

Anmeldungsdatum:
23. Oktober 2004

Beiträge: 2159

ingo2 schrieb:

Danke für die Aufklärung, aber das hilft mir persönlich nich weiter, da: 1. ich bin Newbie im schreiben von Scripten, Deinen Lösungsvorschlag kann ich nicht umsetzen.

Ändert nichts daran das Gedit trotzdem keine Schweinerei macht, und dein Lösungsweg eher bescheiden ist.

2. ich möchte nicht nur eine einzige URL an wget übergeben, sondern bei Bedarf eine ganze Liste.

Und wo ist das Problem? Dann rufst du das Programm 10, 15 oder hundert mal auf um deine Liste zu haben.

3. Das Script soll (wenn es denn mal tut) per cron-Job nachts die Liste abarbeiten und dann wieder beendet werden.

Bei sowas würde ich gar kein inotify dienst aufsetzen wenn es sowieso nur einmal in der nacht durchläuft.

Vielleicht benutze ich ja inotify falsch - wie kann man sowas denn noch monitoren (Dateiveränderungen)??? Das dürfte ja nix exotisches sein, jedes RAID1 oder RAID5, ... sollte so etwas ja implementiert haben.

Nein, RAIDs funktionieren nicht auf Dateisystemebene sondern auf Blockebene.

Ansonsten nutzt du inotify im diesem Sinne nicht verkehrt. Nur auf Datei änderungen zu lauschen ist nur nicht die korrekte Lösung weil Programme eben Dateien löschen/moven.

Ich glaube nicht, dass sich gedit da optimal verhält, wenn es der Fall ist, wie von dir beschrieben. Dass eine eigentlich existierende Datei für kurze Zeit nicht existent ist, weil sie gelöscht und umkopiert wird ist nie gut. Besser wäre es hier während des Editierens in eine temporäre Datei zu speichern, und damm beim Speichern diese in die Originaldatei zu "moven". Move ist unter Unix atomar, es gibt also keine Lücke, in die ein anderes Programm hineinfallen kann während gemoved wird. So macht es z.B. "vi". Nano vielleicht auch.

Genau das wird wohl gedit auch tuen. Wenn du zwei Dateien hast und movest die eine in die andere herein dann bricht ein inotifywait auch ab ohne eine Änderung zu melden. Ist ja auch logisch die Datei hat sich ja auch nicht verändert, sie hört nur auf zu existieren, und es erscheint eine komplett neue Datei an dieser Stelle mit dem gleichen Namen.

ingo2

(Themenstarter)
Avatar von ingo2

Anmeldungsdatum:
15. Juni 2007

Beiträge: 2145

Wohnort: wo der gute Riesling wächst

Sid Burn schrieb:

Ändert nichts daran das Gedit trotzdem keine Schweinerei macht, und dein Lösungsweg eher bescheiden ist.

Tja, meine Linux/Script Kenntnisse sind wirklich noch bescheiden - und damit muß ich leben (oder auf Hilfe von Fachleuten hoffen).

Trotz allem, ich habe wenigstens eine Lösung gefunden mit try and error, wenn auch nicht optimal.

BadBoy

Avatar von BadBoy

Anmeldungsdatum:
25. Oktober 2007

Beiträge: 479

Pommes schrieb:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11

# IFS auf Zeilenumbruch setzem, damit "for" nicht bei Leerzeichen
# trennt, sondern nur bei Zeilenumbruch.
IFS="
"

for url in `cat ${FILE}`; do
  wget ${url}
done

unset IFS

Und am Ende löscht du die Datei ${FILE}.

useless use of "cat"...und dann auch noch die IFS modifizieren...

1
2
3
while read url; do
  wget ${url}
done < "${FILE}"

wäre besser 😉

Antworten |