ubuntuusers.de

Unterschiedliche Dateien nacheinander in neues Verzeichnis kopieren

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

Kamelot

Anmeldungsdatum:
10. Mai 2013

Beiträge: Zähle...

Guten Tag Miteinander

Ich stehe momentan gerade bei folgendem Problem an und würde mich riesig über Unterstützung freuen. Mein vor geraumer Zeit erstelltes Skript geht sämtliche Dateien in einem Quellverzeichnis durch und sucht sich die Dateien raus, in welchen eine der sechs Nummernfolgen (egrep) vorkommt und das Erstelldatum von "Gestern" ist.

Die identifizierten Files werden danach in ein anderes Verzeichnis auf einem anderen Server kopiert.

Nun gibt es im Quellverzeichnis jeweils Dateipäärchen, eine Datei beginnt mit dem Namen "envl*" die andere mit "data*". Die Eingangs erwähnten Nummerfolgen kommen in beiden Dateien vor.

Jetzt müsste ich zusätzlich gewährleisten können, dass entweder alle "data*"-Files zuerst ins Zielverzeichnis oder besser das "data*"-File eines Pärchens jeweils zuerst ins Zielverzeichnis kopiert wird.

Für Tipps möchte ich mich bereits im Voraus bedanken.

quelldir=/appl/geresAdapter/sent/

datum=`date  --date="yesterday" "+%F"`

egrep -l -r ">1-4001-1<|>1-4021-1<|>1-4045-1<|>1-4141-1<|>1-4034-1<|>1-4258-1<" $quelldir | while read file; do
        dat="$(stat -c "%y" $file)"
        if [ "${dat%% *}" = "$datum" ]; then
                scp -p -q $file geres@svuaf015:/appl/sedexAdapter_aux/inbox
        fi
done

redknight Team-Icon

Moderator & Supporter
Avatar von redknight

Anmeldungsdatum:
30. Oktober 2008

Beiträge: 21850

Wohnort: Lorchhausen im schönen Rheingau

Wie wäre es mit find? EIn durchlauf für data* und eine für envl*, dann kommen die Daten auch so an wie Du es gern hättest.

Kamelot

(Themenstarter)

Anmeldungsdatum:
10. Mai 2013

Beiträge: 6

Hi redknight,

danke für Deine schnelle Antwort.

Ich versuchte im Skript ursprünglich Find zu verwenden, stiess dann aber auf die "argument list too long" Problematik, da sich im Quellverzeichnis jeweils täglich mehrere hundert bis tausend neue Files einfinden welche nach 24 Uhr (Script wird um diese Zeit von einem Cronjob ausgeführt) durchsucht werden müssen.

Hättest Du evtl. einen Lösungsansatz für mein Problem welcher mit grep / while read line funktionieren könnte?

Danke und Gruss

redknight Team-Icon

Moderator & Supporter
Avatar von redknight

Anmeldungsdatum:
30. Oktober 2008

Beiträge: 21850

Wohnort: Lorchhausen im schönen Rheingau

Kamelot schrieb:

Ich versuchte im Skript ursprünglich Find zu verwenden, stiess dann aber auf die "argument list too long" Problematik, da sich im Quellverzeichnis jeweils täglich mehrere hundert bis tausend neue Files einfinden welche nach 24 Uhr durchsucht werden müssen.

Das hat aber nichts mit der Anzahl der Files zu tun, sondern mit der Länge deines find-KOmmandos.

Hättest Du evtl. einen Lösungsansatz für mein Problem welcher mit grep / while read line funktionieren könnte?

Nö, da passe ich.

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Hi Kamelot,

erstmal willkommen hier auf dem Forum !

Ich würde auch für find plädieren, denn das kann sowohl die Namen nach Regex-en durchsuchen als auch nach Zeitabschnitten filtern.
Vielleicht solltest Du zuerst mal gucken, ob alle gewünschten Dateien richtig angezeigt werden (noch gar nicht kopiert !), und erst danach das Skript Stück für Stück weiter aufbauen.

Ich kenne Deine Datenstrukturen nun nicht, aber womöglich wäre es auch sinnvoll, dass Du find nur die data_xxxx- Dateien suchen lässt, und dann im Skript die jeweils zugehörige envl_xxxx- Datei einfach hinterherziehst ?
Auf jeden Fall solltest Du Dir man find mal sorgfältig ansehen, außerdem Dir angucken, wie man ein Tochterskript in find ... -exec einbettet und die Geschichte mit der Parameter Expansion. Mit dieser Kombination sollte Dein Vorhaben zu machen sein.

LG,

track

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13209

Kamelot schrieb:

Guten Tag Miteinander

Auch von mir ein herzliches Willkommen hier im Forum!

Mein vor geraumer Zeit erstelltes Skript geht sämtliche Dateien in einem Quellverzeichnis durch und sucht sich die Dateien raus, in welchen eine der sechs Nummernfolgen (egrep) vorkommt und das Erstelldatum von "Gestern" ist.

Du suchst die Folgen im Dateiinhalt, entnehme ich Deinem Skript.

Nun gibt es im Quellverzeichnis jeweils Dateipäärchen, eine Datei beginnt mit dem Namen "envl*" die andere mit "data*". Die Eingangs erwähnten Nummerfolgen kommen in beiden Dateien vor.

Jetzt müsste ich zusätzlich gewährleisten können, dass entweder alle "data*"-Files zuerst ins Zielverzeichnis oder besser das "data*"-File eines Pärchens jeweils zuerst ins Zielverzeichnis kopiert wird.

Das kann man recht bequem mit find lösen - das ginge sogar mit einem einzigen Aufruf, wenn man "-o" nutzt, denke ich. Das Muster für egrep kann man auch noch kompakter (und auch einen Tick effizienter) machen, denn die Alternativen enthalten sich wiederholende Teile; das sieht man, wenn man etwas umformatiert:

">1-4001-1<
|>1-4021-1<
|>1-4045-1<
|>1-4141-1<
|>1-4034-1<
|>1-4258-1<"

Was Du da mit egrep und der Pipe machst, ist verhältnismäßig unsicher. Wenn ein Zeilenumbruch in einem Dateinamen vorkommt, funktioniert es nicht. Mindestens müsstest Du egrep -lZ und read -d '' -r nutzen. Du solltest auch Deine Variablen mit Dateinamen quoten, sonst führen auch Leerzeichen in Dateinamen zu Problemen.

Zum Lösungsvorschlag: blöd ist, dass scp leider nicht die Quelldateien am Ende akzeptiert. Das wäre aber wünschenswert, denn dann könnte man mehrere Dateien mit einem Aufruf kopieren. Das ist sinnvoll, denn der Aufbau der SSL-Verbindung ist relativ teuer. Dann schlage ich doch zwei Durchläufe von find vor (ungetestet, weil ich die Dateien nicht da habe):

1
2
3
4
for pattern in 'data*' 'envl*'; do
  find /appl/geresAdapter/sent -type f -mtime 1 -name "$pattern" \
    -exec egrep -lZ '>1-4(001|021|045|141|034|258)-1<' {} +
done | xargs -r0 dash -c 'echo scp -p -q "$@" geres@svuaf015:/appl/sedexAdapter_aux/inbox' --

Ich habe ein echo eingefügt, damit Du erst mal schauen kannst, ob der Befehl die Dateien in der Reihenfolge kopiert, die Du möchtest. Wenn es klappt, lösch das "echo " aus Zeile 4 einfach raus.

Noch eine Anmerkung: das Muster für egrep kann man natürlich noch kompakter machen, aber ich wollte es nicht gleich übertreiben. ☺

Versuch bitte erst mal selber, herauszufinden, was das da oben tut. Wenn etwas unklar ist, frag einfach, dann erkläre ich es.

Ciao

robert

Kamelot

(Themenstarter)

Anmeldungsdatum:
10. Mai 2013

Beiträge: 6

Hallo track & robert,

vielen Dank für eure ausführlichen Antworten bzw. Lösungsansätze.

Für Sonntag wird bei uns eine Regen-Wahrscheinlichkeit von 83% vorher gesagt, also ideal um eure super Tipps genauer anschauen zu können 😉

Viele Grüsse aus der Schweiz und ein schönes Wochenende.

Kamelot

Kamelot

(Themenstarter)

Anmeldungsdatum:
10. Mai 2013

Beiträge: 6

Hallo robert

Ich fand heute Nachmittag die Zeit dazu Deinen Lösungsvorschlag testen zu können. Funktioniert 1A ☺

Nachfolgend habe ich nochmals Deine Lösung inkl. zwei kleiner Anpassungen aufgeführt welche es aufgrund meiner Situation zusätzlich erforderte.

for pattern in 'data*' 'envl*'; do
  find /appl/geresAdapter/sent -type f -daystart -mtime 1 -name "$pattern" \
    -exec egrep -lZ '>1-4(001|021|045|141|034|258)-1<' {} +
done | xargs -r0 bash -c 'scp -p -q "$@" geres@svuaf015:/appl/sedexAdapter_aux/inbox' --

- 2. Zeile: Habe vor -mtime 1 noch ein -daystart eingebaut damit die Files vom Vortag von 00.00 bis 23.59 Uhr berücksichtigt werden.

- 4. Zeile: dash habe ich durch bash ersetzt, da das Script nach der "Testphase" definitiv unter SLES10 laufen wird.

An dieser Stelle nochmals ganz herzlichen Dank für Deine tolle Unterstützung, sowie auch an alle anderen welche sich an der Problemlösung beteiligt haben.

Viele Grüsse und einen erholsamen Sonntag Abend.

Kamelot

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13209

Kamelot schrieb:

Ich fand heute Nachmittag die Zeit dazu Deinen Lösungsvorschlag testen zu können. Funktioniert 1A ☺

Prima! Das hat man ja auch nicht allzu oft, dass Code auf Anhieb macht, was er soll. 😬

- 2. Zeile: Habe vor -mtime 1 noch ein -daystart eingebaut damit die Files vom Vortag von 00.00 bis 23.59 Uhr berücksichtigt werden.

Oh ja, sehr guter Punkt! Das habe ich total vernachlässigt.

- 4. Zeile: dash habe ich durch bash ersetzt, da das Script nach der "Testphase" definitiv unter SLES10 laufen wird.

Ja, wenn es da keine dash gibt, muss man natürlich eine andere Shell nehmen. In dem Fall würde ich sogar noch vor das scp ein "exec " setzen. Die dash macht das als Optimierung, dass sie den letzten gestarteten Prozess per exec startet sofern das möglich ist. Aber die bash macht das meines Wissens nicht. Ist kein großes Ding, Du sparst Dir nur eine Prozesserzeugung.

$ for sh in dash bash sh; do $sh -c 'ps -l'; done
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S  1000  2838  2835  0  80   0 -  1586 wait   pts/1    00:00:00 bash
0 S  1000  3015  2838  0  80   0 -   558 wait   pts/1    00:00:00 dash
0 R  1000  3016  3015  0  80   0 -  1242 -      pts/1    00:00:00 ps
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S  1000  2838  2835  0  80   0 -  1586 wait   pts/1    00:00:00 bash
0 R  1000  3017  2838  0  80   0 -  1242 -      pts/1    00:00:00 ps
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S  1000  2838  2835  0  80   0 -  1586 wait   pts/1    00:00:00 bash
0 S  1000  3018  2838  0  80   0 -   558 wait   pts/1    00:00:00 sh
0 R  1000  3019  3018  0  80   0 -  1242 -      pts/1    00:00:00 ps 

Man sieht an dem fehlenden Shell-Prozess, dass die dash den eigenen Prozess überlagert. Wenn man es explizit macht, dann sieht es bei allen wieder gleich aus:

$ for sh in dash bash sh; do $sh -c 'exec ps -l'; done
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S  1000  2838  2835  0  80   0 -  1586 wait   pts/1    00:00:00 bash
0 R  1000  3020  2838  0  80   0 -  1242 -      pts/1    00:00:00 ps
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S  1000  2838  2835  0  80   0 -  1586 wait   pts/1    00:00:00 bash
0 R  1000  3021  2838  0  80   0 -  1242 -      pts/1    00:00:00 ps
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S  1000  2838  2835  0  80   0 -  1586 wait   pts/1    00:00:00 bash
0 R  1000  3022  2838  0  80   0 -  1242 -      pts/1    00:00:00 ps 

xargs übergibt in einem Rutsch so viele Dateinamen wie möglich an den Subprozess. Da Du ja in der Kommandozeile von scp mit der Zielangabe noch ein Argument hinzufügst, könnte es theoretisch passieren, dass die Kommandozeile zu lang wird. Wenn Du dem Fall vorbeugen willst, kannst Du xargs noch ein "-n 10000" o.ä. mitgeben. Aber das ist wirklich ein bisschen paranoid. ☺

An dieser Stelle nochmals ganz herzlichen Dank für Deine tolle Unterstützung, sowie auch an alle anderen welche sich an der Problemlösung beteiligt haben.

Bitteschön!

Viele Grüße

robert

Kamelot

(Themenstarter)

Anmeldungsdatum:
10. Mai 2013

Beiträge: 6

Hoi Robert

vielleicht magst Du Dich noch an mich und mein Skript erinnern, welches bestimmte Dateien vom Vortag, welche ein bestimmtes Pattern beinhalten via scp von einem Verzeichnis in ein anderes kopiert.

for pattern in 'data*' 'envl*'; do
  find /appl/geresAdapter/sent -type f -daystart -mtime 1 -name "$pattern" \
    -exec egrep -lZ '>1-4(001|021|045|141|034|258)-1<' {} +
done | xargs -r0 bash -c 'scp -p -q "$@" geres@svuaf015:/appl/sedexAdapter_aux/inbox' --

Ich möchte nun eine neue zusätzliche Anforderung umsetzen. Es wäre super genial, wenn Du mir für mein Vorhaben, falls Du die Zeit und Lust dazu hast, den ein oder anderen Tipp zukommen lassen könntest.

Die neue Anforderung sieht folgendermassen aus, in den Filepaaren (jeweils data & envl) im Quellverzeichnis ist jeweils das Pattern >2-AG-1< enthalten, welches ich bei den ins Zielverzeichnis kopierten Files gerne durch >T2-AG-1< ersetzen würde.

Ich weis, dass das zusätzlich einzubauende Kommando in etwa folgendermassen lauten sollte sed "s/>2-AG1</>T2-AG-1</" , kriege jedoch keine funktionierende Lösung zustande.

Besten Dank & viele Grüsse Kamelot

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Kamelot schrieb:

Die neue Anforderung sieht folgendermassen aus, in den Filepaaren (jeweils data & envl) im Quellverzeichnis ist jeweils das Pattern >2-AG-1< enthalten, welches ich bei den ins Zielverzeichnis kopierten Files gerne durch >T2-AG-1< ersetzen würde.

Ich weis, dass das zusätzlich einzubauende Kommando in etwa folgendermassen lauten sollte sed "s/>2-AG1</>T2-AG-1</" , kriege jedoch keine funktionierende Lösung zustande.

Was spricht dagegen, dafür einfach rename zu benutzen ? - in etwa so:

track@lucid:~$ touch envl02-AG-1.txt
track@lucid:~$ rename 's/(2-AG-1)/T$1/' envl*2-AG-1*
track@lucid:~$ ls envl*
envl0T2-AG-1.txt 

Du musst bei rename nur ein bisschen aufpassen, weil die dort verwendete Perl- Syntax in einigen Details etwas von der sed- Syntax abweicht.

LG,

track

Kamelot

(Themenstarter)

Anmeldungsdatum:
10. Mai 2013

Beiträge: 6

Hallo Miteinander

Ich habe heute nochmals zusammen mit einem Kollegen über dem Script gebrütet. Folgende Lösung welche ich euch selbstverständlich nicht vorenthalten möchte ist dabei rausgekommen.

#!/bin/bash

target="/appl/work/tempverzeichnis"
datum=`date  --date="yesterday" "+%F"`
transferdate=`date +"%Y%m%d"`

for pattern in 'data*' 'envl*'; do
  find /appl/geresAdapter/sent -type f -daystart -mtime 4 -name "$pattern" -exec egrep -lZ '>1-4(289)-1<' {} +
done | xargs -0 > $target/temp.txt

files=`cat $target/temp.txt`

for datei in $files; do
        dateiname=`basename $datei`
        cp -p $datei $target/$dateiname
        sed -i "s/>2-AG-1</>T2-AG-2</g" $target/$dateiname
done

datas=`ls -1 $target/data*`
for pattern in $datas; do
        echo $pattern
done | xargs -r bash -c 'scp -p -q "$@" test@svuafxxx:/appl/interfaces_ktag/xxx/inbox/test' --

envl=`ls -1 $target/envl*`
for pattern in $envl; do
        echo $pattern
done | xargs -r bash -c 'scp -p -q "$@" test@svuafxxx:/appl/interfaces_ktag/xxx/inbox/test' --

cd $target
rm *.xml

Die gewünschten Files werden identifiziert und deren Filename in einem Temp-Verzeichnis in einem Temp-File abgelegt. Die Files werden danach ins Tempverzeichnis kopiert und das entsprechende Pattern via sed gesucht und durch das Neue ersetzt. Danach werden sämtliche data* -Files sowie sämtliche envl* -Files nacheinander via scp auf den Zielserver kopiert.

Besten Dank an alle für eure Unterstützung. Viele Grüsse Kamelot

Antworten |