aktion (script) starten wenn ftp transfer beendet ist
Hallo Liste! vielleicht hat jemand hier eine Idee, die zur Lösung meiner Aufgabe helfen könnte. Ich habe hier eine "externe" Hardware, die zu unvorhersehbaren Zeitpunkten (reicht von 2x täglich bis minütlich) über ftp eine XML Datei schickt. Der von dieser Hardware automatisch generierte Dateiname ist dabei der Zeitstempel ("yyyymmddhhmmss.xml"). Die Hardware verbindet sich zum ftp-server, sendet die Datei und schließt die Verbindung wieder. Das läuft jetzt seit cirka 4 Jahren ohne einen einzigen "Zwischenfall". So weit, so gut. Nun gibt es den Wunsch, diese XML Datei, sobald sie empfangen wurde, nicht einfach (nur) zu speichern, sondern "gleich" zu parsen und den Inhalt in eine sql Datenbank zu füttern. Jetzt denke ich mal über den ersten Schritt nach, wie man ein shell-script automatisch starten könnte, sobald eine Datei angekommen ist. hat jemand von Euch eine Idee dazu? In der Doku des ftp-servers (z.B. vsftpd) habe ich auf den ersten Blick nichts gefunden, was dafür helfen könnte. Gab es da nicht noch etwas anderes? Dass das filesystem bei Änderung eines directories irgendwelche Signale schickt? Grüße, Norbert
Hallo, Am Sa, 22 Okt 2022, Norbert Zawodsky schrieb:
Jetzt denke ich mal über den ersten Schritt nach, wie man ein shell-script automatisch starten könnte, sobald eine Datei angekommen ist. hat jemand von Euch eine Idee dazu?
In der Doku des ftp-servers (z.B. vsftpd) habe ich auf den ersten Blick nichts gefunden, was dafür helfen könnte. Gab es da nicht noch etwas anderes? Dass das filesystem bei Änderung eines directories irgendwelche Signale schickt?
Schau dir mal die Programme inotifywait und incrond an. incrond (siehe englisches 'man 5 incrontab', drittes Beispiel): /VERZEICHNIS IN_CREATE /pfad/zu/scriptname $@/$# (wobei das $@/$# Pfad und Dateiname sind). Alternativ z.B. das Beispiel 4 in der engl. Version von 'man 1 inotifywait' könnte was für dich sein, Kurzgerüst daraus: inotifywait ... /VERZEICHNIS | while IFS= read -r -d '' file ; do machwas mit $file done HTH, -dnh -- It is traditional, when loading wire trolleys, to put the most fragile items at the bottom. -- Terry Pratchett, Reaper Man
Hallo David, Hallo Jürgen, inotifywait -- super! Mit inotifywait warten. Wenn eine Datei angekommen ist, mit den xmltools parsen und z.B. ein csv generieren. Das csv dann mit 'mysql' in die Datenbank füttern. Auf den ersten Blick nicht schwierig. (mal sehen welche Stolpersteine auftauchen...) Danke! Norbert Am 22.10.22 16:12 schrieb David Haller:
Hallo,
Am Sa, 22 Okt 2022, Norbert Zawodsky schrieb:
Jetzt denke ich mal über den ersten Schritt nach, wie man ein shell-script automatisch starten könnte, sobald eine Datei angekommen ist. hat jemand von Euch eine Idee dazu? In der Doku des ftp-servers (z.B. vsftpd) habe ich auf den ersten Blick nichts gefunden, was dafür helfen könnte. Gab es da nicht noch etwas anderes? Dass das filesystem bei Änderung eines directories irgendwelche Signale schickt? Schau dir mal die Programme inotifywait und incrond an.
incrond (siehe englisches 'man 5 incrontab', drittes Beispiel):
/VERZEICHNIS IN_CREATE /pfad/zu/scriptname $@/$#
(wobei das $@/$# Pfad und Dateiname sind).
Alternativ z.B. das Beispiel 4 in der engl. Version von 'man 1 inotifywait' könnte was für dich sein, Kurzgerüst daraus:
inotifywait ... /VERZEICHNIS | while IFS= read -r -d '' file ; do machwas mit $file done
HTH, -dnh
Am 22.10.2022 um 16:38 schrieb Norbert Zawodsky:
Hallo David, Hallo Jürgen,
inotifywait -- super!
Mit inotifywait warten. Wenn eine Datei angekommen ist, mit den xmltools parsen und z.B. ein csv generieren. Das csv dann mit 'mysql' in die Datenbank füttern. Auf den ersten Blick nicht schwierig. (mal sehen welche Stolpersteine auftauchen...)
Das ist auch nicht schwierig. Ich verwende das auch in mehreren Skripten auf verschiedenen Servern ohne Probleme seit vielen vielen Jahren Manfred
Hallo, Am Sa, 22 Okt 2022, Norbert Zawodsky schrieb:
inotifywait -- super!
Mit inotifywait warten. Wenn eine Datei angekommen ist, mit den xmltools parsen und z.B. ein csv generieren. Das csv dann mit 'mysql' in die Datenbank füttern. Auf den ersten Blick nicht schwierig. (mal sehen welche Stolpersteine auftauchen...)
Erstens: für mich klingt incrond fast interessanter, um den scriptaufruf auszulösen ... Zweitens: Kannst du ein wenig perl? Das ist für solche Aufgaben ideal geeignet und kann XML parsen (mit diversen Backends wie expat, libxml). Dabei gibt's dann diverse Module über die man recht bequem z.B. per XPath auf bestimmte Daten zugreifen kann. Die geparsten Daten kann man dann direkt per DBI in ne DB schreiben. Und für das Programmier-Interface DBI gibt's in Perl diverse Backends, u.a. für mysql/mariadb, postgres und *tada* auch für .csv ;) Grundidee, eher platzsparend statt schön formatiert: ==== #!/usr/bin/perl -w use strict; use XML::TreeBuilder; use XML::XPathEngine; use DBI; ### "DB"-Verbindungen herstellen my $dbh = DBI->connect("dbi:mysql:dbname=$dbname", ...) or die "Cannot connect to MySQL: $DBI::errstr"; my $csv = DBI->connect ("dbi:CSV:", ...) or die "Cannot connect to CSV: $DBI::errstr"; my $mst = $dbh->prepare('INSERT INTO mytable(a) VALUES (?)'); my $cst = $csv->prepare('INSERT INTO mytable(a) VALUES (?)'); ### XML einlesen my $xp = XML::XPathEngine->new(); # Optionen möglich my $xmltree = XML::TreeBuilder->new(); # Optionen möglich $xmltree->parse_file($ARGV[1]) or die; ### geparstes XML verarbeiten, z.B. my @grandkids = $xp->find('/root/kid/grandkid[3]', $xmltree); foreach my $gk (@grandkids) { $cst->bind_param($gk->{'foo'}, $gk->{'bar'}); $cst->execute(); $mst->bind_param($gk->{'foo'}, $gk->{'bar'}); $mst->execute(); } ### "DB" Verbindungen schließen $csv->disconnect(); $dbh->disconnect(); ### XML-Tree abräumen $xmltree->delete(); ==== Das geht garantiert besser. Soll nur als (Grund-)Ideengeber dienen. Der Vorteil von DBI ist u.a., daß die Schnittstelle eben (so weit es möglich ist) bei allen Datenbanken von CSV über SQLite, MySQL/MariaDB, PostgreSQL bis hin zu Oracle oder DB/2 oder weiß der Geier gleich bleibt... Achso: ich hab grad ohne nachzuschauen und ggfs. zu testen keinen Schimmer, ob das mit dem ->prepare(..) und ->bind_param(..) so korrekt ist. Ist lange her, daß ich das verwendet habe. Aber die Schnittstelle ist noch so wie damals vor, öhm, wohl ca. 20 Jahren ;) Und eben: in perl kannst du das ganze Geraffel (XML einlesen, parsen, Daten rausprökeln, in CSV und/oder DB wegschreiben) recht bequem quasi auf einen Schlag abhandeln. Geht mit python genauso gut, soweit ich weiß. Nur ziemlich anders ;) Aber perl/python bieten sich extrem an für das was du vorzuhaben scheinst. HTH, -dnh -- C, on the other hand, has a reputation as something that will segfault your foot off if you look at the compiler funny, so by and large it scares off those who should leave coding to others. -- AdB re PHP
Am 22.10.22 17:45 schrieb David Haller:
Hallo,
inotifywait -- super!
Mit inotifywait warten. Wenn eine Datei angekommen ist, mit den xmltools parsen und z.B. ein csv generieren. Das csv dann mit 'mysql' in die Datenbank füttern. Auf den ersten Blick nicht schwierig. (mal sehen welche Stolpersteine auftauchen...) Erstens: für mich klingt incrond fast interessanter, um den
Am Sa, 22 Okt 2022, Norbert Zawodsky schrieb: scriptaufruf auszulösen ...
Zweitens: Kannst du ein wenig perl? Das ist für solche Aufgaben ideal geeignet und kann XML parsen (mit diversen Backends wie expat, libxml). Dabei gibt's dann diverse Module über die man recht bequem z.B. per XPath auf bestimmte Daten zugreifen kann.
Die geparsten Daten kann man dann direkt per DBI in ne DB schreiben.
Und für das Programmier-Interface DBI gibt's in Perl diverse Backends, u.a. für mysql/mariadb, postgres und *tada* auch für .csv ;)
Grundidee, eher platzsparend statt schön formatiert:
==== #!/usr/bin/perl -w use strict; use XML::TreeBuilder; use XML::XPathEngine; use DBI;
### "DB"-Verbindungen herstellen my $dbh = DBI->connect("dbi:mysql:dbname=$dbname", ...) or die "Cannot connect to MySQL: $DBI::errstr"; my $csv = DBI->connect ("dbi:CSV:", ...) or die "Cannot connect to CSV: $DBI::errstr";
my $mst = $dbh->prepare('INSERT INTO mytable(a) VALUES (?)'); my $cst = $csv->prepare('INSERT INTO mytable(a) VALUES (?)');
### XML einlesen my $xp = XML::XPathEngine->new(); # Optionen möglich my $xmltree = XML::TreeBuilder->new(); # Optionen möglich $xmltree->parse_file($ARGV[1]) or die;
### geparstes XML verarbeiten, z.B. my @grandkids = $xp->find('/root/kid/grandkid[3]', $xmltree); foreach my $gk (@grandkids) { $cst->bind_param($gk->{'foo'}, $gk->{'bar'}); $cst->execute(); $mst->bind_param($gk->{'foo'}, $gk->{'bar'}); $mst->execute(); }
### "DB" Verbindungen schließen $csv->disconnect(); $dbh->disconnect();
### XML-Tree abräumen $xmltree->delete(); ====
Das geht garantiert besser. Soll nur als (Grund-)Ideengeber dienen.
Der Vorteil von DBI ist u.a., daß die Schnittstelle eben (so weit es möglich ist) bei allen Datenbanken von CSV über SQLite, MySQL/MariaDB, PostgreSQL bis hin zu Oracle oder DB/2 oder weiß der Geier gleich bleibt...
Achso: ich hab grad ohne nachzuschauen und ggfs. zu testen keinen Schimmer, ob das mit dem ->prepare(..) und ->bind_param(..) so korrekt ist. Ist lange her, daß ich das verwendet habe. Aber die Schnittstelle ist noch so wie damals vor, öhm, wohl ca. 20 Jahren ;)
Und eben: in perl kannst du das ganze Geraffel (XML einlesen, parsen, Daten rausprökeln, in CSV und/oder DB wegschreiben) recht bequem quasi auf einen Schlag abhandeln.
Geht mit python genauso gut, soweit ich weiß. Nur ziemlich anders ;)
Aber perl/python bieten sich extrem an für das was du vorzuhaben scheinst.
HTH, -dnh
Hallo David! erst mal vielen Dank für die SEHR ausführlichen Erklärungen! Von perl hab ich keine Ahnung. Da ich aber schon viel C++ programmiert habe, werde ich perl hoffentlich auch verstehen. incrond klingt interessant. werde ich mir ansehen, aber auf einem anderen Rechner. Der gegenständliche server läuft noch unter OS 15.1, da scheint es incrond (noch) nicht zu geben. Norbert
Am 22.10.22 21:38 schrieb Norbert Zawodsky:
Am 22.10.22 17:45 schrieb David Haller:
Hallo,
inotifywait -- super!
Mit inotifywait warten. Wenn eine Datei angekommen ist, mit den xmltools parsen und z.B. ein csv generieren. Das csv dann mit 'mysql' in die Datenbank füttern. Auf den ersten Blick nicht schwierig. (mal sehen welche Stolpersteine auftauchen...) Erstens: für mich klingt incrond fast interessanter, um den
Am Sa, 22 Okt 2022, Norbert Zawodsky schrieb: scriptaufruf auszulösen ...
Zweitens: Kannst du ein wenig perl? Das ist für solche Aufgaben ideal geeignet und kann XML parsen (mit diversen Backends wie expat, libxml). Dabei gibt's dann diverse Module über die man recht bequem z.B. per XPath auf bestimmte Daten zugreifen kann.
Die geparsten Daten kann man dann direkt per DBI in ne DB schreiben.
Und für das Programmier-Interface DBI gibt's in Perl diverse Backends, u.a. für mysql/mariadb, postgres und *tada* auch für .csv ;)
Grundidee, eher platzsparend statt schön formatiert:
==== #!/usr/bin/perl -w use strict; use XML::TreeBuilder; use XML::XPathEngine; use DBI;
### "DB"-Verbindungen herstellen my $dbh = DBI->connect("dbi:mysql:dbname=$dbname", ...) or die "Cannot connect to MySQL: $DBI::errstr"; my $csv = DBI->connect ("dbi:CSV:", ...) or die "Cannot connect to CSV: $DBI::errstr";
my $mst = $dbh->prepare('INSERT INTO mytable(a) VALUES (?)'); my $cst = $csv->prepare('INSERT INTO mytable(a) VALUES (?)');
### XML einlesen my $xp = XML::XPathEngine->new(); # Optionen möglich my $xmltree = XML::TreeBuilder->new(); # Optionen möglich $xmltree->parse_file($ARGV[1]) or die;
### geparstes XML verarbeiten, z.B. my @grandkids = $xp->find('/root/kid/grandkid[3]', $xmltree); foreach my $gk (@grandkids) { $cst->bind_param($gk->{'foo'}, $gk->{'bar'}); $cst->execute(); $mst->bind_param($gk->{'foo'}, $gk->{'bar'}); $mst->execute(); }
### "DB" Verbindungen schließen $csv->disconnect(); $dbh->disconnect();
### XML-Tree abräumen $xmltree->delete(); ====
Das geht garantiert besser. Soll nur als (Grund-)Ideengeber dienen.
Der Vorteil von DBI ist u.a., daß die Schnittstelle eben (so weit es möglich ist) bei allen Datenbanken von CSV über SQLite, MySQL/MariaDB, PostgreSQL bis hin zu Oracle oder DB/2 oder weiß der Geier gleich bleibt...
Achso: ich hab grad ohne nachzuschauen und ggfs. zu testen keinen Schimmer, ob das mit dem ->prepare(..) und ->bind_param(..) so korrekt ist. Ist lange her, daß ich das verwendet habe. Aber die Schnittstelle ist noch so wie damals vor, öhm, wohl ca. 20 Jahren ;)
Und eben: in perl kannst du das ganze Geraffel (XML einlesen, parsen, Daten rausprökeln, in CSV und/oder DB wegschreiben) recht bequem quasi auf einen Schlag abhandeln.
Geht mit python genauso gut, soweit ich weiß. Nur ziemlich anders ;)
Aber perl/python bieten sich extrem an für das was du vorzuhaben scheinst.
HTH, -dnh
Hallo David!
erst mal vielen Dank für die SEHR ausführlichen Erklärungen!
Von perl hab ich keine Ahnung. Da ich aber schon viel C++ programmiert habe, werde ich perl hoffentlich auch verstehen. incrond klingt interessant. werde ich mir ansehen, aber auf einem anderen Rechner. Der gegenständliche server läuft noch unter OS 15.1, da scheint es incrond (noch) nicht zu geben.
Norbert
Hallo David, nur so als follow-up, falls Du / jemand eine ähnlich gelagerte Aufgabe hat... Ein Freund hat mich darauf gebracht, das Weg XML -> SQL mit einer XSL Transformation zu machen. Das ging absolut einfach! 1x die Transformations-Regeln ausdenken und in einer Datei (im Besispiel Transform2SQL.xslt) speichern, dann nur mehr * XML Datei empfangen * xsltproc Transform2SQL.xslt input.xml > output.sql * mysql < output.sql Das war's im Wesentlichen (abgesehen von so Kleinigkeiten wie Fehlerbehandlung 😉) Gruß, Norbert
Hi vielleicht hilft inotifywait https://linux.die.net/man/1/inotifywait Bye Jürgen Am Samstag, 22. Oktober 2022, 15:44:04 CEST schrieb Norbert Zawodsky:
Hallo Liste!
vielleicht hat jemand hier eine Idee, die zur Lösung meiner Aufgabe helfen könnte.
Ich habe hier eine "externe" Hardware, die zu unvorhersehbaren Zeitpunkten (reicht von 2x täglich bis minütlich) über ftp eine XML Datei schickt. Der von dieser Hardware automatisch generierte Dateiname ist dabei der Zeitstempel ("yyyymmddhhmmss.xml"). Die Hardware verbindet sich zum ftp-server, sendet die Datei und schließt die Verbindung wieder. Das läuft jetzt seit cirka 4 Jahren ohne einen einzigen "Zwischenfall". So weit, so gut.
Nun gibt es den Wunsch, diese XML Datei, sobald sie empfangen wurde, nicht einfach (nur) zu speichern, sondern "gleich" zu parsen und den Inhalt in eine sql Datenbank zu füttern.
Jetzt denke ich mal über den ersten Schritt nach, wie man ein shell-script automatisch starten könnte, sobald eine Datei angekommen ist. hat jemand von Euch eine Idee dazu?
In der Doku des ftp-servers (z.B. vsftpd) habe ich auf den ersten Blick nichts gefunden, was dafür helfen könnte. Gab es da nicht noch etwas anderes? Dass das filesystem bei Änderung eines directories irgendwelche Signale schickt?
Grüße, Norbert
-- Dr.rer.nat. Jürgen Vollmer, Am Rennbuckel 21, D-76185 Karlsruhe Tel: +49(721) 92 04 87 1 Fax: +49(721) 92 04 87 2 Juergen.Vollmer@informatik-vollmer.de www.informatik-vollmer.de ------------------------------------------------------------------------------- Diese EMail ist elektronisch mittels GPG / PGP signiert. Diese elektronische Unterschrift ist in einem EMail-Anhang enthalten. Leider kann die Signatur ohne die Installation entsprechender Programme weder geprüft noch angezeigt werden. Mehr dazu unter: http://www.gnupg.org oder auch http://www.pgpi.org -------------------------------------------------------------------------------
participants (4)
-
David Haller
-
Dr. Juergen Vollmer
-
Manfred Kreisl
-
Norbert Zawodsky