Dateien unter Linux Verschieben

Stevi

Member
Themenstarter
Registriert
18 Juli 2018
Beiträge
166
Moin zusammen,

ich stehe gerade vor folgendem Problem:

Ich möchte Dateien unter Linux per Script von einer Ordnerstruktur in eine andere verschieben, dabei soll die Ordnerstruktur beibehalten werden.

Es wird von einem Scanner auf eine Netzwerkfreigabe "Input\A\1" oder "Input\B\2" oder "Input\C\1\XY" usw. eingescannt. Nun sollen die PDF Dokumente von z.B. "Input\A\1\xyz.pdf" nach "work\A\1\xyz.pdf" alle 60 Sekunden verschoben werden, damit Tesseract drüber laufen kann.

Grundsätzlich hat das mit folgendem Script funktioniert: (Das Script läuft von morgens bis Abends in Dauerschleife und wird um 00:10 per Crontab noch mal gestartet)

Code:
#!/bin/bash
while /bin/true; do

        start_date=$(date "+%d-%m-%Y")
        current_date=$start_date
        
        while [ "$start_date" = "$current_date" ]; do
                sleep 1m
                        
                cp -r /mnt/ocr/input/* /mnt/ocr/tesseractwork/
                find /mnt/ocr/input -name '*.pdf' -delete
                    
                /home/xyz/OCRmyFiles.sh
                current_date=$(date "+%d-%m-%Y")
        done
done
exit

Problem hierbei ist das es doch häufiger vorkommt das genau in dem Moment gescannt wird, während der cp Befehl läuft und dann der Löschbefehl. Somit wurde das PDF Dokument noch nicht verschoben aber im nächsten Schritt schon gelöscht.

Das gleiche Passiert wenn ich die Dateien gar nicht in ein "work" Folder für tesseract kopiere, wenn tesseract läuft und es kommt ein neues PDF Dokument vom Scanner, wird am Ende von tesseract auch das Dokument gelöscht. Daher mein Ansatz mit dem work Folder.

Vlt. hat ja jemand eine Idee wie sich das ohne großen Aufwand realisieren lässt? Am besten wäre ein mv Befehl. Hier scheitert es aber daran das die Ordnerstruktur mit allen Unterordnern beibehalten werden muss.
 
Hallo zwieblum, da hast du natürlich recht. Ich habe mich falsch ausgedrückt. Ich meine natürlich nicht das der Grep-Befehl einen Bug hat, sondern das es z.B. einen Syntaxfehler oder Schreibfehler oder was auch immer in diesem Script sein muss. Etwas was ich wohl trotz Prüfung übersehen habe.

Code:
root@XYZ-OCR:/home/XYZ# inotifywait -r -m /home/konicaminolta
Setting up watches.  Beware: since -r was given, this may take a while!
Watches established.
/home/konicaminolta/Ordner1/ OPEN,ISDIR Eingang
/home/konicaminolta/Ordner1/Eingang/ OPEN,ISDIR
/home/konicaminolta/Ordner1/ ACCESS,ISDIR Eingang
/home/konicaminolta/Ordner1/Eingang/ ACCESS,ISDIR
/home/konicaminolta/Ordner1/ ACCESS,ISDIR Eingang
/home/konicaminolta/Ordner1/Eingang/ ACCESS,ISDIR
/home/konicaminolta/Ordner1/ CLOSE_NOWRITE,CLOSE,ISDIR Eingang
/home/konicaminolta/Ordner1/Eingang/ CLOSE_NOWRITE,CLOSE,ISDIR
/home/konicaminolta/ OPEN,ISDIR Ordner1
/home/konicaminolta/Ordner1/ OPEN,ISDIR
/home/konicaminolta/ CLOSE_NOWRITE,CLOSE,ISDIR Ordner1
/home/konicaminolta/Ordner1/ CLOSE_NOWRITE,CLOSE,ISDIR
/home/konicaminolta/ OPEN,ISDIR Ordner1
/home/konicaminolta/Ordner1/ OPEN,ISDIR
/home/konicaminolta/ ACCESS,ISDIR Ordner1
/home/konicaminolta/Ordner1/ ACCESS,ISDIR
/home/konicaminolta/ ACCESS,ISDIR Ordner1
/home/konicaminolta/Ordner1/ ACCESS,ISDIR
/home/konicaminolta/ CLOSE_NOWRITE,CLOSE,ISDIR Ordner1
/home/konicaminolta/Ordner1/ CLOSE_NOWRITE,CLOSE,ISDIR
/home/konicaminolta/ OPEN,ISDIR
/home/konicaminolta/ CLOSE_NOWRITE,CLOSE,ISDIR
/home/konicaminolta/ OPEN,ISDIR
/home/konicaminolta/ ACCESS,ISDIR
/home/konicaminolta/ CLOSE_NOWRITE,CLOSE,ISDIR
/home/konicaminolta/ OPEN,ISDIR
/home/konicaminolta/ CLOSE_NOWRITE,CLOSE,ISDIR
/home/konicaminolta/ OPEN,ISDIR
/home/konicaminolta/ CLOSE_NOWRITE,CLOSE,ISDIR
/home/konicaminolta/Ordner1/ CLOSE_NOWRITE,CLOSE,ISDIR Eingang
/home/konicaminolta/Ordner1/Eingang/ CLOSE_NOWRITE,CLOSE,ISDIR
/home/konicaminolta/Ordner1/ CLOSE_NOWRITE,CLOSE,ISDIR Eingang
/home/konicaminolta/Ordner1/Eingang/ CLOSE_NOWRITE,CLOSE,ISDIR
/home/konicaminolta/Ordner1/ OPEN,ISDIR Eingang
/home/konicaminolta/Ordner1/Eingang/ OPEN,ISDIR
/home/konicaminolta/Ordner1/ ACCESS,ISDIR Eingang
/home/konicaminolta/Ordner1/Eingang/ ACCESS,ISDIR
/home/konicaminolta/Ordner1/ ACCESS,ISDIR Eingang
/home/konicaminolta/Ordner1/Eingang/ ACCESS,ISDIR
/home/konicaminolta/Ordner1/ CLOSE_NOWRITE,CLOSE,ISDIR Eingang
/home/konicaminolta/Ordner1/Eingang/ CLOSE_NOWRITE,CLOSE,ISDIR
/home/konicaminolta/Ordner1/Eingang/ CREATE SXYZ Printe21012914170_0019 - Copy.pdf
/home/konicaminolta/Ordner1/Eingang/ OPEN SXYZ Printe21012914170_0019 - Copy.pdf
/home/konicaminolta/Ordner1/ OPEN,ISDIR Eingang
/home/konicaminolta/Ordner1/Eingang/ OPEN,ISDIR
/home/konicaminolta/Ordner1/ CLOSE_NOWRITE,CLOSE,ISDIR Eingang
/home/konicaminolta/Ordner1/Eingang/ CLOSE_NOWRITE,CLOSE,ISDIR
/home/konicaminolta/ OPEN,ISDIR Ordner1
/home/konicaminolta/Ordner1/ OPEN,ISDIR
/home/konicaminolta/ CLOSE_NOWRITE,CLOSE,ISDIR Ordner1
/home/konicaminolta/Ordner1/ CLOSE_NOWRITE,CLOSE,ISDIR
/home/konicaminolta/Ordner1/Eingang/ MODIFY SXYZ Printe21012914170_0019 - Copy.pdf
/home/konicaminolta/Ordner1/Eingang/ ATTRIB SXYZ Printe21012914170_0019 - Copy.pdf
/home/konicaminolta/Ordner1/Eingang/ ATTRIB SXYZ Printe21012914170_0019 - Copy.pdf
/home/konicaminolta/Ordner1/Eingang/ MODIFY SXYZ Printe21012914170_0019 - Copy.pdf
/home/konicaminolta/Ordner1/Eingang/ ATTRIB SXYZ Printe21012914170_0019 - Copy.pdf
/home/konicaminolta/Ordner1/Eingang/ CLOSE_WRITE,CLOSE SXYZ Printe21012914170_0019 - Copy.pdf
/home/konicaminolta/Ordner1/ OPEN,ISDIR Eingang
/home/konicaminolta/Ordner1/Eingang/ OPEN,ISDIR
/home/konicaminolta/Ordner1/ CLOSE_NOWRITE,CLOSE,ISDIR Eingang
/home/konicaminolta/Ordner1/Eingang/ CLOSE_NOWRITE,CLOSE,ISDIR
/home/konicaminolta/Ordner1/ OPEN,ISDIR Eingang
/home/konicaminolta/Ordner1/Eingang/ OPEN,ISDIR
/home/konicaminolta/Ordner1/ OPEN,ISDIR Eingang
/home/konicaminolta/Ordner1/Eingang/ OPEN,ISDIR
/home/konicaminolta/Ordner1/ CLOSE_NOWRITE,CLOSE,ISDIR Eingang
/home/konicaminolta/Ordner1/Eingang/ CLOSE_NOWRITE,CLOSE,ISDIR
/home/konicaminolta/Ordner1/ OPEN,ISDIR Eingang
/home/konicaminolta/Ordner1/Eingang/ OPEN,ISDIR
/home/konicaminolta/ OPEN,ISDIR
/home/konicaminolta/ CLOSE_NOWRITE,CLOSE,ISDIR
/home/konicaminolta/ OPEN,ISDIR
/home/konicaminolta/ CLOSE_NOWRITE,CLOSE,ISDIR
/home/konicaminolta/Ordner1/ OPEN,ISDIR Eingang
/home/konicaminolta/Ordner1/Eingang/ OPEN,ISDIR
/home/konicaminolta/Ordner1/ CLOSE_NOWRITE,CLOSE,ISDIR Eingang
/home/konicaminolta/Ordner1/Eingang/ CLOSE_NOWRITE,CLOSE,ISDIR
/home/konicaminolta/Ordner1/ OPEN,ISDIR Eingang
/home/konicaminolta/Ordner1/Eingang/ OPEN,ISDIR
/home/konicaminolta/Ordner1/ ACCESS,ISDIR Eingang
/home/konicaminolta/Ordner1/Eingang/ ACCESS,ISDIR
/home/konicaminolta/Ordner1/ ACCESS,ISDIR Eingang
/home/konicaminolta/Ordner1/Eingang/ ACCESS,ISDIR
/home/konicaminolta/Ordner1/ CLOSE_NOWRITE,CLOSE,ISDIR Eingang
/home/konicaminolta/Ordner1/Eingang/ CLOSE_NOWRITE,CLOSE,ISDIR
 
Na siehste, geht doch :)

Du bist hinter dieser Zeile her:
Code:
/home/konicaminolta/Ordner1/Eingang/ CLOSE_WRITE,CLOSE SXYZ Printe21012914170_0019 - Copy.pdf

... und ich böser Mensch hab' dir Unterschlagen, nur den Filenamen extrahierst - na, war wohl schon spät .... Ginge z.B. so:

Code:
inotifywait -r -m /home/konicaminolta | grep 'CLOSE_WRITE,CLOSE' | cut -d ' ' -f 3- | while read a; do echo $a; done

das sollte nur die Dateinamen auswerfen ... bis jemand auf die schlaue Idee kommt, Leerzeichen in Verzeichnisnamen zu packen. Ah ja, $a kann jetzt auch Leerzeichen enthalten und du musst dich darum kümmern, dass die nicht von der Shell als einzelen Parameter genommen werden, z.B. mit "$a" ... aber da gibt's ja ein Manual :)

Eigendlich müsste dir das Script eine liste von Fehlermeldungen ausgeben, wenn du's auf der Konsole startest und eine Datei erzeugst.
 
Zuletzt bearbeitet:
Code:
#!/bin/bash

SRC=/home/foo
DST=/home/bar
PATTERN="*.img"

for FILE in $( find ${SRC} -name "${PATTERN}" 2> /dev/null ); do
    [ -z $(fuser ${FILE} 2> /dev/null) ] && cp -p ${FILE} ${DST}
done
 
Ja schon, aber find findet nicht nur Dateien, wenn sie bereits geschlossen sind, sonder sobald sie erzeugt wurden.
 
ich habe das Problem nun erfolgreich wie folgt lösen können:

Code:
#!/bin/bash

        inotifywait --format "%w%f" --event close_write -r -m /home/konicaminolta | while read a; do

                ordnername=$(echo $(dirname "$a" | cut -d '/' -f 4-))
                mkdir -p /home/tesseract/"$ordnername"
                mv "$a" /home/tesseract/"$ordnername"
                rm "$a"
                /home/<sshuser>/OCRmyFiles.sh

        done
exit

dieser Teil ist abhängig von der Ordnerstruktur und muss individuell angepasst werden, wobei "-f 4-" die Stelle des "/" angibt.

Code:
ordnername=$(echo $(dirname "$a" | cut -d '/' -f 4-))

Danke an alle für die tolle Unterstützung und das schubsen in die richtige Richtung :)
 
Frage:
Wäre es nicht sinnvoller, mit "lsof" zu arbeiten?

Was passiert mit Dateien, die schon bei Aufruf von inotifywait existieren? - Diese werde nie berücksichtigt.

Baue ich mir hingegen mit lsof <pfad>/* eine Schleife, die wartet, bis kein Prozess zurückgegeben wird, kann ich sicher gehen, dass derzeit kein Schreibvorgang stattfindet und Dateien, die bei Skriptstart schon existierten, werden ebenfalls verschoben.

inotifywait hingegen behandelt nir Dateien, die es selbst auch durch die angegebene Zugriffsart(en) registriert. Liegt eine geschlossene Datei bereits im Verzeichnis, bemerkt inotifywait diese nicht. Einfach vorher wegkopieren ist aber auch nicht sinnvoll, da man nicht weiß, of sie vielleicht gerade geschrieben wird.

Möglich wäre z.B.:
Code:
#!/bin/sh
zielordner="/irgendwas/"
quellordner="/home/konicaminolta/"
a=`lsof $quellordner* 2>/dev/null |grep REG|awk '{print $2}' ` # PID der Prozesse sammeln, die auf Quelldateien zugreifen - lsof Type: REG
if [ -z "$a" ]; then
  echo "PID-Array empty"                                       # Keine Prozesse laufen
  for file in $quellordner*; do                                # wenn Dateien existieren, dann kopieren
    if [ -f $file ]; then
      echo "cp <quelldatei> <ziel>"
      cp "$file" "$zielordner" && rm "$file"                   # kopieren und wenn erfolgreich, auch löschen
    fi
  done
  fi
else
  echo "PID-Array non empty"                                   # es läuft gerade ein Prozess, der auf Dateien im Pfad zugreift
fi
 
Zuletzt bearbeitet:
Nicht ganz. inotifywait kriegt reagiert auf alle Änderungen. Pobier mal:

Code:
mkdir -p /tmp/x; cd /tmp/x; inotifywait -m . & (sleep 3; touch test; sleep 3; touch test; sleep 1; echo hallo >> test; sleep 3; rm test; killall inotifywait);

Wenn existierende Dateien ein Problem darstellen - so die überhaupt existieren - dann läßt sich auch einfach lösen.


Loop mit "lsof" ist eine ausgesprochen schlecht Idee, weil das nur offene Dateien zu einem Zeitpunkt findet.
 
Guter Hinweis, auch wenn kaum Zeit besteht, zwischen "lsof" und "for file in $quellordner*;" eine neue Datei zu erzeugen.
Ich lasse dieses als Cron-Job ohne Loop alle 5 Minuten laufen.
Dein Beispiel versuche ich mal umzusetzen.
 
Zuletzt bearbeitet:
Oh, ich vergaß: Ein verstorbener Prozess, der einen Filehandle im besagten Verzeichnis offen hält, ist in deinem Beispiel ein echtes Problem. z.B. ein Spaßvogel mit Texteditor, oder ein lustiges "sleep 99999d>/in/das/besagte/verzeichnis/eine/.datei" :)
 
... aber wozu das "rm" nach "mv"?

guter Einwand, wird entfernt :)

bei dem Ding
Code:
ordnername=$(echo $(dirname "$a" | cut -d '/' -f 4-))
gibt's aber auch einiges zu optimieren

tu dir keinen Zwang an ;)


Was passiert mit Dateien, die schon bei Aufruf von inotifywait existieren? - Diese werde nie berücksichtigt.

sehr gute Frage. Sollte im besten Falle ja gar nicht vorkommen in meiner Konstellation. Denkbar wäre das mein Script oder der Server hängen bleibt
und dann im Input Ordner unbearbeitete PDF's liegen bleiben.

Mein Script läuft ja per crontab -e mit dem Eintrag "@reboot" mit 60 Sekunden Verzögerung.
Jetzt könnte ich solche Fälle noch mit einem "@reboot" 30 Sekunden Verzögerung abfangen, also
bevor das Script mit inotifywait in Dauerschleife geht.
 
Egal wie früh das Programm gestartet wird, es können immer Dateien im Ordner liegen (meistens vom Sysadmin dor hin gestellt, weil ein User meint da feht was, worauf hin sich der Sysadmin lange fragt warum die Dateine nicht verschwinden ...) also lieber zuerst alle vorhandenen Dateien weiterreichen, dann Überwachung starten und ganz zum Schluss jenen Prozess, der es dem User erlaubt, Dateien abzulegen.
Code:
ordnername=$(echo $(dirname "$a" | cut -d '/' -f 4-))
Code:
ordnername=$(basename $(dirname "$a"))
ordnername=$(echo "$a" | cut -d / -f 3)
...
 
Ich habe eure Anmerkungen noch mal versucht umzusetzen und das Script ein wenig übersichtlicher gestaltet. Falls euch noch was einfällt was ich nicht beachtet habe, gerne kommentieren ;)

Code:
#!/bin/bash

        #Variablen:
        #info = inputfolder, oufo = outputfolder, fpath = filepath, fname = filename
        #tessscript = OCRMyFiles.sh Path, dd =  directory deep (wie viele Slashs bis zum Dateinamen)

        info=/home/tesseract/input
        oufo=/home/tesseract/work
        tessscript=/home/tesseract/OCRmyFiles.sh
        dd=5

        #Beim start des Scripts werden alle ggf. noch vorhandenen Dateien in den Tesseract work Ordner verschoben
        #und anschließend Tesseract einmalig ausgeführt.

        mv $info/*.pdf $oufo/"$fname"
        /bin/bash $tessscript;

        #Anschließend startet die Überwachung des Input Ordners mittels inotifywait in Endlossschleife
        #Das Event close_write führt zur Ausführung der Verschiebung der neuen Datei in den work Ordner.

        inotifywait --format "%w%f" --event close_write -r -m $info | while read fpath; do

                fname=$("$fpath" | cut -d '/' -f $dd-)

                #Verschieben der neuen Datei in den work Ordner von Tesseract

                mv "$fpath" $oufo/"$fname"

                #Ausführung von Tesseract

                /bin/bash $tessscript;

        done
exit
 
Zuletzt bearbeitet:
Ich habe eure Anmerkungen noch mal versucht umzusetzen und das Script ein wenig übersichtlicher gestaltet. Falls euch noch was einfällt was ich nicht beachtet habe, gerne kommentieren ;)

Code:
inotifywait --format "%w%f" --event close_write -r -m $info | while read fpath; do

Mit welchem Style-Guide ist denn das kompatibel?

Code:
fname=$("$fpath" | cut -d '/' -f $dd-)
Wenn in fpath Dateiname mit Pfad ist, sollte basename $fpath reichen.

Eingerückt wird nur wenn Änderungen im Programmfluss erfolgen, also bei Schleifen, Bedingungen oder Funktionen/Prozeduren.

/home/tesseract/input würde mal wohl eher als /var/spool/tesseract/input anlegen.
 
  • ok1.de
  • ok2.de
  • thinkstore24.de
  • Preiswerte-IT - Gebrauchte Lenovo Notebooks kaufen

Werbung

Zurück
Oben