Dateien automatisch umbennen
Biesterfeld
- webserver
Hallo Leute,
ein wenig Off-Topic:
Auf einem unserer Ubuntu 7.10 Server läuft das eGroupware 1.4 in Kombination mit PostgreSQL 8.2.6, php 5.2.3 und einem Apache 2.2.4. Eine Applikation innerhalb des Groupwares, nämlich MyDMS (Data Managment System) macht hierbei tierisch Ärger. Dateien die per DMS hochgeladen werden, werden als data.<DATEIENDUNG> auf dem Dateisystem gespeichert, aber die Dateiinformationen (u.a. der Pfad im Dateisystem) in der Datenbank abgelegt. Durch eine Inkompatibilität zu Postgres wird der Dateipfad nun ohne Dateiendung in der DB abgelegt und ein späteres Herunterladen scheitert entsprechend, da die Datei nicht gefunden werden kann. Der Bug ist dokumentiert.
Um jetzt nochmal auf MySQL zu migrieren ist es eigentlich zu spät, da schon zu viel im Groupware angelegt ist und die Migration wohl auch nicht so problemlos abläuft.
Daher brauch ich jetzt ne andere Lösung und dachte mir, die Dateinamen sobald sie auf dem Dateisystem liegen um die Endung zu beschneiden. Aber: Wie mach ich sowas sinnvoll? Ist ein Cron-Job für sowas das geeignete Mittel? Gibt es unter Linux Tools, denen man sowas beibringen kann? Gibt es irgendeine Möglichkeit den Apache zu veranlassen, nach jedem Upload ein Shell-Skript anzuwerfen? Kennt vielleicht sogar jemand von euch das konkrete Problem und kann mir helfen?
Vielen Dank und beste Grüße
Biesterfeld
Hallo Biesterfeld,
Daher brauch ich jetzt ne andere Lösung und dachte mir, die Dateinamen sobald sie auf dem Dateisystem liegen um die Endung zu beschneiden. Aber: Wie mach ich sowas sinnvoll?
ich habe folgende Vermutungen:
- alle Dateien liegen im gleichen Verzeichnis (eventuell mit Unterverzeichnissen).
- die Dateien haben "handelsübliche" Endungen, d.h. es ist eine bekannte Menge.
dann könnte es ein kleiner Einzeiler tun.
Ist ein Cron-Job für sowas das geeignete Mittel?
Wenn Du eine Minute Unerreichbarkeit akzeptieren kannst.
Gibt es unter Linux Tools, denen man sowas beibringen kann?
Ja, mv (in Verbindung z.B. mit find)
Gibt es irgendeine Möglichkeit den Apache zu veranlassen, nach jedem Upload ein Shell-Skript anzuwerfen?
Äh, das Uploadskript des CMS. Allerdings willst Du das nicht tun, weil Du bei Updates erneut patchen müsstest.
Natürlich könntest Du auch einen kleinen Prozess als Dämon im Hintergrund laufen lassen, der in einem von Dir vorgegebenem Intervall die betroffene Verzeichnishierarchie auf neue Dateien überprüft und diese dann entsprechend umbenennt, wieder ein Intervall schläft, ...
Freundliche Grüße
Vinzenz
Hallo Biesterfeld,
- alle Dateien liegen im gleichen Verzeichnis (eventuell mit Unterverzeichnissen).
- die Dateien haben "handelsübliche" Endungen, d.h. es ist eine bekannte Menge.
dann könnte es ein kleiner Einzeiler tun.
Ansätze:
for i in /path/to/dir/*.txt /path/to/dir/*.mp3 ; do mv $i ${i%.*} ; done
beseitigt bei allen Dateien im Verzeichnis /path/to/dir, die die Endung .txt oder .mp3 tragen diese Endung. Mit Dateien wie
beispiel.txt
beispiel.mp3
im gleichen Verzeichnis bekommst Du natürlich ein Problem.
Für Dateien in einer Verzeichnishierarchie könntest Du folgendes (mit dem gleichen Problem bei gleichen resultierenden Dateinamen) anwenden:
for i in $(find /path/to/dir -regex ".*(txt|mp3)$") ; do mv $i {i%.*} ; done
benennt alle Dateien im Verzeichnis /path/to/dir und den darin enthaltenen Unterverzeichnissen um, die die Endungen .txt oder .mp3 tragen.
Wenn Dir die x Minuten Nichtverfügbarkeit akzeptabel erscheinen (x Element der Natürlichen Zahlen), dann wäre ein Cronjob die einfachste Lösung. Die Erweiterung der akzeptablen Dateiendungen sollte leicht fallen, Du könntest gegebenenfalls das Kommando auch dynamisch mittels einer Datei erstellen, die eine Liste der Dateiendungen enthält.
Alternativ könntest Du $programmiersprache nutzen, was ich hier nicht für notwendig erachte :-)
Freundliche Grüße
Vinzenz
Hallo Vinzenz,
vielleicht habe ich mich nicht ganz klar ausgedrückt.
Daher brauch ich jetzt ne andere Lösung und dachte mir, die Dateinamen sobald sie auf dem Dateisystem liegen um die Endung zu beschneiden. Aber: Wie mach ich sowas sinnvoll?
ich habe folgende Vermutungen:
- alle Dateien liegen im gleichen Verzeichnis (eventuell mit Unterverzeichnissen).
Jede hochgeladene Datei liegt in Ihrem eigenen Unterverzeichnis innerhalb des "Upload-Verzeichnisses", also in der Art:
/<upload>/<[0-9]{5}>/data.<endung>, das Download-Skript sucht aber nach /<upload>/<[0-9]{5}>/data
- die Dateien haben "handelsübliche" Endungen, d.h. es ist eine bekannte Menge.
Wieso wäre das wichtig? Ich dachte da an einen einfachen Substring des Dateinamens bis zum letzten Punkt exklusive.
Ist ein Cron-Job für sowas das geeignete Mittel?
Wenn Du eine Minute Unerreichbarkeit akzeptieren kannst.
Eine Minute Unerreichbarkeit des Servers oder der Datei nach Upload? Falls du zweites meintest, wäre dies auch das Intervall welches du für den Cron-Job vorschlägst? Eine Minute?
Gibt es unter Linux Tools, denen man sowas beibringen kann?
Ja, mv (in Verbindung z.B. mit find)
Hmmm, schon klar ,-) Ich meinte auch nicht, ein 'tool' welches mir den Dateinamen umbenennt, sondern dachte da eher an sowas wie einen "Listener", dem ich sagen kann dass er ein bestimmtes Verzeichnis auf Änderungen überwachen soll und bei einer Änderung instantan ein von mir anzugebenes Skript/Einzeiler lostritt. Mir passt halt die Idee mit dem Cron-Job nicht: Entweder die Datei ist für X Minuten nicht erreichbar, oder der Cron-Job arbeitet alle 5 Sekunden obwohl nur einmal pro Woche ne Datei hochgeladen wird.
Gibt es irgendeine Möglichkeit den Apache zu veranlassen, nach jedem Upload ein Shell-Skript anzuwerfen?
Äh, das Uploadskript des CMS. Allerdings willst Du das nicht tun, weil Du bei Updates erneut patchen müsstest.
Schon klar, ich meinte daher auch konkret den Apache, ob der z.B. sowas wie einen Upload-Listener hat.
Natürlich könntest Du auch einen kleinen Prozess als Dämon im Hintergrund laufen lassen, der in einem von Dir vorgegebenem Intervall die betroffene Verzeichnishierarchie auf neue Dateien überprüft und diese dann entsprechend umbenennt, wieder ein Intervall schläft, ...
Was doch identisch mit einem Cron-Job wäre, oder nicht?
Ich frag mich halt z.B. wie ein grafischer Dateimanager wie Nautilus oder Konquerer das machen. Wenn ich an der Konsole z.B. eine Datei hinzufüge und im Dateimanager das Verzeichnis geöffnet habe, wird die Datei auch fast synchron in der GUI angezeigt. Läuft da auch ein Prozess des Dateimanagers der jede Sekunde den Inhalt des Verzeichnisses aktualisiert oder wird der Dateimanager vom Dateisystem irgedwie "informiert" dass etwas hinzugekommen ist?
Ich weiß ja nicht ob ich mich jetzt richtig ausgedrückt habe, aber hoffe dass es doch eine bessere Möglichkeit gibt als einen Cron-Job oder Dämon mit hysterischem Schlaf-Wach-Rythmus.
Beste Grüße
Biesterfeld
Hallo Biesterfeld,
/<upload>/<[0-9]{5}>/data.<endung>, das Download-Skript sucht aber nach /<upload>/<[0-9]{5}>/data
siehe zweites Beispiel im zweiten Posting
- die Dateien haben "handelsübliche" Endungen, d.h. es ist eine bekannte Menge.
Wieso wäre das wichtig? Ich dachte da an einen einfachen Substring des Dateinamens bis zum letzten Punkt exklusive.
Äh, ja, wenn es nur einen einzigen Punkt gibt, dann geht das.
Aber wenn es zwei Punkte gibt, was dann?
Erste Runde: erste Endung wird abgeschnitten
Zweite Runde: zweite Endung wird abgeschnitten
Also: Gibt es nun genau einen Punkt, dann brauchen wir nur diesen zu finden.
Da ich das CMS nicht kenne, Du aber, solltest Du diese Information liefern können.
Eine Minute Unerreichbarkeit des Servers oder der Datei nach Upload? Falls du zweites meintest, wäre dies auch das Intervall welches du für den Cron-Job vorschlägst? Eine Minute?
Zweites. Eine Minute ist das kürzeste Intervall, dass Du beim Cron-Job nutzen kannst.
Gibt es unter Linux Tools, denen man sowas beibringen kann?
Hmmm, schon klar ,-) Ich meinte auch nicht, ein 'tool' welches mir den Dateinamen umbenennt, sondern dachte da eher an sowas wie einen "Listener", dem ich sagen kann dass er ein bestimmtes Verzeichnis auf Änderungen überwachen soll und bei einer Änderung instantan ein von mir anzugebenes Skript/Einzeiler lostritt.
Sorry, aber was macht dieser "Listener" anderes, als das Dateisystem zu befragen, ob was hinzugekommen ist? Nichts.
Natürlich könntest Du auch einen kleinen Prozess als Dämon im Hintergrund laufen lassen, der in einem von Dir vorgegebenem Intervall die betroffene Verzeichnishierarchie auf neue Dateien überprüft und diese dann entsprechend umbenennt, wieder ein Intervall schläft, ...
Was doch identisch mit einem Cron-Job wäre, oder nicht?
Nein, der Cron-Job wird im vorgegebenen Takt aufgerufen, der Daemon hingegen läuft die ganze Zeit durch.
Ich frag mich halt z.B. wie ein grafischer Dateimanager wie Nautilus oder Konquerer das machen. Wenn ich an der Konsole z.B. eine Datei hinzufüge und im Dateimanager das Verzeichnis geöffnet habe, wird die Datei auch fast synchron in der GUI angezeigt. Läuft da auch ein Prozess des Dateimanagers der jede Sekunde den Inhalt des Verzeichnisses aktualisiert
sehr wahrscheinlich.
oder wird der Dateimanager vom Dateisystem irgedwie "informiert" dass etwas hinzugekommen ist?
Das bezweifle ich sehr. Wozu sollte das Dateisystem so etwas machen?
Ich weiß ja nicht ob ich mich jetzt richtig ausgedrückt habe, aber hoffe dass es doch eine bessere Möglichkeit gibt als einen Cron-Job oder Dämon mit hysterischem Schlaf-Wach-Rythmus.
Was heißt hysterischer Schlaf-Wach-Rhythmus?
Ein Cron-Job, wie oben erwähnt, startet zu bestimmten Zeiten, das Minimalintervall ist eine Minute. Ein Daemon kann halt feiner dosiert werden, das muss doch nicht hysterisch sein.
Freundliche Grüße
Vinzenz
Hej,
/<upload>/<[0-9]{5}>/data.<endung>, das Download-Skript sucht aber nach /<upload>/<[0-9]{5}>/data
siehe zweites Beispiel im zweiten Posting
Was mir wieder ewiges rumprobieren abgenommen hat. Vielen Dank.
- die Dateien haben "handelsübliche" Endungen, d.h. es ist eine bekannte Menge.
Wieso wäre das wichtig? Ich dachte da an einen einfachen Substring des Dateinamens bis zum letzten Punkt exklusive.
Äh, ja, wenn es nur einen einzigen Punkt gibt, dann geht das.
Aber wenn es zwei Punkte gibt, was dann?
Erste Runde: erste Endung wird abgeschnitten
Zweite Runde: zweite Endung wird abgeschnitten
Au Backe da hab ich gar nicht dran gedacht.
Also: Gibt es nun genau einen Punkt, dann brauchen wir nur diesen zu finden.
Da ich das CMS nicht kenne, Du aber, solltest Du diese Information liefern können.
Ach ne ... richtig, da die Dateinamen alle data.<endung> als Endung haben, haben wir genau einen Punkt. Geht also doch.
Eine Minute Unerreichbarkeit des Servers oder der Datei nach Upload? Falls du zweites meintest, wäre dies auch das Intervall welches du für den Cron-Job vorschlägst? Eine Minute?
Zweites. Eine Minute ist das kürzeste Intervall, dass Du beim Cron-Job nutzen kannst.
Achja, richtig.
Gibt es unter Linux Tools, denen man sowas beibringen kann?
Hmmm, schon klar ,-) Ich meinte auch nicht, ein 'tool' welches mir den Dateinamen umbenennt, sondern dachte da eher an sowas wie einen "Listener", dem ich sagen kann dass er ein bestimmtes Verzeichnis auf Änderungen überwachen soll und bei einer Änderung instantan ein von mir anzugebenes Skript/Einzeiler lostritt.Sorry, aber was macht dieser "Listener" anderes, als das Dateisystem zu befragen, ob was hinzugekommen ist? Nichts.
Nuja, er würde darauf warten vom Dateisystm ins Ohr geflüstert zu bekommen "Es hat sich was in Verzeichnis XY geändert". Hab ich mir halt so gedacht. Hab ich wohl falsch gedacht. :-)
Natürlich könntest Du auch einen kleinen Prozess als Dämon im Hintergrund laufen lassen, der in einem von Dir vorgegebenem Intervall die betroffene Verzeichnishierarchie auf neue Dateien überprüft und diese dann entsprechend umbenennt, wieder ein Intervall schläft, ...
Was doch identisch mit einem Cron-Job wäre, oder nicht?
Nein, der Cron-Job wird im vorgegebenen Takt aufgerufen, der Daemon hingegen läuft die ganze Zeit durch.
So, das ist genau das was ich brauche. Jetzt fehlt mir nur noch ein kleines Dateiwissen: Muss ich den Schlaf-Wach-Rythmus eines solchen Dämonskriptes selber verwalten? Oder gibt es so eine Art Superdämon, der das ganze besser verwaltet?
Ein Daemon kann halt feiner dosiert werden, das muss doch nicht hysterisch sein.
Z.B. so:
#!/bin/bash
while true ; do for i in $(find ./ -regex .*data\..*) ; do mv $i ${i%.*}; done; sleep 2s; done
?
Vielen Dank für die Hilfe
Biesterfeld
Hi Vinzenz,
Äh, ja, wenn es nur einen einzigen Punkt gibt, dann geht das.
Aber wenn es zwei Punkte gibt, was dann?
Erste Runde: erste Endung wird abgeschnitten
Zweite Runde: zweite Endung wird abgeschnitten
Warum nicht einfach einen Link auf die korrekt benannte Datei erzeugen? Ein symbolischer Link müsste in den meisten Fällen ja reichen, falls das CMS damit nicht zurecht kommt, dann eben ein Hardlink. Aber so würde man wenigstens die korrekt benannte Datei im System behalten und wenn das CMS diesen Bug mal gefixed kriegt, hat man nicht die Arbeit, allen Dateien eine Dateiendung geben zu müssen ;-)
oder wird der Dateimanager vom Dateisystem irgedwie "informiert" dass etwas hinzugekommen ist?
Das bezweifle ich sehr. Wozu sollte das Dateisystem so etwas machen?
Ich hatte im Kopf, dass es unter Linux entsprechende Hooks im Kernel gibt, mit denen du dich über Änderungen im Dateisystem informieren lassen kannst. Nach einer kurzen Recherche bin ich auf Inotify gestoßen und habe u.a. auch noch diesen Artikel dazu gefunden.
Vielleicht hilft euch das ja weiter, mit dem dort erwähnten Tool inotifywait könnte man vermutlich auf ein create-Event in dem Upload-Ordner warten. Geht natürlich alles nur, wenn das auf dem Zielserver auch verfügbar ist ;-)
Viele Grüße,
~ Dennis.
Hallo Dennis,
Äh, ja, wenn es nur einen einzigen Punkt gibt, dann geht das.
Aber wenn es zwei Punkte gibt, was dann?
Erste Runde: erste Endung wird abgeschnitten
Zweite Runde: zweite Endung wird abgeschnittenWarum nicht einfach einen Link auf die korrekt benannte Datei erzeugen? Ein symbolischer Link müsste in den meisten Fällen ja reichen, falls das CMS damit nicht zurecht kommt, dann eben ein Hardlink. Aber so würde man wenigstens die korrekt benannte Datei im System behalten und wenn das CMS diesen Bug mal gefixed kriegt, hat man nicht die Arbeit, allen Dateien eine Dateiendung geben zu müssen ;-)
mir ist das ehrlich gesagt egal :-) Ich brauch's ja nicht.
Ein Hardlink ist (in meinen Augen) die bessere Idee. Wozu ein symbolischer Link _im gleichen Verzeichnis_ auf die gleiche Datei. Das erscheint mir nicht sinnvoll.
oder wird der Dateimanager vom Dateisystem irgedwie "informiert" dass etwas hinzugekommen ist?
Das bezweifle ich sehr. Wozu sollte das Dateisystem so etwas machen?
Ich hatte im Kopf, dass es unter Linux entsprechende Hooks im Kernel gibt, mit denen du dich über Änderungen im Dateisystem informieren lassen kannst. Nach einer kurzen Recherche bin ich auf Inotify gestoßen und habe u.a. auch noch diesen Artikel dazu gefunden.
Danke für die Infos. Wieder etwas dazugelernt. Ich weiß zwar immer noch nicht, warum man so etwas wirklich haben möchte, die positiven Blogkommentare haben mich nicht überzeugen können. "Ende der Vernunft" passt da richtig ;-)
Freundliche Grüße
Vinzenz
Hi Vinzenz,
Ich hatte im Kopf, dass es unter Linux entsprechende Hooks im Kernel gibt, mit denen du dich über Änderungen im Dateisystem informieren lassen kannst. Nach einer kurzen Recherche bin ich auf Inotify gestoßen und habe u.a. auch noch diesen Artikel dazu gefunden.
Danke für die Infos. Wieder etwas dazugelernt. Ich weiß zwar immer noch nicht, warum man so etwas wirklich haben möchte, die positiven Blogkommentare haben mich nicht überzeugen können. "Ende der Vernunft" passt da richtig ;-)
Nun ja, stell dir mal vor, du hast 10 Applikationen, welche unabhängig voneinander laufen und welche alle etwas machen wollen, wenn in einem bestimmten Verzeichnis eine neue Datei angelegt wird. Nutzt du dafür herkömmliche Methoden, wie du sie erwähnst, also Verzeichnis regelmäßig öffnen, Einträge einlesen und mit einer Liste der Einträgen vom letzten Auslesen vergleichen, dann ist das meines Erachtens nicht gerade förderlich für die Performance.
Wenn jetzt auch noch jede dieser Applikationen nicht mit einer Verzögerung von 1 Minute leben kann, sondern das Verzeichnis jede Sekunde auslesen will, dann hast du auf deinem Server in jeder Sekunde die gleiche stupide Aktion 10 mal ausgeführt, wobei doch einmal reichen würde. Außerdem erwähnte ich ja bereits, dass du irgendwie im Speicher ein Abbild haben musst, wie das Verzeichnis beim letzten Einlesen aussah, denn sonst kannst du ja nicht feststellen, ob eine Datei gerade erstellt worden ist oder nicht. Auch wenn das wohl eher nur marginal ist, aber mehr Arbeitsspeicher wird also auch noch benötigt, obwohl letztlich überall nur dasselbe drin steht. ;-)
Hingegen sehe ich da inotify klar im Vorteil, ich habe mir das jetzt vermutlich auch nicht genauer angeguckt als du es wahrscheinlich hast *g* aber dieses Ding scheint mir ja als Kernelmodul implementiert zu sein. Somit muss dieses Programm eben nicht regelmäßig das überwachte Verzeichnis auslesen, sondern hängt sich einfach in z.B. die Prozedur des Datei-Anlegens im Kernel ein. Sprich der Kernel legt eine Datei an (weil irgendwo der Befehl dazu gegeben wurde) und löst dann gleichzeitig noch das inotify Event aus. Ergo hast du keine Rechenleistung verschwendet, ohne das etwas passiert und du hast auch keine Abbilder der Verzeichnisse im Speicher.
Viele Grüße,
~ Dennis.
Hallo Vinzenz, hallo Dennis,
also vielen Dank euch beiden. Ich hab mich jetzt tatsächlich für die Lösung mit inotify entschieden. Dies aus zwei Gründen:
Erstens will mir das Prinzip eher einleuchten, nur auf ein Event hin auch eine Aktion vorzunehmen. Zweitens kann ich so ganz gezielt nur die hinzugekommene Datei behandeln.
Das Shell-Skript sieht nun so aus:
#!/bin/bash
OBSERVED_DIR=/var/egroupware/default/files/mydms
DELAY=2s
# Wait for created files and folders in $OBSERVED_DIR
while message=`inotifywait -r -e CREATE $OBSERVED_DIR`;
do
# A file was created
if [ -z `echo $message | grep ISDIR | sed 's/ //g'` ]
then
# Removing the CREATE -Message gives the /path/to/file
f=`echo $message | sed 's/ CREATE //'`;
# Make the hard-link
ln $f ${f%.*};
# A folder was created
else
# wait $DELAY just to make sure the file is created;
# assume that if the file is not created yet, inotifywait is listening
# again for its creation
sleep $DELAY;
# Removing the CREATE,ISDIR -Message gives the /path/to/folder
dir=`echo $message | sed 's/ CREATE,ISDIR //'`;
# find all data.* files in the new Folder
for f in $(find $dir -regex ".*data\..*$");
do
# Make the hard-link
ln $f ${f%.*} ;
done
fi
done
Gestartet wird das Skript durch sudo su www-data -c <skript.sh>. Am besten als Runlevel-Prozess. Vielleicht hilft es in der Zukunft auch anderen mit ähnlichem Problem.
Ich bin zwar noch nicht ganz zufrieden damit, da genau für mein Problem ein bekanntes Problem bei inotifywait -r greift, nämlich dass Order und Inhalt so kurz hintereinander erstellt werden, dass das Erzeugen des Inhaltes u.U. nicht verfolgt wird, aber das hab ich ja nun durch den else-Abschnitt behoben.
Nochmal vielen Dank, wieder recht viel über Linux in den letzten 24 Stunden gelernt.
Beste Grüße
Biesterfeld