Hinweis: Das Forum wird geschlossen! Neue Registrierungen sind nicht mehr möglich!

 Zurück zu Pro-Linux   Foren-Übersicht   FAQ     Suchen    Mitgliederliste
Shell: verschieben der Dateien

 
Neuen Beitrag schreiben   Auf Beitrag antworten    Pro-Linux Foren-Übersicht -> Programmieren - Allgemein
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen  
Autor Nachricht
micbur



Anmeldungsdatum: 05.06.2004
Beiträge: 86

BeitragVerfasst am: 10. Okt 2005 12:11   Titel: Shell: verschieben der Dateien

Hallo,

ich habe da ein kleines Problem. Ich denke, wenn jemand mit der Bash umgehen kann, das ist es für ihn kein Problem, für mich ist es leider eines.

Ich habe in einem Verzeichnis durch logrotate ganz viele Unterverzeichnisse. Verzeichnistiefe ist maximal 1. In jedem Unterverzeichnis befinden sich verschiedene logs.
Beispiel:
$dir/subdir1/file.gz
$dir/subdir2/file.gz
$dir/subdir3/file.gz

Nun möchte ich die aber zur Weiterverarbeitung kopiert/verschoben haben, sodass der Verzeichnisname sich im Dateinamen nachher wiederfindet.
Beispiel:
$dir/file_subdir1.gz
$dir/file_subdir2.gz
$dir/file_subdir3.gz

So richtig komme ich nicht weiter.
Ich kann mir zwar alle Dateien ab einer bestimmten Verzeichnistiefe anzeigen lassen, das sogar auf verschiedenen Wegen, aber ich komme leider nicht soweit, dass ich die Dateien kopieren kann.

Entweder: find $PWD -type f -name *gz
oder:
find $PWD -depth -type d -print | while read DIR ;
do
echo $DIR;
done

Ich weiß nicht recht, wie ich mir den Verzeichnisnamen 'merken' kann, damit ich den dann weiter verwenden kann.
Es ist zwar blamabel, aber ich brauche Hilfe.

Ciao, micbur
 
Benutzer-Profile anzeigen Private Nachricht senden

jochen
prolinux-forum-admin


Anmeldungsdatum: 14.01.2000
Beiträge: 699
Wohnort: Jülich

BeitragVerfasst am: 10. Okt 2005 12:39   Titel:

Hi, micbur,

hier muss man entweder mit sed oder in der bash mit geschickter Variablensubstitution arbeiten...
Code:
#!/bin/bash
EXT=gz

find . -name "*.$EXT" -type f | \
while read FULLNAME ; do
        FILENAME=${FULLNAME##*/}
        FILENAME=${FILENAME%.$EXT}
        DIRNAME=${FULLNAME%/*}
        DIRNAME=${DIRNAME##*/}
        echo cp $FULLNAME ${FILENAME}_$DIRNAME.$EXT
done
find liefert die zu beharkenden Dateien. Die while-Schleife läuft pro Dateinamen einmal durch und setzt den aktuellen Namen in die Variable FULLNAME. Aus dieser wird der Dateiname (alles hinter dem letzten /) extrahiert und die Dateiendung abgeschnitten. Damit wäre der Dateiname extrahiert und steht in FILENAME.
Der Verzeichnisname wird ähnlich extrahiert: Erst alles ab dem letzten Slash entfernen (also den Dateinamen und dann alles bis zum dann noch letzten Shash entfernen - übrig bleibt der Name des Verzeichnisses, in dem die Datei direkt steht. Daraus dann nur noch einen neuen Namen basteln und ein cp davor hängen - fertig!

Nur eins noch: Ich habe das Skript mittels "echo" vo dem cp-Kommando entschärft - nach ausgiebigem Testen und Anpassen bitte entfernen!

Wenn Du genauer wissen willst, was bei ${VAR##*/} und so passiert, dann schau in der bash-Manualpage mal unter dem Abschnitt "Parameter Expansion" nach.

Viel Spass damit!

Jochen
_________________
Die grösste Lüge der EDV? "Mal eben..."
 
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen

micbur



Anmeldungsdatum: 05.06.2004
Beiträge: 86

BeitragVerfasst am: 10. Okt 2005 12:59   Titel:

Vielen Dank.

Das geht ja klasse.

Ich habe die ganze Zeit noch versucht mit Regex und cp mein Ziel zu erreichen.
Dabei wollte ich gerade die Zeile etwa so aussehen lassen:
cp -vr */*.gz archiv/$2_$1.gz

Also ich hatte so eine Ahnung, dass man im Suchmuster Regex benutzen kann, die man dann im Zielmuster verwenden kann. Das hat aber leider nicht so geklappt.

Vielen Dank für dein Script. Habe es schon angepasst, damit nicht zu viel kopiert wird. Wer intresse hat, ich werde noch ein bisschen rumtesten und ein paar Anpassungen vornehmen, und es hier dann reinstellen.

Ciao, micbur
 
Benutzer-Profile anzeigen Private Nachricht senden

micbur



Anmeldungsdatum: 05.06.2004
Beiträge: 86

BeitragVerfasst am: 12. Okt 2005 10:27   Titel:

Wie versprochen, hier der gesamte Code

Code:
#!/bin/sh
#
# Dieses Script kopiert/verschiebt alle Dateien aus einem Verzeichnis mit Unterverzeichnissen in
# ein anders Verzeichnis und benennt dabei die Dateien um, in einer Namenskomination aus
# Verzeichnisnamen und altem Dateinamen.
#
#    Beispiel:
# von:
# $dir/quelle/subdir1/file
# $dir/quelle/subdir2/file
#
# nach:
# $dir/ziel/file_subdir1
# $dir/ziel/file_subdir2
#

# wir suchen nur gezippte Logfiles, also brauchen wir auch nur nach *gz zu suchen
EXT=gz

# Zielverzeichnis
TARGET=/mount-point

umount /mount-point
mount -t smbfs -o ip=***,username=***/***,password=*** //***/*** /mount-point

# wir brauchen nur die access-logs, alles andere ist nicht analysierbar
find $PWD -name "*access*.$EXT" -type f | \
while read FULLNAME ; do

# der Dateiname ist alles nach dem letztem Slash
        FILENAME=${FULLNAME##*/}

# der Dateiname ohne Dateiendung
        FILENAME=${FILENAME%.$EXT}

# der Verzeichnisname ist immer vor dem letztem Slash
        DIRNAME=${FULLNAME%/*}

# im Ergebnis habe ich nun den Verzeichnisnamen, der sich zwischen den beiden letzten Slashes befand
        DIRNAME=${DIRNAME##*/}

# nun endlich das Kopieren/Verschieben
# rsync lohnt nicht, weil mit dem Kopieren die Dateien auch umbenannt werden
# Parameter: --reply=no, bei jedem Dialog wird mit 'no' geantwortet, zum Beispiel beim Überschreiben
# Parameter: -v, viele Ausgaben zu jedem Kopiervorgang
        cp --reply=no -v $FULLNAME $TARGET/${FILENAME}_$DIRNAME.$EXT
done
 
Benutzer-Profile anzeigen Private Nachricht senden

jochen
prolinux-forum-admin


Anmeldungsdatum: 14.01.2000
Beiträge: 699
Wohnort: Jülich

BeitragVerfasst am: 16. Okt 2005 11:16   Titel:

Hi micbur!

Ich zitier hier mal die Änderung, die Du benötigst, aus Deiner PN:
Zitat:
Es handelt sich ja um Apache-Access-Logs, die von logrotate gezippt und verschoben werden. Nun haben wir aber noch eine zweite Applikation, die in einem Unterverzeichnis arbeitet.
der normale Apache mit logrotate arbeiten so:
/var/log/apache/<date>/*log.gz

Die andere Applikation arbeitet in einem anderen Verzeichnis:
/var/log/apache/six/<date>/*log.gz

Nun wurden durch das Skript alle Logs in ein Verzeichnis gepackt und können nicht mehr unterschieden werden. Also wäre es besser, wenn ich eine Lösung finde, in der der Verzeichnisname ab einem bestimmten Punkt genutzt wird, so wie
$SOURCE=/var/log/apache
$SOURCE/<dir>/<subdir>/file -> $TARGET/dir_subdir_file
(Ja, ich weiss auch, dass man PNs oder Auszüge daraus nicht ungefragt öffentlich zitiert. Aber das hier ist ja nun hinreichend zweckgebunden & unpersönlich. OK?)

Die Lösung zum Problem ist sogar einfacher als die ursprüngliche, da man dort den Verzeichnisnamen und den Dateinamen getrennt behandeln musste. Schließlich wurde der Name da "umgekehrt" wieder zusammengesetzt.

DIe grundlegende Lösung sieht aus wie folgt:
Code:
#!/bin/bash
EXT=gz

STARTDIR=/var/apache/logs/
TARGETDIR=/wohin/meine/logs/kommen/

find $STARTDIR -name "*.$EXT" -type f | \
while read FULLNAME ; do
        FILENAME=${FULLNAME#$STARTDIR}
        FILENAME=${FILENAME//\//-}
        echo cp $FULLNAME ${TARGETDIR}${FILENAME}
done
Auch dieses Skript ist wieder zu Testzwecken entschärft (echo vor dem cp-Kommando -> Ausgabe, was passieren würde, aber keine echte Aktion).

EXT, STARTDIR und TARGETDIR dürften selbsterklärend sein.

Die eigentlichen Änderungen stecken im Schleifenkörper. Die Zeile
Code:
FILENAME=${FULLNAME#$STARTDIR}
löscht das Startverzeichnis aus dem Dateinamen und weist das Ergebnis der Variablen FILENAME zu. In der haben wir jetzt alle Verzeichnisse und Unterverzeichnisse und den Dateinamen stehen. Eigentlich schon genau das, was wir wollen, aber die Slashes stören und sollten lieber Bindestriche sein. Das erreichen wir mittels
Code:
FILENAME=${FILENAME//\//-}
In der Variablen FILENAME "${FILENAME" wird alles ersetzt "//", was ein Slash "\/" ist, und zwar durch "/" ein Minuszeichen "-". Fertig "}"!

Beispiel: Aus "/var/apache/logs/six/irgendwas.gz" wird durch die erste Zeile "six/irgendwas.gz" und durch die zweite dann "six-irgendwas.gz".

Damit ist der Zieldateiname komplett und man braucht nur noch das Zielverzeichnis davorzuflanschen.

Alles klar? Viel Spass beim Anpassen der Lösung! Smile

Jochen
_________________
Die grösste Lüge der EDV? "Mal eben..."
 
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen

der_micbur
Gast





BeitragVerfasst am: 17. Okt 2005 15:19   Titel:

Vielen Dank Jochen,
ich habe das auch gleich getestet. Funktioniert prima.

Danke, micbur
 

andib



Anmeldungsdatum: 20.06.2000
Beiträge: 277
Wohnort: Dortmund

BeitragVerfasst am: 17. Okt 2005 22:34   Titel:

Wie wäre es mit
Code:

mmv "*/*.*" "#1/#2_#1.#3"

Erläuterung: auf der Linken Seite werden alle Dateien der Form */*.* gematcht.
Auf der rechten Seite wird das n-te Wildcard ("*") durch #n ersetzt.
dir/file.gz
wird also nach
dir/file_dir.gz
verschoben etc.

Für solche Sachen ist mmv immer hübsch einfach Smile

CU
Andi
 
Benutzer-Profile anzeigen Private Nachricht senden

der_micbur
Gast





BeitragVerfasst am: 18. Okt 2005 12:05   Titel:

Hallo andib,

ja, das waere auch ganz toll, aber ich habe hier Apache-Logs, die mittels logrotate rotiert werden. Bei der Namenskonvention, fuer die wir uns entschieden haben, koennen an einem Tag die Logs auch schonmal mehrfach rotoeren, was dazu fuehrt, dass wur dann Logs haben, die solche Namen haben wie ...

apache_access.2.gz oder
apache_access.gz oder unkomprimiert
apache_access.log

Da wir also mehrere Punkte im Namen haben und es nicht vorhersehbar ist, ob und wann mehrere Logs pro Tag auftreten, kann man leider deine Loesung nicht nehmen.

Aber trotzdem vielen Dank. Ich dachte eigentlich, dass die Tools in fileutils alls regulaere Ausdruecke bzw. Platzhalter als Eingabe verstehen.

Ciao, micbur
 

Beiträge vom vorherigen Thema anzeigen:   
     Pro-Linux Foren-Übersicht -> Programmieren - Allgemein Alle Zeiten sind GMT + 1 Stunde
Seite 1 von 1

 
Gehen Sie zu:  

Powered by phpBB © phpBB Group
pro_linux Theme © 2004 by Mandaxy