Artikel mit Schlagwort "Quellcode"
USB-Stick automatisch synchronisieren (udev+rsync)
Im Zuge meiner Abschlussarbeit stellte ich einige Überlegungen zwecks der Verwaltung und Sicherung der entstehenden Datenflut an. Nach einigem Für und Wider habe ich mich für eine Variante entschieden, die ich hier kurz vorstellen möchte.
Ein USB-Stick dient zum Transport der Daten. Dies hat sich als besonders praktikabel erwiesen, da auf unterschiedlichen PCs gearbeitet werden muss und auch ein Internetzugang nicht immer garantiert ist.
Vor dem Verlust des USB-Sticks oder einem technischen Defekt ist keiner gefeit und darum muss eine möglichst einfache Backup-Lösung her.
Das geht unter Linux nativ mit Bordmitteln, die nur ein wenig kombiniert werden müssen:
Um das Sichern der Daten so bequem wie möglich zu machen, soll sich der USB-Stick nach dem Einstecken automatisch mit einem Verzeichnis auf der Festplatte synchronisieren. Ein Benutzereingriff soll nicht nötig sein.
Das kleine Tool udev (Homepage) ist dafür besonders gut geeignet, denn mit selbst erstellten Regeln kann man das Anschließen von Hardware erkennen (hotplug-Ereignisse) und selber Aktionen definieren.
Zuerst müssen ein paar Daten gesammelt werden, damit der USB-Stick von der udev-Regel eindeutig identifiziert werden kann. Mit dem folgenden Befehl sucht man sich das Device zum USB-Stick heraus:
mount…
/dev/sdc1 on /media/JETFLASH600 …
…
Der USB-Stick ist dem System also unter /dev/sdc bekannt. Mit einem Tool von udev können nun Gerätedetails ausgelesen werden:
udevadm info --path=/sys/block/sdc --query=all --attribute-walk | grep serial
…
ATTRS{serial}==”RWTAG4K2”
ATTRS{serial}==”0000:00:1d.7″
…
Das fett gedruckte ist die Seriennummer des USB-Sticks, die wir zur eindeutigen Identifizierung benutzen werden. Es können auch andere Merkmale zur Identifizierung genutzt werden und auch Kombinationen daraus (grep-Befehl weglassen). Nähere Informationen gibt es auf der man-Page.
Die udev-Regeln liegen bei Ubuntu im Verzeichnis /lib/udev/rules.d/ bzw. /etc/udev/rules.d/. Und im letzteren legt man eine eigene Regel an. Die Zahl im Dateinamen gibt an, zu welchem Zeitpunkt/in welcher Reihenfolge die Regeln greifen (näheres dazu in /lib/udev/rules.d/README).
sudo vim /etc/udev/rules.d/99-usb-backup-custom.rules
BUS==”usb”, ACTION==”add”, KERNEL==”sd?1″, SYSFS{serial}==”RWTAG4K2“, RUN+=”/pfad/zum/script/usb_backup.sh“
(wichtig: kein Zeilenumbruch!)
| BUS==”usb” | USB-Ports sollen beobachtet werden |
| ACTION==”add” | Nur beim Anschließen des Gerätes die Regel ausführen (sonst startet das Backup-Script immer wieder neu) |
| KERNEL==”sd?1″ | Mit dem Fragezeichen als Platzhalter wird die erste Partition des Device berücksichtigt (sda1, sdb1, …) |
| SYSFS{serial}==”RWTAG4K2″ | Es wird nach der Seriennummer gefiltert |
| RUN+=”/pfad/zum/script/usb_backup.sh” | Hier wird die Aktion angegeben (hier: Pfad zum Backup-Script) |
Nun kann das Backup-Script angelegt werden (unbedingt die gekennzeichneten Stellen anpassen!):
vim /pfad/zum/script/usb_backup.sh
#!/bin/bash { dev="JETFLASH600" #Device-Name angeben! (hier z.B. /media/JETFLASH600) exec 3> >(sudo -H -u USERNAME zenity \ #Username einfügen! --display :0.0 \ --text-info \ --title "USB-Stick Datasaver" \ --width=450 \ --height=250) echo "USB-Stick detected: $dev" >&3 mp=$(grep "$dev" /etc/mtab) i=0 while [ -z "$mp" ] && [ "$i" -lt 30 ] do sleep 1 mp=$(grep "$dev" /etc/mtab) i=$((i+1)) done if [ -n "$mp" ] then rsync -avz --delete /media/$dev /pfad/zum/backup >&3 #Verzeichnis anpassen! echo "Done!" >&3 fi } &
Sehr wichtig sind die geschweiften Klammern ({,}) und das Et-Zeichen (&). Dies bewirkt, dass das Script im Hintergrund arbeitet und dazu parallel die gewöhnliche Einbindung des USB-Sticks ablaufen kann. Mit zenity (Homepage) wird ein kleines Fenster geöffnet, was eine Übersicht über den Vorgang gibt. Die etwas umständlich wirkende Warteschleife (while…) ist nötig, um die Zeit zwischen der Erkennung des USB-Sticks (Script wird gestartet) und dem Einbinden zu überbrücken. Erst nach dem Einbinden ist ein Zugriff auf die Dateien möglich.
Das Tool rsync (Homepage) gleicht die Daten zwischen dem USB-Stick und dem Backup-Verzeichnis ab. In der man-Page wird erklärt, was die einzelnen Optionen bedeuten:
| -a | Dateien, Verzeichnisse, symbolische Links rekursiv abgleichen und dabei Rechte beibehalten |
| -v | Ausgabe anzeigen |
| -z | Datenabgleich komprimieren |
| –delete | in der Quelle (USB-Stick) gelöschte Dateien auch im Ziel (Backup) löschen |
Das Backup-Script braucht jetzt noch Berechtigungen zum Ausführen:
chmod 755 /pfad/zum/script/usb_backup.sh
Ausserdem muss das Verzeichnis für das Backup angelegt werden:
mkdir /pfad/zum/backup
Damit die udev-Regel benutzt werden kann, ist ein Neustart des udev-Daemons nötig:
sudo service udev reloadFertig! Ab sofort werden die Daten des USB-Sticks beim Einstecken in das Backup-Verzeichnis geschrieben.
Screenshot:

Short-Circuit-Tests bei der Shellprogrammierung
Bei der Shellprogrammierung gibt es mit den sogenannten Short-Circuit-Tests eine sehr komfortable und knappe Methode, um mehrere Befehle logisch hintereinander zu reihen und zu verküpfen.
Die Syntax sieht dazu wie folgt aus:
COMMAND1 && COMMAND2 COMMAND1 || COMMAND2
Prinzipiell funktionieren die Anweisungen wie if-Abfragen:
&&: liefert der COMMAND1 true, wird COMMAND2 ausgeführt
||: liefert der COMMAND1 true, wird COMMAND2 nicht (!) ausgeführt
Als COMMAND1 werden oft Abfragebedingungen verwendet (müssen aber nicht), während COMMAND2 ein richtiger Befehl sein muss.
Die Arbeitsweise der beiden Operatoren sind als logisch UND bzw. ODER zu verstehen. Der Gedanke dahinter:
Ist COMMAND1 true, so muss für UND (&&) auch COMMAND2 ausgeführt werden, um zu testen, ob COMMAND2 ebenfalls true ist. Falls COMMAND1 bereits false ist, wird COMMAND2 gar nicht erst ausgeführt.
Ähnlich bei ODER (||): Ist COMMAND1 true, reicht dies bereits aus, um das gesamte Statement true werden zu lassen und COMMAND2 wird nicht ausgeführt. Erst wenn COMMAND1 false ist, muss COMMAND2 ausgeführt werden, um dort auf true zu prüfen.
Tabellarisch kann es folgendermaßen dargestellt werden:
|
|
||||||||||||||||||||||||||||||
% bedeutet, dass der COMMAND nicht ausgeführt wird!
Beliebt sind solche Ausdrücke vor allem zum Abfangen kleiner Abfragen:
[ ! -f /path/to/file.ext ] && exit 1
(falls die Datei file.ext nicht existiert, wird das Programm an dieser Stelle mit dem Fehlercode 1 beendet)
rm text.ext || echo "Datei konnte nicht geloescht werden!"
(Fehlermeldung, falls Datei nicht gelöscht werden konnte)
ls test.ext && touch test.ext
(Datei anlegen, falls nicht existiert)
Noch viele weitere Möglichkeiten sind denkbar und zeigen die Flexibilität dieses Ausdrucks! Zudem lassen sich mehr als zwei Befehl hintereinander reihen (mit beliebig vermischten Operatoren).
Anmerkung: Code in Bourne-Again-Shell (Bash) Syntax
Strings mit PHP prüfen
Einen String prüfen, ob er eine Binärzahl ist:
function is_bin($val) { return (preg_match('/^[0-1]*$/', $val)) ? true : false; }
Einen String prüfen, ob er eine Hexadezimalzahl ist:
function is_hex($val) { return (preg_match('/^[0-9a-f]*$/i', $val)) ? true : false; }
vim komfortabel beenden mit MyQuit
Die Situation kennt vielleicht der ein oder andere vim-Nutzer: Man editiert an mehreren Dateien, schließt und öffnet sie. Leicht verliert man den Überblick, ob man nun mit :wq (also mit speichern) oder nur mit :q vim beenden soll. Hinzu kommt der Umstand, dass man sich im Kommandomodus befinden und den jeweiligen Befehl erst eingeben muss.
Spontan kam mir der Gedanke: Das geht doch bestimmt viel komfortabler.
Und so habe ich mich an ein Script gegeben, was das Beenden von vim viel einfacher und schneller gestaltet. Dabei handelt es sich um eine Funktion, die mit Mapping auf eine Taste gelegt wird.
Wird diese Taste betätigt, überprüft das Script, ob an der geöffneten Datei Änderungen vorgenommen wurden. Existiert die Datei und wurde sie nicht verändert, wird vim sofort geschlossen (:q). Falls es Änderungen gab, wird nun abgefragt, ob diese abgespeichert werden sollen. Ist das nicht der Fall, wird vim wiederum sofort geschlossen (:q!). Sollen die Änderungen gespeichert werden, wird noch überprüft, ob es sich um eine existierende Datei handelt (:wq) oder ob sie neu angelegt werden muss. Muss die Datei erstellt werden, wird man nach dem gewünschten Dateinamen gefragt (:wq $dateiname).
Die Vorteile des Scripts liegen auf der Hand: Es reagiert auf die jeweilige Situation um vim möglichst effizient und schnell zu beenden. Im Vergleich zum herkömmlichen Beeden muss man nicht mehr den jeweils richtigen Befehl eingeben. Es braucht auch nur eine einzige Tastenkombination in das Mapping eingetragen werden (ein Tastendruck für das Beenden).
""""""""""""""""""""""""""""""""""""""""""""""" " myquit.vim " Author: Julian <julian@tuxoid.net> " URL: http://www.tuxoid.net/stuff/myquit.vim " Version: 1.0 - Mi 8. Sep 11:37:31 CEST 2010 " License: CC 3.0 BY-NC-SA """"""""""""""""""""""""""""""""""""""""""""""" """"""""""""""""""""""""""""""""""""""""""""""" " Installation: " 1) copy myquit.vim to ~/.vim/scripts " 2) edit .vimrc and insert: " :so $HOME/.vim/scripts/myquit.vim " map <F8> :call MyQuit()<CR> """"""""""""""""""""""""""""""""""""""""""""""" function! MyQuit() " file modified / not stored yet if(&modified == 1) " should the file be saved or not?" let inp = input('save current file? (y)es/(n)o: ') " save file if(inp == "y") " file already exists if(expand('%:p') != "") exec "wq" " file doesn't exist, ask for filename else let fname = input('filename: ') exec "wq" fname endif " don't save file => quit immediately elseif(inp == "n") exec "q!" endif " file not modified => quit immediately else exec "q" endif endfunction
Die aktuellste Version des Scripts ist unter tuxoid.net/stuff/myquit.vim zu finden!
Das Script kann nun an einen beliebigen Ort kopiert werden. Ich habe es unter ~/.vim/scripts abgelegt. In der .vimrc macht man nun noch folgende Angaben, um das Script einzubinden und die Taste zu belegen:
:so $HOME/.vim/scripts/myquit.vim map <F8> :call MyQuit()<CR>
Würde mich sehr über Feedback freuen.
C programmieren mit vim
Mit vim, dem vielseitigen und hoch konfigurierbaren Editor, kann man sich auch sehr einfach eine kleine IDE für C bauen. Ziel ist es den geschriebenen Quellcode direkt in vim zu kompilieren und auszuführen. Dazu ist nur ein wenig Konfigurationsarbeit in der vimrc nötig.
Zunächst macht man Angaben zum Compiler:
Falls der Dateityp auf .c endet (autocmd Filetype c), soll bei Eingabe von “:make” folgender Befehl ausgeführt werden: gcc dateiname.c -o dateiname. Der Eintrag in der vimrc sieht wie folgt aus:
autocmd FileType c let &makeprg='gcc % -o %<'
Das % steht hierbei für den Dateinamen mit der Dateiendung und das %< für den Dateinamen alleine.
Desweiteren ist es hilfreich die Fehlerausgaben des Compilers sich besser lesbar ausgeben zu lassen (hier: Datei:Zeile:Spalte:Meldung):
let &errorformat='%f:%l:%c:%m'
Nun zu der eigentlichen Konfigurierung:
Im folgenden werden zwei Funktionen definiert. Die erste speichert beim Aufruf die Datei (:w) und kompiliert den Quellcode (:make). Die zweite Funktion macht zunächst das gleiche, führt aber anschließend die kompilierte Datei aus (:!./dateiname).
func! _gcc() exec "w" exec "make" endfunc func! _gccs() exec "w" exec "make" exec "! ./%<" endfunc
Nun werden noch beide Aufrufe der Funktionen auf eine beliebiger Taste gelegt (Mapping). Hier lege ich sie auf die Tasten F3 und F4, wobei nmap bedeutet, dass dieses Mapping nur für den Normalmodus/Kommandomodus gültig ist.
nmap <F3> :call _gcc()<CR> nmap <F4> :call _gccs()<CR>
Und was ohnehin in jede vimrc hinein gehört, um die Syntax farblich hervorzuheben (syntax highlighting):
syntax on
Über ein Addon/Script kann man sich dann noch die Projektdateien in einer Art Dateibrowser anzeigen lassen. Es nennt sich sinnvollerweise project.
Damit man im Quellcode steht den Überblick behält unterstützt vim auch das Falten (Folding), womit sich geklammerte Terme ausblenden lassen. Das ist aber wiederum so umfangreich, dass ich hier in diesem Artikel nicht weiter darauf eingehen möchte. Eine gute Anlaufstelle ist, wie immer, die Hilfe (:help folding).
Da vim so unglaublich variabel ist, lässt er nahezu keine Wünsche offen und die oben beschriebene “IDE” ist nur eine von vielen Möglichkeiten.