Nachdem der Entwurf unseres Programms nun feststeht, können wir den Code schreiben, der eine Implementierung unserer Lösung darstellt.
Beispiel 10.1. Sicherungsskript - erste Version (sicherung_ver1.py)
#!/usr/bin/python import os import time # 1. Die Dateien und Verzeichnisse, die gesichert werden sollen, # werden in der folgenden Liste angegeben: quellen = ['/home/swaroop/byte', '/home/swaroop/bin'] # Unter Windows muessen Sie die Pfade auf diese Weise angeben: # quellen = ['C:\\Dokumente', 'D:\\Arbeit'] # 2. Die Sicherung muss in das folgende Hauptverzeichnis fuer # Sicherungen gespeichert werden: ziel_verzeichnis = '/mnt/e/sicherung/' # Denken Sie daran, dies an Ihre Gegebenheiten anzupassen. # 3. Die Dateien werden in einer ZIP-Datei gesichert. # 4. Der Name der ZIP-Datei setzt sich aus dem aktuellen Datum # und der Uhrzeit wie folgt zusammen: ziel = ziel_verzeichnis + time.strftime('%Y%m%d%H%M%S') + '.zip' # 5. Wir benutzen den Befehl zip (unter Unix/Linux), um die Dateien # zu einem ZIP-Archiv zu komprimieren: zip_befehl = 'zip -qr %s %s' % (ziel, ' '.join(quellen)) # Windows-Benutzer koennen z.B. PKZIP oder Info-ZIP in das # Windows-Systemverzeichnis kopieren, damit dies funktioniert. # Sicherung starten if os.system(zip_befehl) == 0: print 'Erfolgreiche Sicherung nach', ziel else: print 'Sicherung fehlgeschlagen!'
$ python sicherung_ver1.py Erfolgreiche Sicherung nach /mnt/e/backup/20041208073244.zip
Wir sind nun in der Test-Phase, in der wir ausprobieren, ob unser Programm ordentlich funktioniert. Wenn es sich nicht so verhält, wie erwartet, dann müssen wir unser Programm debuggen, d.h. die Bugs (Fehler) aus dem Programm entfernen.
Sie werden bemerkt haben, wie wir unseren Entwurf Schritt für Schritt in Programm-Code umgewandelt haben.
Wir benutzen die Module os
und time
,
weswegen wir sie am Anfang importieren. Danach geben wir in einer Liste namens
Quellen
die Quelldateien und -verzeichnisse an, die
gesichert werden sollen. Das Zielverzeichnis, in das wir die Sicherungsdateien speichern,
wird in der Variable ziel_verzeichnis
angegeben.
Der Name des ZIP-Archivs, das wir erzeugen werden, setzt sich aus dem aktuellen Datum und
der Uhrzeit zusammen, die wir mit der Funktion time.strftime()
ermitteln. Dem Namen wird noch die Dateiendung .zip
angehängt
und das Zielverzeichnis vorangestellt. Dieser vollständige Dateiname mit Pfad wird in der
Variable ziel
gespeichert.
Der Funktion time.strftime()
muss eine Formatspezifikation
übergeben werden, wie wir sie im obigen Programm benutzt haben. Das %Y
wird hierbei durch das Jahr ersetzt. Das %m
wird
durch den Monat als Dezimalzahl zwischen 01
und 12
ersetzt, und so weiter. Die vollständige Liste aller solcher Format-Spezifikationen kann im
[Python-Referenz-Handbuch] nachgelesen werden, das zusammen mit
Python ausgeliefert wird. Beachten Sie, dass dies der Spezifikation ähnelt (aber nicht das gleiche ist),
wie wir sie im print
-Befehl benutzt haben (mit dem %
-Zeichen,
gefolgt von einem Tupel).
Wir erzeugen den Namen der Ziel-ZIP-Datei, indem wir den Summierungs-Operator (das Plus-Zeichen)
benutzen, der die einzelnen Strings miteinander verkettet, d.h. er
verbindet zwei Strings und liefert dies als neuen String zurück. Danach erzeugen wir einen String
zip_befehl
, der den Befehl enthält, den wir ausführen wollen.
Sie können ausprobieren, ob dieser Befehl funktioniert, indem Sie ihn auf der Kommandozeilen-Ebene
ausprobieren (Linux-Terminal oder DOS-Eingabeaufforderung).
Dem von uns verwendeten Befehl zip geben wir noch
einige Optionen und Parameter mit. Die Option -q
wird benutzt,
um anzuzeigen, dass der zip-Befehl ohne Ausgaben arbeiten soll (d.h. ohne viel bei der
Arbeit zu quatschen). Die Option -r
gibt an, dass der zip-Befehl rekursiv arbeiten
soll, d.h. er soll die Unterverzeichnisse und Dateien in den Unterverzeichnissen mit archivieren.
Die beiden Optionen werden kombiniert in der Kurzform -qr
angegeben.
Den Optionen folgt der Name des zu erzeugenden ZIP-Archivs und die Liste der Dateien und Verzeichnisse,
die in dem Archiv gesichert werden sollen. Wir konvertieren die Liste quellen
in einen String, indem wir die join
-Methode für Strings benutzen,
die wir bereits früher kennen gelernt haben.
Danach starten wir endlich den Befehl, indem
wir die Funktion os.system
benutzen, die einen Befehl
auf Betriebssystemebene des Systems ausführt, d.h.
in einer Kommandozeilen-Umgebung - wobei eine 0
zurückgegeben
wird, wenn der Befehl erfolgreich ausgeführt wurde, oder einen Fehlercode ungleich 0
im Fall, dass ein Fehler aufgetreten ist.
Je nachdem, wie die Ausführung des Befehls ausgegangen ist, geben wir eine entsprechende Meldung auf dem Bildschirm aus, dass die Sicherung fehlgeschlagen ist oder erfolgreich war, und das war's, wir haben damit ein Skript erzeugt, das eine Sicherungskopie unserer wichtigen Dateien erzeugt!
Sie können in der Liste quellen
und der Variable
ziel_verzeichnis
beliebige Datei- bzw. Verzeichnisnamen
angeben, aber Sie müssen unter Windows ein wenig Acht geben.
Das Problem ist, dass Windows den umgekehrten Schrägstrich
(\
) als das Trennzeichen für Verzeichnisse benutzt,
Python jedoch den umgekehrten Schrägstrich für Maskierungscodes benutzt!
Daher müssen Sie einen umgekehrten Schrägstrich selber durch einen Maskierungscode
oder durch die Benutzung von rohen Zeichenketten darstellen. Zum Beispiel können Sie
'C:\\Dokumente'
oder r'C:\Dokumente'
schreiben,
nicht aber 'C:\Dokumente'
- Sie verwenden hier einen unbekannten Maskierungscode \D
!
Nachdem wir nun ein funktionierendes Sicherungsskript haben, können wir es jederzeit benutzen, um eine Sicherungskopie der Dateien zu erstellen. Für Linux/Unix-Benutzer empfiehlt es sich, die früher besprochene Methode für ausführbare Dateien zu verwenden, damit das Sicherungsskript jederzeit und überall ausgeführt werden kann. Dies wird die Produktions- oder Einsatz-Phase der Software genannt.
Das obige Programm funktioniert zufrieden stellend, aber (meistens) funktionieren erste Versionen von Programmen nicht genau so, wie man es erwartet. Zum Beispiel könnten Probleme entstehen, wenn das Programm nicht sauber entworfen wurde, oder wenn man einen Fehler beim Eintippen des Programmcodes gemacht hat, usw. Dementsprechend muss man dann wieder in die Entwurfsphase zurückgehen oder sein Programm debuggen.
Die erste Version unseres Skripts funktioniert. Wir können aber noch einige Verfeinerungen daran vornehmen, so dass es für den täglichen Einsatz besser tauglich wird. Man nennt dies die Wartungs-Phase der Software.
Eine der Verfeinerungen, die ich nützlich fand, ist ein besserer Mechanismus zur Benennung der Sicherungsdateien - indem die Uhrzeit als der Name der Datei verwendet wird, die in einem Verzeichnis gespeichert wird, dessen Name aus dem aktuellen Datum gebildet wird, und das sich im Hauptverzeichnis für die Sicherungen befindet. Ein Vorteil davon ist, dass die Sicherungen in einer hierarchischen Weise gespeichert werden und daher einfacher zu verwalten sind. Ein weiterer Vorteil ist, dass die Länge der Dateinamen auf diese Weise viel kürzer wird. Noch ein weiterer Vorteil ist, dass verschiedene Verzeichnisse dabei helfen, auf einfache Weise zu überprüfen, ob man an jedem Tag eine Sicherung gemacht hat, denn das Verzeichnis wird nur angelegt, wenn am jeweiligen Tag eine Sicherung vorgenommen wurde.
Beispiel 10.2. Sicherungsskript - zweite Version (sicherung_ver2.py)
#!/usr/bin/python import os import time # 1. Die Dateien und Verzeichnisse, die gesichert werden sollen, # werden in der folgenden Liste angegeben: quellen = ['/home/swaroop/byte', '/home/swaroop/bin'] # Unter Windows muessen Sie die Pfade auf diese Weise angeben: # quellen = ['C:\\Dokumente', 'D:\\Arbeit'] # 2. Die Sicherung muss in das folgende Hauptverzeichnis fuer # Sicherungen gespeichert werden: ziel_verzeichnis = '/mnt/e/sicherung/' # Denken Sie daran, dies an Ihre Gegebenheiten anzupassen. # 3. Die Dateien werden in einer ZIP-Datei gesichert. # 4. Das Tagesdatum ist der Name des Unterverzeichnisses: heute = ziel_verzeichnis + time.strftime('%Y%m%d') # Die aktuelle Uhrzeit ist der Name des ZIP-Archivs: jetzt = time.strftime('%H%M%S') # Erzeuge das Unterverzeichnis, wenn noch nicht vorhanden: if not os.path.exists(heute): os.mkdir(heute) # erzeuge das Verzeichnis print 'Verzeichnis', heute, 'erfolgreich angelegt' # Der Name der ZIP-Datei: ziel = heute + os.sep + jetzt + '.zip' # 5. Wir benutzen den Befehl zip (unter Unix/Linux), um die Dateien # zu einem ZIP-Archiv zu komprimieren: zip_befehl = 'zip -qr %s %s' % (ziel, ' '.join(quellen)) # Windows-Benutzer koennen z.B. PKZIP oder Info-ZIP in das # Windows-Systemverzeichnis kopieren, damit dies funktioniert. # Sicherung starten if os.system(zip_befehl) == 0: print 'Erfolgreiche Sicherung nach', ziel else: print 'Sicherung fehlgeschlagen!'
$ python sicherung_ver2.py Verzeichnis /mnt/e/backup/20041208 erfolgreich angelegt Erfolgreiche Sicherung nach /mnt/e/backup/20041208/080020.zip $ python sicherung_ver2.py Erfolgreiche Sicherung nach /mnt/e/backup/20041208/080428.zip
Das Programm bleibt im Wesentlichen das gleiche. Die Änderungen
bestehen darin, dass wir prüfen, of es bereits ein Verzeichnis mit dem
aktuellen Tagesdatum als Namen innerhalb des Hauptverzeichnisses für
Sicherungen gibt, wofür wir die Funktion os.exists
einsetzen. Wenn es nicht existiert, legen wir das Verzeichnis mit der
Funktion os.mkdir
an.
Beachten Sie die Benutzung der Variablen os.sep
-
sie stellt das Trennzeichen für Verzeichnisse des jeweils benutzten Betriebssystems
dar, d.h. sie wird unter Unix oder Linux '/'
sein, unter Windows
wird sie '\\'
sein, und ':'
unter MacOS.
Indem man os.sep
verwendet, anstatt diese Zeichen
direkt hinzuschreiben, wird das Programm portabel und funktioniert plattformunabhängig
unter all diesen Betriebssystemen.
Die zweite Version funktioniert hervorragend, wenn man viele Sicherungskopien macht, aber wenn man so viele Sicherheitskopien macht, dann wird es schwer zu unterscheiden, wofür diese Sicherungskopien gemacht worden sind. Zum Beispiel könnte ich einige größere Änderungen an einem Programm oder einer Präsentation gemacht haben, und möchte dann, dass diese Änderungen mit dem Namen des ZIP-Archivs verknüpft werden. Dies kann einfach dadurch erreicht werden, dass man dem Namen des ZIP-Archivs einen benutzerdefinierten Kommentar anhängt.
Beispiel 10.3. Sicherungsskript - dritte Version (funktioniert nicht!) (sicherung_ver3.py)
#!/usr/bin/python import os import time # 1. Die Dateien und Verzeichnisse, die gesichert werden sollen, # werden in der folgenden Liste angegeben: quellen = ['/home/swaroop/byte', '/home/swaroop/bin'] # Unter Windows muessen Sie die Pfade auf diese Weise angeben: # quellen = ['C:\\Dokumente', 'D:\\Arbeit'] # 2. Die Sicherung muss in das folgende Hauptverzeichnis fuer # Sicherungen gespeichert werden: ziel_verzeichnis = '/mnt/e/sicherung/' # Denken Sie daran, dies an Ihre Gegebenheiten anzupassen. # 3. Die Dateien werden in einer ZIP-Datei gesichert. # 4. Das Tagesdatum ist der Name des Unterverzeichnisses: heute = ziel_verzeichnis + time.strftime('%Y%m%d') # Die aktuelle Uhrzeit ist der Name des ZIP-Archivs: jetzt = time.strftime('%H%M%S') # Eine Anmerkung als Benutzereingabe entgegennehmen, # die fuer den Namen der ZIP-Datei verwendet wird: anmerkung = raw_input('Geben Sie eine Anmerkung ein --> ') if len(anmerkung) == 0: # pruefe, ob eine Anmerkung eingegeben wurde ziel = heute + os.sep + jetzt + '.zip' else: ziel = heute + os.sep + jetzt + '_' + anmerkung.replace(' ', '_') + '.zip' # Erzeuge das Unterverzeichnis, wenn noch nicht vorhanden: if not os.path.exists(heute): os.mkdir(heute) # erzeuge das Verzeichnis print 'Verzeichnis', heute, 'erfolgreich angelegt' # 5. Wir benutzen den Befehl zip (unter Unix/Linux), um die Dateien # zu einem ZIP-Archiv zu komprimieren: zip_befehl = 'zip -qr %s %s' % (ziel, ' '.join(quellen)) # Windows-Benutzer koennen z.B. PKZIP oder Info-ZIP in das # Windows-Systemverzeichnis kopieren, damit dies funktioniert. # Sicherung starten if os.system(zip_befehl) == 0: print 'Erfolgreiche Sicherung nach', ziel else: print 'Sicherung fehlgeschlagen!'
$ python sicherung_ver3.py File "sicherung_ver3.py", line 30 ziel = heute + os.sep + jetzt + '_' + ^ SyntaxError: invalid syntax
Dieses Programm funktioniert nicht! Python sagt, dass es einen Syntax-Fehler hat, was bedeutet, dass das Skript an einer Stelle nicht die Struktur aufweist, die Python hier erwartet. Wenn wir auf die Fehlermeldung von Python Acht geben, gibt sie uns auch die genaue Stelle an, wo der Fehler entdeckt wurde. Wir fangen also an, das Programm ab dieser Zeile zu debuggen.
Bei genauerer Untersuchung erkennen wir, dass die eine logische Zeile
in zwei physikalische Zeilen aufgespalten worden ist, aber dass wir nicht
angegeben haben, dass diese zwei physikalischen Zeilen zusammengehören.
Für Python fehlt dem Summierungs-Operator (+
) am Ende
der logischen Zeile daher ein Operand, weswegen es an dieser Stelle
abbricht. Erinnern Sie sich daran, dass wir angeben können, dass die logische
Zeile in der folgenden physikalischen Zeile fortgeführt wird, indem wir einen
umgekehrten Schrägstrich am Ende der physikalischen Zeile benutzen. Wir machen
daher diese Verbesserung an unserem Programm. Eine solche Fehlerkorrektur wird
auch als Bug-Fixing bezeichnet.
Beispiel 10.4. Sicherungsskript - vierte Version (sicherung_ver4.py)
#!/usr/bin/python import os import time # 1. Die Dateien und Verzeichnisse, die gesichert werden sollen, # werden in der folgenden Liste angegeben: quellen = ['/home/swaroop/byte', '/home/swaroop/bin'] # Unter Windows muessen Sie die Pfade auf diese Weise angeben: # quellen = ['C:\\Dokumente', 'D:\\Arbeit'] # 2. Die Sicherung muss in das folgende Hauptverzeichnis fuer # Sicherungen gespeichert werden: ziel_verzeichnis = '/mnt/e/sicherung/' # Denken Sie daran, dies an Ihre Gegebenheiten anzupassen. # 3. Die Dateien werden in einer ZIP-Datei gesichert. # 4. Das Tagesdatum ist der Name des Unterverzeichnisses: heute = ziel_verzeichnis + time.strftime('%Y%m%d') # Die aktuelle Uhrzeit ist der Name des ZIP-Archivs: jetzt = time.strftime('%H%M%S') # Eine Anmerkung als Benutzereingabe entgegennehmen, # die fuer den Namen der ZIP-Datei verwendet wird: anmerkung = raw_input('Geben Sie eine Anmerkung ein --> ') if len(anmerkung) == 0: # pruefe, ob eine Anmerkung eingegeben wurde ziel = heute + os.sep + jetzt + '.zip' else: ziel = heute + os.sep + jetzt + '_' + \ anmerkung.replace(' ', '_') + '.zip' # Beachten Sie den umgekehrten Schraegstrich! # Erzeuge das Unterverzeichnis, wenn noch nicht vorhanden: if not os.path.exists(heute): os.mkdir(heute) # erzeuge das Verzeichnis print 'Verzeichnis', heute, 'erfolgreich angelegt' # 5. Wir benutzen den Befehl zip (unter Unix/Linux), um die Dateien # zu einem ZIP-Archiv zu komprimieren: zip_befehl = 'zip -qr %s %s' % (ziel, ' '.join(quellen)) # Windows-Benutzer koennen z.B. PKZIP oder Info-ZIP in das # Windows-Systemverzeichnis kopieren, damit dies funktioniert. # Sicherung starten if os.system(zip_befehl) == 0: print 'Erfolgreiche Sicherung nach', ziel else: print 'Sicherung fehlgeschlagen!'
$ python sicherung_ver4.py Geben Sie eine Anmerkung ein --> neue beispiele ergaenzt Erfolgreiche Sicherung nach /mnt/e/backup/20041208/082156_neue_beispiele_ergaenzt.zip $ python sicherung_ver4.py Geben Sie eine Anmerkung ein --> Erfolgreiche Sicherung nach /mnt/e/backup/20041208/082316.zip
So funktioniert das Programm jetzt! Wir wollen die eigentlichen Änderungen
durchgehen, die wir in Version 3 gemacht haben. Wir nehmen eine Anmerkung
des Benutzers mit der Funktion raw_input
als Eingabe
entgegen und prüfen, ob der Benutzer wirklich irgendetwas eingegeben hat, indem
wir die Länge der Eingabe mit der Funktion len
ermitteln.
Wenn der Benutzer aus irgendeinem Grund (zum Beispiel, weil es nur eine Routine-Sicherung
ist, und keine besonderen Änderungen vorgenommen wurden) nur einfach die
Enter-Taste gedrückt hat, dann verfahren wir genauso wie vorher.
Wenn jedoch eine Anmerkung eingegeben wurde, dann wird diese an den Namen
des ZIP-Archivs angehängt, direkt vor der Dateiendung .zip
.
Beachten Sie, dass wir Leerzeichen in der Anmerkung durch Unterstriche ersetzen -
aus dem Grund, dass solche Dateinamen leichter handhabbar sind.
Die vierte Version ist für die meisten Benutzer ein zufrieden stellend arbeitendes Skript,
aber es gibt stets Möglichkeiten zur weiteren Verbesserung. Zum Beispiel könnte man
einen Grad der Ausführlichkeit der Programmausgaben
einbauen, den man mit einer Option -v
angeben könnte, und der
das Programm dazu bringt, geschwätziger in der Ausgabe zu sein.
Eine weitere mögliche Verbesserung würde es erlauben, dem Skript zusätzliche
Dateien und Verzeichnisse auf der Kommandozeile zu übergeben. Wir könnten
diese Übergabeparameter der Liste sys.argv
entnehmen,
und sie der Liste quellen
hinzufügen, indem wir die
extend
-Methode benutzen, die von der Klasse
list
bereitgestellt wird.
Eine Verfeinerung, die ich bevorzuge, ist die Verwendung des tar-Befehls
anstelle des zip-Befehls. Ein Vorteil hierbei ist, dass die Sicherung viel
schneller durchgeführt wird, und die Sicherungsdatei außerdem viel kleiner wird, wenn man den
tar-Befehl zusammen mit gzip verwendet.
Wenn ich dieses Archiv unter Windows benötige, dann werden .tar.gz
-Dateien
auch problemlos von WinZip entpackt. Der tar-Befehl
ist standardmäßig auf den meisten Linux/Unix-Systemen vorhanden. Windows-Benutzer können ihn sich
ebenfalls aus dem Internet
holen und auf ihrem Windows-System installieren.
Die entsprechende Befehlszeile sähe dann zum Beispiel so aus:
tar = 'tar -cvzf %s %s -X ausnahmen.txt' % (ziel, ' '.join(quellen))
Die Optionen werden im Folgenden erläutert.
-c
(für create)
zeigt an, dass eine Archivdatei erzeugt werden soll.
-v
(für verbose)
bedeutet, dass die Ausgabe des Programms geschwätziger sein sollte.
-z
bedeutet, dass gzip
als Filter benutzt werden soll.
-f
(für force)
bedeutet, dass beim Anlegen der Archivdatei eine eventuell bereits vorhandene
Datei gleichen Namens überschrieben werden soll.
-X
(für exclude)
gibt eine Ausnahmedatei an, d.h. eine Textdatei, die eine Liste von Dateinamen enthält,
die von der Sicherung ausgeschlossen werden sollen. Zum Beispiel könnte man in diese
Datei den Eintrag *~
schreiben, wenn man nicht möchte, dass Dateien,
deren Name mit dem Zeichen ~
endet (gewöhnlicherweise sind das
temporär angelegte Dateien), mit in die Sicherung aufgenommen werden sollen.
Die bevorzugte Weise, solche Archive anzulegen, ist unter Verwendung
des Moduls zipfile
bzw. tarfile
-
Sie gehören zur Python-Standard-Bibliothek und stehen Ihnen bereits zum
Gebrauch zur Verfügung. Durch den Einsatz dieser Bibliotheken kann man auch
die Benutzung von os.system
vermeiden, was grundsätzlich
ratsam ist, weil man bei Benutzung dieser Funktion sehr schnell kostspielige
Fehler machen kann.
Ich habe dennoch aus didaktischen Gründen os.system
im Sicherungskript verwendet, damit das Beispiel einfach genug ist, dass es jeder
verstehen kann, und real genug, um nützlich zu sein.