• Willkommen im Linux Club - dem deutschsprachigen Supportforum für GNU/Linux. Registriere dich kostenlos, um alle Inhalte zu sehen und Fragen zu stellen.

[gelöst] Script While Schleife

chappert

Hacker
Hallo,

ich habe folgendes Problemchen. Ich möchte von einem Rechner im Netzwerk die mTime von Ordnern und Dateien, die sich alle in einem Verzeichniss befinden auslesen UND das ganze auf dem ausführendem Rechner für die gleichen Dateien und Verzeichnisse wieder setzen

das Problem: das script sollte das ganze möglich automatisiert ausführen UND leider existiert auf dem ausführedem Rechner nicht exat dieselbe Verzeichnisstrucktur aber die Daten sind die selben nur halt aktueller....

Unterschiede der Verzeichnisstruktur:

Problem1:
Rechner im Netzwerk: ./Online/_Keding/... -> ausführender Rechner: ./Online/Mitarbeiter/Keding/... (das ganze mit mehreren Verzeichnissen, was fett ist ist Variable, es kann dort also auch ein andere Name stehen z.B. ./Online/_Kiani ---> ./Online/Mitarbeiter/Kiani)

Problem2:
Rechner im Netzwerk: ./Online/Temp/... -> ausführender Rechner: ./Online/Tmp/...

Problem3:
Rechner im Netzwerk: ./Online_VIP/... -> ausführender Rechner: ./OnlineVIP/...

mein Anfang (mach natürlich weiter):

Code:
#!/bin/sh
ONLINE_ALT=/file/Online
ONLINE_NEU=/fileserver/Online

# touchdate fuer ONLINE
# modifikation time auslesen
MDATE_OLD=`ssh root@192.168.1.122 "ls -l --time-style=long-iso $ONLINE_ALT/_Keding/Arkeia-Backup/Arkeia_Backup_Infos.doc | cut -d ' ' -f 6"`
MTIME_OLD=`ssh root@192.168.1.122 "ls -l --time-style=long-iso $ONLINE_ALT/_Keding/Arkeia-Backup/Arkeia_Backup_Infos.doc | cut -d ' ' -f 7"`

#jetzt Copy File
blablablablaaaaa

#modifikation time neu setzen
touch -d "$MDATE_OLD $MTIME_OLD" $ONLINE_NEU/Mitarbeiter/Keding/Arkeia-Backup/Arkeia_Backup_Infos.doc

#Variablen Inhaltskontrolle
echo $MDATE_OLD
echo $MTIME_OLD

bis jetzt hab ich das ganze ertsmal an einer einzigen Datei probiert, wie man sehen kann, jetzt soll das ganze aber mit allen Verzeichnissen und Dateien passieren und das möglicht automatisch, dabei die Verzeichnisstrukturprobleme beachten...

schon mal vielen dank an alle die sich beteiligen
 
OP
C

chappert

Hacker
hab jetzt ma das script auf den anderen rechner kopiert und ein wenig was verändert, leider arbeitet er nicht datei für datei ab sondern will gleich alles mit einmal machen... und irgendwie is dat och ne endlosschleife :( ich kann sowas nicht heeeeeeeelp

Code:
#!/bin/sh

ONLINE_ALT=/file/Online
ONLINE_NEU=/fileserver/Online/Mitarbeiter


# touchdate fur ONLINE
while [ /file/Online/_Keding/Arkeia-Backup/$FILE  ]
do
# modifikation time auslesen
MDATE_OLD=`ls -l --time-style=long-iso $FILE | cut -d ' ' -f 6`
MTIME_OLD=`ls -l --time-style=long-iso $FILE | cut -d ' ' -f 7`
#jetzt Copy File

#modifikation time neu setzen
ssh root@192.168.1.126 "touch -d "$MDATE_OLD $MTIME_OLD" $ONLINE_NEU/Keding/Arkeia-Backup/$FILE"

#Variablen Inhaltskontrolle
echo $MDATE_OLD
echo $MTIME_OLD

done
 
OP
C

chappert

Hacker
neuer stand der dinge: er arbeitet schon mal in einem Verzeichniss datei für Datei ab ABER es funktioniert nicht rekrusiv, hat einer ne Idee

Code:
#!/bin/sh
ONLINE_ALT=/file/Online
ONLINE_NEU=/fileserver/Online/Mitarbeiter

# touchdate fur ONLINE
for i in /file/Online/_Keding/test1/*;
do
# modifikation time auslesen
MDATE_OLD=`ls -l --time-style=long-iso $i | cut -d ' ' -f 6`
MTIME_OLD=`ls -l --time-style=long-iso $i | cut -d ' ' -f 7`

#modifikation time neu setzen


#Variablen Inhaltskontrolle
echo DATEI: $i
echo DATUM: $MDATE_OLD
echo ZEIT: $MTIME_OLD
done

wenns jetzt noch rekrusiv funktioniert is es ja eigentlich schon fast fertig
 
OP
C

chappert

Hacker
sooo ihr tollen helferlein, jetzt klapp es auch rekrusiv ABER jetzt bekomme ich Probleme mit den leerzeichen in den Verzeichnissnamen, glaub ich jedenfalls...

Code:
#!/bin/sh

ONLINE_ALT=/file/Online/_Keding/
ONLINE_NEU=/fileserver/Online/Mitarbeiter


# touchdate fur ONLINE
find $ONLINE_ALT -type d > /root/bin/dir
for DIR in `cat /root/bin/dir`;
do
for FILE in $DIR*;
do

# modifikation time auslesen
MDATE_OLD=`ls -l --time-style=long-iso $FILE | cut -d ' ' -f 6`
MTIME_OLD=`ls -l --time-style=long-iso $FILE | cut -d ' ' -f 7`

#Variablen Inhaltskontrolle
echo Verz:  $DIR
echo DATEI: $FILE
echo DATUM: $MDATE_OLD
echo ZEIT:  $MTIME_OLD

done
done
 
OP
C

chappert

Hacker
so jetzt aber funktoniert es rekrusiv, problem mit den leerzeichen besteht weiterhin...

Code:
#!/bin/sh

ONLINE_ALT=/file/Online/_Keding/test1
ONLINE_NEU=/fileserver/Online/Mitarbeiter


# touchdate fur ONLINE
find $ONLINE_ALT -type d > /root/bin/dir
for DIR in `cat /root/bin/dir`;
do
for FILE in $DIR/*;
do

# modifikation time auslesen
MDATE_OLD=`ls -l --time-style=long-iso $FILE | cut -d ' ' -f 6`
MTIME_OLD=`ls -l --time-style=long-iso $FILE | cut -d ' ' -f 7`

#Variablen Inhaltskontrolle
echo Verz:  $DIR
echo DATEI: $FILE
echo DATUM: $MDATE_OLD
echo ZEIT:  $MTIME_OLD

done
done
 
A

Anonymous

Gast
Ich hatte als Kernstück hier an so was gedacht,

Code:
DATEIOLD=                            # Datei die überschrieben werden soll
DATEINEU=
......
TIMEOLD=`stat -c%y "$DATEIOLD" | tr -d  ":.\-  " | sed 's/^\([0-9]\{12\}\)\([0-9]\{2\}\).*$/\1.\2/'`
cp "$DATEINEU" "$DATEIOLD"
touch -t "$TIMEOLD" "$DATEIOLD"
......

Fehlt noch die Schleife und eventuelle Sicherungen und Eventualitäten.
muss nur jetzt erst mal was essen und mich ein wenig im meine Frau kümmern ;)

robi
 
A

Anonymous

Gast
Wenn du jetzt natürlich übers Netz arbeiten willst, dann ist diese oben begonnenen Methoden alle wohl ziemlich ungünstig und extrem langsam, desshalb stell ich dir hier mal eine ganz andere Idee vor.



1. Zuerst wird mittels Script1 von dem Verzeichnis das mit den Dateien überschrieben werden soll eine Art Sicherung gemacht, und zwar werden die Zeitstempel von allen Dateien in diesem Verzeichnis in einer Datei gesichert.

2. Danach kannst du dann die Daten rüber kopieren und überschreiben hinzufügen wie du willst, ist völlig egal und ganz allein dir überlassen

3. Aus der Sicherung werden die Dateien mit Script2 wieder mit dem altem Zeitstempel versehen. Auch die Direktories auch wenn das etwas aufwendig und vollkommen unnütz in meinen Augen ist, habe ich es mal mit hineinprogrammiert.

Script1 damit würde die Sicherung gemacht
Code:
#! /bin/bash
LOGDATEI=/tmp/logdatei

find "$1" | while read A
do
stat -c"%y;%n" "$A" | awk -F';' '{print $2 ";" substr($1,1,4) substr($1,6,2) substr($1,9,2) substr($1,12,2) substr($1,15,2) "." substr($1,18,2)}' | tr '/' '%'
done >  "$LOGDATEI"

Script2 damit würden die alten Zeiten wieder auf alle Dateien gesetzt werden. Neue hinzugekommene Dateien würden ignoriert.
Code:
#!/bin/bash
LOGDATEI=/tmp/logdatei

function edittime()
{
find "$1" -depth -maxdepth 1 | while read A
do
 if [ -d "$A" -a "$A" != "$1" ]
   then
     edittime "$A"
   else
    B=`echo "$A" | tr '/' '%'`
    TIME=`awk -F';' '/^'"$B"';/ {print $2}' "$LOGDATEI" `
     if [ -n "$TIME" ]
     then
       echo " touch -t $TIME \"$A\" "
#     touch -t $TIME "$A"                        # mit dieser Zeile würde das Script scharf geschalten
     fi
 fi
done
}

edittime "$1"

Beide Scripte werden auf dem Rechner gestartet auf dem die Dateien überschrieben werden.
Beide Scripte werden aufgerufen mit ./script /verzeichnis (Zwingend immer mit dem selben Verzeichnis) und in jeder Datei muss die selbe Logdatei konfiguriert sein. im Beispiel (/tmp/logdatei)
Das Script2 ist noch nicht scharf geschaltet, es gibt nur die touch Befehle auf der Konsole aus, die Zeile die die Zeiten ändern würde ist noch auskommentiert.

Die Scripte sind noch nicht 100%ig ausgetestet und müssten auch noch besser abgesichert werden. Aber zum spielen sollte es so schon mal reichen.

robi
 
OP
C

chappert

Hacker
erstmal danke für die arbeit aber ich hab da noch nen paar fragen...

zu deinem Script...
1. deine scripte funktionieren die auch rekrusiv oder nur im aktuellen Verzeichniss??? Wenn ja (rekrusiv) wie haste des gemacht
2. wo muss das script ausgeführt werden? genau im dem ordner wo sich die Dateien befinden???
3. es wäre klasse wenn du zu jeder Zeile mal nen kommentar schreiben könntest weil ich das nicht alles verstehe was da so steht und ich will ja auch verstehen und nicht nur übernehmen ;)

zu meinem Script...
1. hättest du da ne idee wegen den Problemen mit Leerezichen in Verzeichnissnamen

Weil immer wenn ein Verzeichniss nen Leerzeichen mit drin hat denkt mein script das was nach dem leerzeichen kommt ein weiterer Unterordner ist, ob probleme bei Dateien (wenn die leerzeichen drin haben) auftreten weiß ich nicht
 
OP
C

chappert

Hacker
wie bekomme ich es hin das find mir seine ausgabe in "" setzt z.B. "Ausgabe"??????

find ./test -type d > /root/bin/dir


hat sich erledigt, habs hiermit hinbekommen: sed -e 's/^\(.*\)$/"\1\"/' < input > output
 
A

Anonymous

Gast
chappert schrieb:
1. deine scripte funktionieren die auch rekrusiv oder nur im aktuellen Verzeichniss??? Wenn ja (rekrusiv) wie haste des gemacht
2. wo muss das script ausgeführt werden? genau im dem ordner wo sich die Dateien befinden???
3. es wäre klasse wenn du zu jeder Zeile mal nen kommentar schreiben könntest weil ich das nicht alles verstehe was da so steht und ich will ja auch verstehen und nicht nur übernehmen ;)

Zu 1 rekursiv ab dem Verzeichnis das du dem Script als Argument mitgibst. Wie recursiv gemacht ?? geheim ;)

Zu 2. wo du dich im Rechner befindest ist egal, muss nur der selbe Rechner sein. zB.
cd /home/usr/bin
./script1 /tmp
kopieren der Daten. (für test zB auch : " find /tmp -exec touch {} \; "
./script2 /tmp

Zu 3. mal sehen ob ich heute abend Zeit habe, im Monent siehts ehr schlecht aus

robi
 
OP
C

chappert

Hacker
ok

vielleicht kannste mir ja bis heut abend auch so weiterhelfen

z.b wie schneide ich eine ganze Zeile, es muss die erste, sein aus einer datei aus????
 
A

Anonymous

Gast
chappert schrieb:
z.b wie schneide ich eine ganze Zeile, es muss die erste, sein aus einer datei aus????
nur den Anfang anzeigen
http://proteino.de/index.php/4102510/

nur das Ende anzeigen
http://linux.die.net/man/1/tail

nur die Mitte geht durch pipen erst durch tail und dann weiter durch head

geht auch alles mit anderen Befehlen zB awk

zB
Code:
awk 'NR==5 {print $0}' DATEI  # nur die 5. Zeile der DATEI anzeigen


robi
 
OP
C

chappert

Hacker
so ich hab jetzt mal deine scripte genommen weil bei mir es nicht hin haut, mit den blöden leerezeichen in verzeichnisnamen

ich hab es aber ein wenig anders ausgeführt wie du mir gesagt hast, weil ich es erstmal ohne kopieren der daten probieren wollte.
hab also dein erstes script genommen und hab das bei dem rechner ausgeführt wo ich die mtime erahlten möchte
script1 /file/Online/_Keding

jetzt habe ich das logfile auf den anderen rechner kopiert

jetzt habe ich dein 2tes script genommen und auf dem anderen rechner ausgeführt wo die mtime ersetzt werden soll
script2 /fileserver/Online/Mitarbeiter/Keding

P.S. pfade für das logfile sind richtig
aber es funktioniert leider nicht, die dateien haben danach alles dieselbe mtime
kannst du die scripte so anpassen das sie so funktionieren würden, das würde mir dann auch schon reichen

das problem ist glaub ich das in deiner logfile der ander pfad drin steht....
 
A

Anonymous

Gast
Irgenwie machst du was falsch.

mit Script1 ein Verzeichnis sichern. Dieses Verzeichnis kannst du dann überschreiben mit den Daten vom anderen Rechner, Wenn du fertig bist, dann genau dieses Verzeichnis mit Script2 wieder auf altes Datum setzen.

Da wird keine Sicherung vom Script1 auf einen anderen Rechner kopiert.

Wenn du testen willst, dann sichere wie oben beschrieben irgend ein unwichtiges Verzeichnis zB /tmp auf irgend einem (möglichst nicht den wichtigsten Zentrall- ) Rechner. Dann mit dem find->touch Befehl von oben alle Zeitstempel auf /tmp auf das aktuelles Datum ändern, und dann kannst du mit Script2 die Zeit der Dateien auf /tmp wieder herstellen. Dann Dateien mit Sonderzeichen anlegen wie du sie in deinen Orginaldatenstamm hast und damit dort testen.

robi
 
A

Anonymous

Gast
Kurze Erklärung zu den beiden Scripten auf den ausdrücklichen Wunsch von chappert

_______________________________________________________
Das erste Script ist ziemlich simpel, es sieht nur so kompliziert aus, weil wir hier die Ausgabe umformatieren, um im 2.Script weniger Probleme zu bekommen


Code:
find "$1"
ein einfaches find beginnend in dem Verzeichnis das als 1. Argument übergeben wurde. $1

Code:
| while read A ; do ...........done > LOGDATEI
Das Ergebnis von find wird in einer while-Schleife jeweils einzeln an die Variable A übergeben, die gesamte Ausgabe der while-Schleife wird in die Logdatei umgeleitet.

Code:
stat -c"%y;%n" "$A"
innerhalb der while-Schleife wird mit dem Befehl stat jeweils aus dem Inhalt von Variable A die mtime %y und der Dateiname %n ermittelt und mit ";" getrennt ausgegeben

Code:
 | awk -F';' '{print $2 ";" substr($1,1,4) substr($1,6,2) ....
# die Ausgabe von stat wird an awk übergeben der zuerst den Namen ausgibt und anschließend die Zeit umformatiert in "YYYYMMDDHHMM.SS" Format ( ginge mit cut zB. auch, allerdings ist das Problem der Punkt der vor den Sekunden eingefügt werden muss, das müsste ein 2. Befehl anschließend noch machen, awk schafft das in einem Zug, desshalb hier awk)

Code:
| tr '/' '%'
Awk übergibt an Befehl tr der dann noch alle "/" durch "%" ersetzt. Der Ganze Aufwand der Umformatierung der stat-Ausgabe sorgt dafür das wir im 2.Script keine Probleme mit Sonderzeichen innerhalb von regulären Ausdrücken bekommen und für den touch Befehl schon das richtige Zeitformat haben.

---------------------------------------------------------------------------


Das 2. Script ist komplizierter zu verstehen. hier wird das Prinzip der Rekursion verwendet. Mit der Funktions-Rekursion soll sicher gestellt sein, dass wir die Verzeichnisse erst dann bearbeiten, wenn der jeweilige Inhalt dieses Verzeichnisses schon fix und fertig bearbeitet ist, nur damit können wird sicherstellen, dass auch die Verzeichnisse wieder sicher die alte Zeitstempel bekommen.
Code:
function edittime()         # hier wird die Funktion definiert
{
 ...................                         
}   
edittime "$1"         # hier wird die Funktion aufgerufen
Die definierte Funktion wird am Ende des Scriptes aufgerufen mit dem 1. Argument (das entspricht dem Verzeichnisnamen) das dem Script übergeben wurde.

Code:
find "$1" -depth -maxdepth 1
hier wird find aufgerufen, $1 beinhaltet hier das Verzeichnis, bedeutet innerhalb der Funktion etwas anderes als außerhalb der Funktion, (innerhalb der Funktion ist das erste Argument beim Aufruf der Funktion gemeint, und außerhalb das erste Argument beim Aufruf des Scriptes) $1 in der Funktion ist also nur dann gleich dem 1. Argument des Scriptaufrufes, wenn die Funktion mit dem ersten Argument des Scriptaufrufes gestartet wird. Die Optionen -depth -maxdepth 1 bedeuten das find nicht rekursiv in die Unterverzeichnisse absteigen soll, und den Verzeichnisnamen als die letzte Datei ausgeben soll.

Code:
| while read A ; do ...........done
ist das selbe wie schon im ersten Script erklärt

Code:
if [ -d "$A" -a "$A" != "$1" ]
   then
     edittime "$A"
   else
   .............
fi
hier prüfen wir ob in A ein Verzeichnisname (-d) ist und (-a) dieser nicht gleich $1 (!="$1") dem Verzeichnis ist, mit dem find innerhalb der Funktion aufgerufen wurde (der steht jeweils in $1 der Funktion)
wenn das alles zutrifft, dann wird edittime "$A" aufgerufen, also die Funktion ruft sich damit selbst wieder auf, aber diesmal mit dem Argument eines Unterverzeichnisses. Sollten sich in diesem Unterverzeichnis wiederum Verzeichnisse befinden, so wird dort wieder die Funktion mit den dort gefundenen Unterverzeichnissen aufgerufen. Die Funktion steigt also immer weiter im Dateibaum hinab bis keine Verzeichnisse mehr von der Funktion gefunden werden.
trifft das nicht zu (also wenn in A zB. eine normale Datei ist), dann wird der Abschnitt zwischen else und fi durchlaufen.

Code:
 B=`echo "$A" | tr '/' '%'`
hier machen wir nichts weiter, als vom Dateinamen der in Variable A steht, alle "/" durch "%" zu ersetzten, wie wir das im Script1 ja auch schon gemacht haben, Das Ergebnis wird in Variable B geschrieben.

Code:
TIME=`awk -F';' '/^'"$B"';/ {print $2}' "$LOGDATEI" `
der wohl komplizierteste Befehl beider Scripte, hier wird vereinfacht ausgedruckt mit dem Befehl awk die Logdatei durchsucht. Gesucht wird nach dem was in Variable B steht und ausgegeben wird in der gefundenen Zeile das 2. Feld in dem ja der formatierte Zeitstring zu dieser Datei steht. Dieser wird in die Variable TIME eingetragen, würde nichts gefunden ist TIME leer.
Der Befehl macht also nichts weiter als TIME=`grep "$B" "$LOGDATEI" | cut -d; -f2` nur ist er genauer und liefert damit eindeutige Werte.



Code:
if [ -n "$TIME" ]
     then
       echo " touch -t $TIME \"$A\" "
       touch -t $TIME "$A"             
fi
ist Variable TIME nicht leer (-n Länge des String in TIME also nicht NULL), (es wurde also von awk etwas gefunden und dort eingetragen) dann hat die Datei mit dem Namen der noch in Variable A steht, vor der Sicherung schon existiert und wir haben jetzt diesen alten Zeitstempel in der Variable TIME
Wenn dem also so ist, dann echo des touchbefehls mit allen Optionen auf der Konsole, und in der nächsten Zeile (wenn sie auskonfiguriert ist) wird touch wirklich ausgeführt.


Ist das Verzeichnis abgearbeitet, (letzter Dateiname ist jeweils das aktuelle Verzeichnis mit dem die Funktion aufgerufen wurde). beendet sich die Funktion durch das Ende der while-Schleife und das Programm wird dort weiter geführt von wo die Funktion aufgerufen wurde, also eine Ebene (ein Verzeichnis) tiefer. Auf diese Art und Weise wird der ganze Dateibaum ab dem Verzeichnis im 1.Argument beider Scripte rekursiv bearbeitet.

Beide Scripte müssen also genau gleich aufgerufen werden da sonst die beiden find Befehle unterschiedliche Dateinnamen kreiren und dadurch nichts gefunden wird.
ZB.
Code:
script1 /tmp
cd /tmp
script2 .
wird nicht funktionieren, obwohl es sich logisch gesehen, um die selben Dateien handeln würde.



robi
 
OP
C

chappert

Hacker
auf jedenfall klappt es hervorragend vieeelen Dank nochmal an robi auch für die nette Erleuterung von dem Quelltext :D
 
Oben