Skripte gehören uns

Einleitung

Was sind Skripte?

von Macedonio Fernandez

Skripte sind normale Textdateien, in denen wir jede mögliche Anzahl von Befehlen eintragen. Selbstverständlich erfordern jene Befehle eine spezifischen Form, aber die gute Sache ist, dass die Syntax, die wir erlernen müssen, verhältnismäßig einfach ist, solange unsere Ziele nicht zu ehrgeizig sind.

Was kann ein Skript für mich tun?

Es kann in verschiedenen Ordnern bestimmte Dateien sortieren; es kann an einem gegebenen Moment über ein Pop-Up Fenster die Drehzahl des Ventilators ausgeben; oder er kann eine tägliche eMail an die derzeitige Verwaltung der Vereinigten Staaten schicken, und ihnen die Probleme unserer lokalen Wirtschaft erklären. Die schöne Sache an Skripten ist, dass Sie sie genauestens auf Ihre Problematik anfertigen können und die Skripte, die Sie geschrieben haben, auch das Leben anderer Leute einfacher machen können.

In dieser Ausgabe stellen wir ein sehr einfaches Skript vor (mit zwei Varianten), welches uns erlaubt, jede mögliche Anzahl von Archiven zu extrahieren, die wir in Konqueror auswählen.

Dieses Skript hat zwei Vorteile: es ist eine Alternative zu Ark's Service-Menü, welches mehrfache Extraktionen anscheinend nicht richtig behandelt ; im Gegensatz zu Ark identifiziert es Passwort-geschützte Dateien und bittet uns, das Kennwort einzugeben. Das wichtigste Ziel ist jedoch, mit den Grundlagen von bash-Skripten vertraut zu werden.

TEIL 1: Ein Beispielskript verstehen

Dazu erklären wir kurz die Syntax und Verwendung der Befehle.

basename

Dies gibt den Namen einer gegebenen Datei, nicht aber den vollständigen Pfad an. Es kann auch nur den Namen der Datei ohne die Extension ausgeben, vorausgesetzt dass wir die Extension in der Befehlszeile angeben.

Beispiel: wenn der komplette Pfad zu einer Datei /home/john/download/random.txt ist, dann können wir den folgenden Befehl ausführen:

$ basename random.txt

Dieses ergibt: random.txt.

Wenn wir den Namen der Datei, aber ohne die Extension erhalten wollen, spezifizieren wir die Extension mit einem vorausgehenden Punkt nach dem Namen der Datei:

$ basename random.txt .txt

Dieses ergibt: random

FOR (DONE)

FOR ist ein Befehl (eigentlich eine Schleife) der dem Interpreten erklärt, die folgenden Befehle für jedes Mitglied einer Gruppe laufen zu lassen. Was ist diese Gruppe? Es könnte eine in Konqueror ausgewählte Dateiengruppe sein (wie wir in diesem Beispiel sehen werden), eine Gruppe von Dateien in einer Liste (wie im Beispiel unten), eine Liste von Namen, eine Reihenfolge von Zahlen, etc.

Beispiel:

for i in (random.txt michael.pdf lars.odt); do
  cp $i /home/john
done

Dieses Skript würde alle Dateien innerhalb der Klammern nach /home/john kopieren. Dies jedoch nicht auf einmal, sondern eins nach dem anderen.

Daher ist FOR eine Schleife, d.h. es startet einen Zyklus mit allen spezifizierten Elementen. Im oben genannten Beispiel würde es zuerst random.txt zu /home/john kopieren, danach kopiert es michael.pdf, etc.

Obwohl dieses Skript in dieser Form zweifellos unbrauchbar ist, ist der Vorteil der FOR Schleife, dass sie jede Datei der Reihe nach verarbeitet: es kann zum Sortieren verschiedener Dateien in Verzeichnissen verwendet werden, oder zum Entfernen oder Backups von bestimmten Dateien, etc. (diese Funktion wird für uns nützlich sein).

Was hier in der ersten Zeile wichtig ist, ist das wir i den Wert zugewiesen haben der nach dem = Zeichen steht. In jeder Schleife entspricht der Ausdruck $i jedem Elemente der Gruppe. Im ersten Durchlauf ist $i random.txt, im zweiten Durchlauf ist es gleich michael.pdf, und so weiter.

Der Ausdruck done zeigt an, dass die Schleife beendet ist und das, bei einem Neustart $i zurückgesetzt wird und einem neuen Wert annimmt.

IF (THEN); ELSE, ELIF

Wie der Name schon andeutet beschreibt die IF Anweisung eine zu erfüllende Bedingung, damit die Anweisung ausgeführt werden kann, z.B. : wenn eine gegebene Zahl gerade ist, dann rufen Sie Ihre Schwiegermutter an; wenn eine gegebene Datei leer ist, dann entferne sie; wenn die Temperatur der Festplatte über 50° ist, dann gib eine Warnung aus. Die IF Bedingung wird immer durch FI geschlossen.

ELIF / THEN liefert eine zweite Bedingung, die ausgeführt wird wenn sie wahr ist und die erste Bedingung nicht wahr war. Dies ist zum Beispiel in unserem Skript für folgendes nützlich: wir haben eine Gruppe von Archiven in Konqueror zum Extrahieren ausgewählt; der if Befehl spezifiziert eine bestimmte Aktion für ein .rar Archiv ist; aber wenn es ein .7z Archiv ist, muss es etwas anderes tun.

ELSE sagt was an zu tun ist falls keine der vorherigen (if oder if+elif) Bedingungen erfüllt werden konnten, ohne irgendwelche weiteren Bedingungen zu spezifizieren.

Beispiel: wir haben 15 Dateien, 5 von ihnen sind .rar, 5 sind .tar.gz, 2 sind pdf, 3 sind txt. Wir schreiben ein Skript mit folgenden Bedingungen: IF eine bestimmte Datei ein .rar Archiv ist, dann extrahiere es: ELIF die Datei ein .tar.gz-Archiv ist, dann extrahiere es und entferne das ursprüngliche Archiv; ELSE verschiebe die Dateien in ein anderes Verzeichnis. Diese letzte Aussage trifft auf alle eingegebenen Dateien zu, die keine der IF und ELIF Bedingungen erfüllen.

Beispiel:

for i in ( random.txt michael.pdf lars.odt morris.jpg morris.jpg ); do
  if [[ $i == *.txt ]]; then
   cp $i /home/john/Text_files/
  elif [[ $i == *.pdf ]]; then
   cp $i /home/john/pdfs/
  else cp $i /home/john/other_files/
  fi
done

Erklärung des Skripts

Dieses erste Skript extrahiert alle ausgewählten Archive im aktuellen Verzeichnis, vorausgesetzt dass sie .zip, .rar, .tar.gz, .tar .bz2 oder .7z Archive sind (unabhängig davon, ob die Namen der Archive oder ihre Extensionen gross oder klein geschrieben sind).

SCRIPT 1

1#!/bin/bash -x
2FILE=$1
3cd "${FILE%/*}"
4for i in "$1"; do
5echo -e "\n\nTrying to extract $i"
6if [[ "$i" == *.[Rr][Aa][Rr] ]]; then
7unrar x -ad "$i";
8elif [[ "$i" == *.7[Zz] ]]; then
97za x "$i";
10elif [[ "$i" == *.zip ]]; then
11unzip "$i";
12elif [[ "$i" == *.ZIP ]]; then
13unzip "$i";
14elif [[ "$i" == *.[Tt][Aa][Rr].[Gg][Zz] ]]; then
15tar -xf "$i";
16elif [[ "$i" == *.[Tt][Aa][Rr].[Bb][Zz][2] ]]; then
17tar -xf "$i";
18fi
19done

Und die Erklärung der wichtigsten Zeilen:

1) #!/bin/bash

Diese erste Zeile ist in jedem Skript vorgeschrieben. Sie gibt den zu verwendenden Interpreter an (in unserem Fall: bash).

2) FILE=$1 3) cd "${FILE%/*}"

Diese zwei Zeilen erklären dem Skript, sich auf das Verzeichnis zu konzentrieren, in dem die ausgewählten Dateien sind. Wenn wir dies nicht tun würden, würden alle Dateien in Ihr Home-Verzeichnis extrahiert.

$i steht für das erste Element des Inputs; in unserem Fall für die erste der ausgewählten Dateien. Es steht jedoch für den vollen Pfad der Datei (/home/john/download/random.txt), nicht nur seines basename (random.txt) oder seines Pfads (/home/john/download/).

Wir haben hier den Input der Variablen FILE zugewiesen, die wir in der folgenden Zeile benutzen werden.

Die zweite Zeile trennt den Archivnamen vom vollen Pfad des Inputs ab und lässt nur das Verzeichnis übrig, in das Archiv liegt; folglich ändert cd "${FILE%/*}" das Verzeichnis zum Weg der Eingangsdatei.

4) for i in "$1"; do

Dieses ist der Anfang der FOR Schleife. $i wird zum gesamten Input (alle in Konqueror ausgewählten Dateien), und i nimmt einen neuen Wert in jedem Schleifendurchlauf an. In unserem Fall beginnt der FOR Befehl einen neuen Schleifendurchlauf für jede der ausgewählten Dateien, die dann jeweils separat bearbeitet werden.

5) echo -e "\n\nTrying to extract "$i""

Druckt eine Mitteilung aus, die den Wert von $1 in jedem Schleifendurchlauf angibt.

6) if [[ "$i" == *.[Rr][Aa][Rr] ]]; then

Hier beginnt die IF Bedingung. IF die Eingangsdatei *.rar oder *.RAR oder *.rAr etc. ist (die eckigen Klammern erklären dem Interpreter, dass die Bedingung erfüllt ist, wenn irgendwelche der Kombinationen der angegebenen Buchstaben in der Extension des Archivs erscheinen), THEN mach etwas, in diesem Fall:

7) unrar x -ad "$i";

Dieser Befehl extrahiert das .rar Archiv (dargestellt durch "$1") im aktuellen Verzeichnis. Jetzt kommt ein drittes Element im FOR Befehl: ELIF, was für „ELSE IF“ steht. Was tut es? Wenn die erste Bedingung nicht erfüllt ist (das heißt, wenn die Datei keine .rar Datei ist), stellt sie eine andere zufrieden zustellende Bedingung dar:

8) elif [[ "$i" == *.7[Zz] ]]; then

Was diese und der Rest der folgenden Zeilen tun (Zeilen 10-17) sollte nun klar sein. In diesem Fall sagen wir, dass, wenn die erste Bedingung nicht erfüllt war, aber diese ist, THEN:

9) 7za x "$i";

Die .7z Datei extrahieren.

18) fi

Diese Zeile schließt die IF Bedingung.

19) done

Diese Zeile schließt die FOR Schleife. Obwohl dieses Skript möglicherweise die nützlichste und einfachste Alternative ist, hat es einen Nachteil: wenn die Person, die die Archive erstellte diese nicht in Verzeichnisse organisierte, könnte Ihr aktuelles Verzeichnis total chaotisch aussehen. Um dieses Problem zu vermeiden, können Sie das folgende Skript benutzen.

SCRIPT 2

1#!/bin/bash -x
2FILE=$1
3cd "${FILE%/*}"
4for i in "$1"; do
5echo -e "\n\nTrying to extract "$i""
6if [[ "$i" == *.[Rr][Aa][Rr] ]]; then
7unrar x -ad "$i";
8elif [[ "$i" == *.7z ]]; then
9file_base_name='basename "$FILE" .7z'
10echo -e "\n\nCreating directory $file_base_name"
11mkdir "$file_base_name"
12cd "$file_base_name";
137za x "$i";
14elif [[ "$i" == *.7Z ]]; then
15file_base_name='basename "$FILE" .7Z'
16echo -e "\n\nCreating directory $file_base_name"
17mkdir "$file_base_name"
18cd "$file_base_name";
197za x "$i";
20elif [[ "$i" == *.zip] ]]; then
21file_base_name='basename $FILE .zip'
22echo -e "\n\nCreating directory $file_base_name"
23mkdir "$file_base_name"
24unzip "$i" -d "$file_base_name";
25elif [[ "$i" == *.ZIP ]]; then
26file_base_name='basename $FILE .ZIP'
27echo -e "\n\nCreating directory $file_base_name"
28mkdir "$file_base_name"
29unzip "$i" -d "$file_base_name";
30elif [[ "$i" == *.tar.gz ]]; then
31file_base_name='basename "$FILE" .tar.gz'
32echo -e "\n\nCreating directory $file_base_name";
33mkdir "$file_base_name";
34cd "$file_base_name";
35tar -xf "$i";
36elif [[ "$i" == *.TAR.GZ ]]; then
37file_base_name='basename $FILE .TAR.GZ'
38echo -e "\n\nCreating directory $file_base_name";
39mkdir "$file_base_name";
40cd "$file_base_name";
41tar -xf "$i";
42elif [[ "$i" == *.tar.bz2 ]]; then
43file_base_name='basename $FILE .tar.bz2';
44echo -e "\n\nCreating directory $file_base_name";
45mkdir "$file_base_name";
46cd "$file_base_name";
47tar -xf "$i";
48elif [[ "$i" == *.TAR.BZ2 ]]; then
49file_base_name='basename $FILE .TAR.BZ2';
50echo -e "\n\nCreating directory $file_base_name";
51mkdir "$file_base_name";
52cd "$file_base_name";
53tar -xf "$i";
54fi
55done

Einige Kommentare zu den neuen Zeilen:

6)if [[ "$i" == *.[Rr][Aa][Rr] ]]; then
7)unrar x -ad "$i";

Der Befehl unrar (in Verbindung mit der Modifikation -ad) extrahiert den Inhalt des Archivs mit seinem vollen Pfad . Für andere Archivarten gibt es diese Option aber nicht. Daher erstellen wir ein Verzeichnis mit dem gleichen Namen wie das Archiv, gehen in das Verzeichnis und extrahieren die Dateien dort.

8)elif [[ "$i" == *.7z ]]; then
9)file_base_name='basename "$FILE" .7z'

Hier weisen wir der Variablen file_base_name das Ergebnis des Befehls zu, der bei basename des aktuellen Fall i genannt wird. Wir haben $FILE in Anführungsstrichen eingeschlossen, um Probleme zu vermeiden, wenn der Name der Datei Leerzeichen hat. Wenn die ausgewählte Datei, die jetzt verarbeitet wird, /home/john/download/polka.7z ist, ist das Resultat von basename "$FILE" .7z polka. Und jetzt ist file_base_name=polka (aber nur für diesen Schleifendurchlauf).

11) mkdir "$file_base_name"
12) cd "$file_base_name";
13) 7za x "$i";

Was wir hier tun, ist offensichtlich: wir erstellen ein Verzeichnis mit dem Namen des aktuellen Wertes der Variable, die wir vorher definierten; wir gehen in das neue Verzeichnis und extrahieren die Dateien dort. Die folgenden Zeilen (14-53) machen das Gleiche wie vorher für die verbleibenden Archivarten. (Jede Zeile ist dupliziert, weil das Befehl basename nicht gut mit Extensionen in eckigen Klammern funktioniert).

TEIL 2: Das Skript aktivieren

Was tun wir jetzt?

  1. Das Skript erstellen
    1. Eine leere Textdatei erzeugen.
    2. Den Inhalt von einem der oben genannten Skripte in die Datei einfügen.
    3. Speichern (z.B.: multiple_extract_nofolder.sh).
    4. Sie ausführbar machen. Die einfachste Weise, dies zu tun ist: Rechtsklick auf die erstellte Datei und „Eigenschaften“ vorwählen. Im Vorsprung „Erlaubnis“ wählen „ist ausführbar“.
    5. Ein Ordner erstellen, in dem Sie Backups Ihrer Skripte speichern. (z.B.: ~/.scripts)
    6. Das Skript in dieses Verzeichnis und zu /usr/local/bin kopieren (zum Kopieren in das zweite Verzeichnis brauchen Sie Root-Rechte).
  2. Ein Service-Menü zum Laufenlassen des Skripts erstellen.
    1. Gehen Sie zu ~/.kde/share/apps/konqueror/servicemenus
    2. Erstellen Sie eine neue Textdatei und nennen Sie sie „multiple_extract_nofolder.desktop“ (oder was auch immer Sie wünschen, vorausgesetzt dass Sie die Endung “.desktop“ verwenden), und diese dann mit einem Texteditor (kate, kwrite, etc.) öffnen.
    3. In die neue Datei das folgende einfügen:
      [Desktop Entry]
      Actions=Extract_Multiple_nofolders
      ServiceTypes=all/allfiles
      X-KDE-Priority=TopLevel
      [Desktop Action Extract_Multiple_nofolders]
      Name=Extract archives here
      Icon=package
      Exec=konsole -e bash
      multiple_extract_nofolder.sh %U
      
    4. Die Datei speichern.
    5. Gehen Sie zu einem Verzeichnis mit mehr als einem Archiv.
    6. Die zu extrahierenden Archive auswählen, Rechtsklick auf die Auswahl und auswählen „Extract archives here“.

ANMERKUNG 1

Eine nützliche Alternative zum testen von Skripten ist die exec Zeile so abzuändern:

Exec=konsole --noclose -e bash multiple_extract_nofolder.sh %U

--noclose wird, wie offensichtlich ist, Konsole geöffnet lassen, damit Sie den Ausgang eines jeden Befehls sehen und feststellen können, wo etwas daneben ging.

ANMERKUNG 2

In die .desktop Datei setzen wir die folgende Zeile:

X-KDE-Priority=TopLevel

Diese Zeilen erstellen das Service-Menü in der ersten Spalte, die erscheint, sobald Sie eine Datei rechtsklicken. Wenn wir sie entfernen, erscheint das Service-Menü unter „Tätigkeiten“. Die Wahl hängt davon ab, wie oft Sie das Skript benutzen.

ANMERKUNG 3 (Abhängigkeiten)

Beide Skripte hängen von den folgenden Anwendungen ab (verfügbar in Synaptic): unrar unzip p7zip tar. Falls diese nicht installiert sein sollten, können Sie sie über die folgende als root auszuführende Zeile installieren:

$ apt-get install unrar unzip p7zip tar

Links:

Einleitungen zu Bash
http://www.tldp.org/LDP/Bash-Beginners-Guide/html/
http://tille.garrels.be/training/bash/
http://www.linuxtopia.org/online_books/bash_guide_for_beginners/
http://linux.die.net/Bash-Beginners-Guide/
Erstellen von KDE Service-Menüs
http://developer.kde.org/documentation/tutorials/dot/servicemenus.html
http://wiki.kde.org/tiki-index.php?page=Tips%20and%20Tricks&pagenum=23

Seitenanfang