Shell Skript beschleunigen

P

patrick1990

Grünschnabel
Hallo zusammen,
ich bin neu hier und hab gerade angefangen mich an Schell Skripte zu wagen. Nun hab eine Frage ich hab ein Skript geschrieben und die Laufzeit ist mehr als bescheiden :D
vielleicht hat von euch einer eine Idee wie ich das ganze ein bisschen beschleunigen kann.
Der Sinn des Skriptes ist ganz einfach es soll einen Ordner durchgehen und dann jeweils die ältere Version einer Datei falls eine vorhanden ist löschen. Der Namen der Datei ist immer gleich testdatei__Dec--2-11-12-44.362-48, testdatei_Nov-30-12-02-17.300-78,...

ls -t |

while read line
do
k=$i
((k--))
array[ $i ]=$"$line"
if [[ i -gt 0 ]]
then
#solange k größer 0 ist geh zurück und suche Datei
while [[ k -gt 0 ]]
do
if [[ $( echo "${array}" | awk -F_ '{print $1}') = $( echo "${array[k]}" | awk -F_ '{print $1}') ]]
then
#echo "$(echo "${array}") wird gelöscht "
#echo "${array[k]} wird behalten"
echo "${array}" >>testfile
rm -f ${array}
((i--))
break
else
((k--))
fi
done
fi
(( i++ ))
done

Danke schon mal im Voraus für eure Hilfe

Viele Grüße
Patrick
 
Bitte Deine Scripte als Code hier rein stellen, dann kann man die auch besser lesen.

Also so:
Code:
ls -t |
while read line
do
k=$i
((k--))
array[ $i ]=$"$line"
if [[ i -gt 0 ]]
then
#solange k größer 0 ist geh zurück und suche Datei
while [[ k -gt 0 ]]
do
if [[ $( echo "${array}" | awk -F_ '{print $1}') = $( echo "${array[k]}" | awk -F_ '{print $1}') ]]
then
#echo "$(echo "${array}") wird gelöscht "
#echo "${array[k]} wird behalten"
echo "${array}" >>testfile
rm -f ${array}
((i--))
break
else
((k--))
fi
done
fi
(( i++ ))
done

Um wieviele Millionen Dateien geht es denn?

Das Script verzichtet erfreulicherweise schon auf viele Prozesserzeugungen, bis auf die IF-Anweisung mit dem doppelten AWK. Da könntest Du noch mit den Bash-Ausdrücken %%,%,# und ## arbeiten. Da brauchst Du dann keinen awk.

Code:
datei="testdatei__Dec--2-11-12-44.362-48"
dateirumpf="${datei%%__*}"
 
Derzeit handelt es sich um knapp 7000 Dateien und es dauert auf jeden Fall länger als 2 Stunden bis jetzt eine genaue Laufzeit kann ich noch nicht sagen weil es noch nicht durchgelaufen ist.
Meinst du das verkürzt die Laufzeit Großartig oder fällt dir vielleicht ein komplett anderer Ansatz ein, der besser geeignet wäre?
 
7000 Dateien sind gar nix. Die Prozesserzeugungen, die man Deinem Script da einsparen kann, bringen da vielleicht ein paar Sekunden, das ist also bei der Dateizahl absolut irrelevant.

Ich würde jetzt mal eher vermuten, dass Dein System eine sehr hohe Last hat, bis zum Anschlag und dass es deswegen so lange dauert - also nix was man durch besseres Scripten lösen kann.
 
Ok danke für die schnelle Antwort dann muss ich da mal noch nachforschen ob ich an der Systemauslastung was machen kann :)
 
lass zum Test doch einfach das rm mal weg und (oder pack ein echo drumrum) - dann siehst Du mal die grobe Laufzeit ohne irgendwelches großartiges HD-IO...

Das Grundproblem an sich würde ich Scripttechnisch vermutlich komplett anders angehen
 
Hast du da was bestimmtes im Sinn oder wie wäre dein Vorschlag
 
Hi,

schon eine Woche alt, aber vielleicht interessiert es dich ja noch ... Hauptproblem dürfte sein, dass du die Dateinamen einzeln einliest und mit allen bisher im Array eingelesenen vergleichst - das skaliert mit O(n^2), im "Optimalfall", also wenn du keine alten Versionen von Dateien rumliegen hast, startest du mit 7000 Dateien im Verzeichnis fast 25.000.000 Instanzen von awk, und das dauert.

Ein Ansatz wäre, erst einmal festzustellen, welche Basisdateinamen überhaupt relevant sind, die dann einzeln anzugehen. Wenn deine Dateinamen nur '_'-Zeichen vor dem Datum enthalten, könnte so etwas wie folgt funktionieren:

Code:
ls *_* | cut -d_ -f1 | uniq |
while read TRUNC; do
        echo $TRUNC:
        echo rm -f -- $(ls -t ${TRUNC}_* | tail -n +2)
done

Gruss, A.
 
Hi floyd62,
aber ich brauche doch den kompletten Dateinamen um eben diese dann zu löschen oder und mit dem cut verliere ich doch den hinteren teil, oder hab ich hier nen Denkfehler

**Nachtrag**

sorry habs begriffen den 2. teil fügst du ja beim rm befehl dazu
aber kannst du mir den code vieleicht nochmal bisschen erläutern was da wann gemacht wird
 
Zuletzt bearbeitet:
Hi,

in der ersten Zeile
Code:
ls *_* | cut -d_ -f1 | uniq |
hole ich mir die eindeutigen ("uniq") Basisdateinamen (ohne den Timestamp). In der while-Loop
Code:
while read TRUNC; do
       echo $TRUNC:
        ...
done
verarbeite ich dann jeweils nur die paar Dateien, die damit anfangen - das sollten doch wesentlich weniger als alle ca. 7000 sein.
In der Zeile
Code:
echo rm -f -- $(ls -t ${TRUNC}_* | tail -n +2)
liste ich die passenden Dateinamen auf, überlasse dabei die Schwerarbeit, also das Sortieren nach Alter, schon mal dem "ls"-Kommando, schmeisse die neuste Datei aus der Liste raus (wird von "ls -t" als erste angezeit, "tail -n +2" überspringt die), und füttere den Rest an das "rm"-Kommando (bzw. hier erst mal zum Ausprobieren an "echo rm").

In der o.a. Form kannst du das Ding gefahrlos laufen lassen, um zu sehen was gelöscht würde, und wie lange das etwa dauern könnte. Für den Ernstfall dann einfach das echo vor dem "rm" entfernen und feuern ...

Gruss, A.
 
Alles klar vielen Dank für eure Hilfe hab die Laufzeit jetzt von 2,5 Stunden auf knapp 2 Minuten runter bekommen.
Und danke für die Erklärung ich verwende nur ungern Code, bei dem ich mir nicht 100% sicher bin was er genau macht

viele Grüße
Patrick
 

Ähnliche Themen

Switche abfragen über Script

script sshpass

Verschlüsseltes Backup-Script mit rsync

Grafische Anzeige der Temperatur

Summe von Zahlen in einer Zeilen bilden

Zurück
Oben