kiss:shell-safari_losungen
Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
Beide Seiten der vorigen RevisionVorhergehende ÜberarbeitungNächste Überarbeitung | Vorhergehende Überarbeitung | ||
kiss:shell-safari_losungen [2014/04/24 13:19] – /* Shell-Konfiguration und Customization -- Aliase, Shell-Voids und die .rc */ jbergner | kiss:shell-safari_losungen [2014/04/24 18:56] (aktuell) – /* Programmieren: Compilerflags */ jbergner | ||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
+ | Dies sind Musterlösungen zur Shell-Safari. Natürlich mag es für jeden der Beispielfälle noch weitere Lösungen geben als die hier vorgestellten. | ||
+ | |||
+ | Insgesamt hoffe ich, dir hat die Shell-Safari wenigstens ein bisschen Spaß und Inspiration gebracht. ^^ | ||
+ | |||
+ | |||
+ | ====== Elementar: Dateisystem ====== | ||
+ | |||
+ | |||
+ | ' | ||
+ | mkdir Safari | ||
+ | ('make directory' | ||
+ | cd | ||
+ | ohne Parameter wechselt standardmäßig ins eigene Homeverzeichnis, | ||
+ | cd .. | ||
+ | ins übergeordnete Verzeichnis. | ||
+ | |||
+ | |||
+ | ====== Elementar: Hilfe bekommen ====== | ||
+ | |||
+ | man | ||
+ | Ist der Befehl zum Aufruf des MANuals, dem man als Parameter den entsprechenden Befehl (oder auch eine C++-Methode) übergeben kann. | ||
+ | man ls | ||
+ | ruft folgerichtig die Dokumentation von ' | ||
+ | |||
+ | Der Parameter | ||
+ | --help | ||
+ | funktioniert nicht bei allen Befehlen, aber bei denen, die ihn unterstützen, | ||
+ | |||
+ | Zusammen erhält man | ||
+ | ls *.pdf # Geier nach Dateinamen sortiert | ||
+ | ls -r *.pdf # Geier nach Dateinamen in umgekehrter Reihenfolge sortiert | ||
+ | ls -S *.pdf # Geier nach Dateigröße (größter zuerst) | ||
+ | ls -Slh *.pdf # S --> wie oben, l --> mehr Infos, h --> human-readable | ||
+ | |||
+ | |||
+ | ====== Elementar: Redirect, less, more, cat, grep und die Pipe ====== | ||
+ | |||
+ | |||
+ | Die Ausgabe einer vollständigen Dateiliste erfolgt mit | ||
+ | ls -lh *.pdf | ||
+ | Allerdings erhalten wir hier viel mehr Information: | ||
+ | -rw-r--r-- 1 owner group 263K Apr 26 2007 001.pdf | ||
+ | -rw-r--r-- 1 owner group 328K Apr 26 2007 002.pdf | ||
+ | -rw-r--r-- 1 owner group 317K Apr 26 2007 003.pdf | ||
+ | -rw-r--r-- 1 owner group 393K Apr 26 2007 004.pdf | ||
+ | -rw-r--r-- 1 owner group 428K Apr 26 2007 005.pdf | ||
+ | ... | ||
+ | Eigentlich interessieren wir uns nur für die erste, die dritte, die fünfte und die letzte Spalte. | ||
+ | |||
+ | Man erreicht dies mit folgender Erweiterung fast: | ||
+ | ls -lh *.pdf | cut -d " " -f 1,3,5,9 | ||
+ | Ausgabe: | ||
+ | -rw-r--r-- owner 263K 2007 | ||
+ | -rw-r--r-- owner 328K 2007 | ||
+ | -rw-r--r-- owner 317K 2007 | ||
+ | -rw-r--r-- owner 393K 2007 | ||
+ | -rw-r--r-- owner 428K 2007 | ||
+ | ... | ||
+ | -rw-rw-r-- owner 221K 064.pdf | ||
+ | -rw-rw-r-- owner 105K 065.pdf | ||
+ | -rw-rw-r-- owner 205K 066.pdf | ||
+ | -rw-rw-r-- owner 209K 067.pdf | ||
+ | -rw-rw-r-- owner 219K 068.pdf | ||
+ | ... | ||
+ | Was passiert hier? | ||
+ | |||
+ | Nun, ' | ||
+ | |||
+ | Wie bekommen wir es nun hin, dass cut wirklich immer die //letzte// Spalte (statt der 9.) ausgibt? Nun, nicht ohne weitere Tools. Eine Variante wäre, statt ' | ||
+ | ls -lh *.pdf | awk ' | ||
+ | awk hat allerdings eine recht gewöhnungsbedürftige Syntax. | ||
+ | Eine andere Variante wäre | ||
+ | ls -lh *.pdf | sed ' | ||
+ | Wir sehen hier, dass man auch mehr als eine Pipe benutzen kann. (Der sed-Befehl wird später noch ausführlicher diskutiert. Hier ersetzt er schlicht zwei Spaces durch eines, bevor dann diese Ausgabe erneut gepiped wird und so zu cut gelangt. | ||
+ | |||
+ | Nun soll das Ganze noch in eine Textdatei. Heißt diese filelist.txt, | ||
+ | ls -lh *.pdf | sed ' | ||
+ | ls -lh *.pdf | sed ' | ||
+ | Das '>' | ||
+ | |||
+ | Der Unterschied zwischen den beiden Varianten besteht darin, dass '>' | ||
+ | |||
+ | Kommen wir als nächstes zu ' | ||
+ | more filelist.txt | ||
+ | less filelist.txt | ||
+ | würden also die Textdatei filelist.txt " | ||
+ | |||
+ | Um als nächstes die Dateigröße von Geier 153 auszugeben, kann man nun entweder die Textdatei mit less oder more aufrufen und mit '/' | ||
+ | ls -lh 153.pdf | ||
+ | Alternativ kann man auch die Ausgabe von 'ls -lh' nach less oder more pipen: | ||
+ | ls -lh *.pdf | less | ||
+ | Nun kann man wieder mit '/' | ||
+ | |||
+ | Natürlich gibt es noch weitere Möglichkeiten. hier ging es primär darum, dass man less (oder more) sowohl per Pipe eine Ausgabe übergeben kann, als auch beide mit nachfolgendem Parameter " | ||
+ | |||
+ | Am Ende noch kurz zu cat, das tatsächlich auch einfache Textdateien ausgeben kann. (Aber noch viel mehr!) | ||
+ | cat filelist.txt | ||
+ | cat filelist.txt | less # Ausgabe der Textdatei filelist.txt mit less (Hier wie 'less filelist.txt' | ||
+ | cat filelist.txt | grep " | ||
+ | grep " | ||
+ | Hier lernen wir den (unglaublich nützlichen) Befehl ' | ||
+ | cp filelist.txt filelist2.txt | ||
+ | grep " | ||
+ | Wir erhalten nun zweimal das altbekannte Ergebnis, aber grep sagt uns auch, in welcher Datei es fündig geworden ist. | ||
+ | |||
+ | Damit können wir die Suche nach der Dateigröße von Geier 153 noch verschönern: | ||
+ | ls -l | grep " | ||
+ | |||
+ | |||
+ | ====== Skripting: Ein erstes kleines Shell-Skript ====== | ||
+ | |||
+ | |||
+ | Shell-Skripte können grundsätzlich jede Dateiendung haben, aber um sie sofort zu erkennen, bietet es sich an, die Erweiterung ' | ||
+ | |||
+ | In diesem Beispiel heißt das Shell-Skript ' | ||
+ | |||
+ | Zunächst schauen wir uns die einzelnen Elemente des Skriptes an: | ||
+ | #!/bin/bash | ||
+ | ist die erste Zeile des Skriptes. In ihr wird festgelegt, dass alle weiteren Zeilen mit dem Programm '/ | ||
+ | #!/bin/zsh | ||
+ | oder | ||
+ | #!/bin/sh | ||
+ | funktionieren auch, sofern die Shells installiert sind und im Verzeichnis /bin tatsächlich auch liegen. (Hier gibt es zum Teil Unterschiede je nach verwendeter Linux-Distribution. ARCH Linux hat die Shells zum Beispiel zwischenzeitlich in /usr/bin gelegt und für Kompatibilität unter /bin verlinkt.) | ||
+ | |||
+ | Kommen wir nun zu den nächsten Zeilen: | ||
+ | # Dieses Shell-Skript erstellt einen neuen Unterordner, | ||
+ | # wechselt in diesen, lädt ein neues Archiv vom Fachschaftsserver | ||
+ | # und entpackt dieses | ||
+ | Diese sind einfach Kommentare; zu erkennen an der vorangestellten Raute '#' | ||
+ | |||
+ | Nun folgen die eigentlichen Befehle: | ||
+ | mkdir queken | ||
+ | cd queken | ||
+ | wget https:// | ||
+ | unzip Safari_queken.zip | ||
+ | Diese sind bereits bekannt und deswegen erspare ich mir, hierauf dezidiert einzugehen. | ||
+ | |||
+ | Nun bleibt allerdings die Frage: Wie startet man so ein Skript? | ||
+ | |||
+ | Man kann einfach | ||
+ | bash quekengetter.sh | ||
+ | zsh quekengetter.sh | ||
+ | sh quekengetter.sh | ||
+ | ... | ||
+ | am Prompt eingeben, aber dann wäre es relativ sinnlos, im Skript selber spezifiziert zu haben, womit es laufen soll. | ||
+ | |||
+ | Eine schönere Variante (die auch für Binärdateien und eigentlich alles ausführbare funktioniert) ist | ||
+ | ./ | ||
+ | |||
+ | Allerdings muss dafür das Shell-Skript als ausführbar markiert sein, was standardmäßig nicht der Fall ist. Ein 'ls -l' würde wohl etwa folgende Ausgabe haben: | ||
+ | -rw-rw-r-- 1 owner group 203 Apr 22 02:06 quekengetter.sh | ||
+ | Will man das Skript ausführen, so kann man mit dem Befehl | ||
+ | chmod u+x quekengetter.sh | ||
+ | das Attribut ' | ||
+ | -rwxrw-r-- 1 owner group 203 Apr 22 02:06 quekengetter.sh | ||
+ | Nun kann der Besitzer ' | ||
+ | ./ | ||
+ | ausführen. Will man auch der zugewiesenen Gruppe ' | ||
+ | chmod g+x quekengetter.sh | ||
+ | chmod o+x quekengetter.sh | ||
+ | Man kann auch kombinieren: | ||
+ | chmod ug+x quekengetter.sh | ||
+ | chmod go+x quekengetter.sh | ||
+ | chmod ugo+x quekengetter.sh | ||
+ | |||
+ | |||
+ | ====== Skripting: Variablen ====== | ||
+ | |||
+ | |||
+ | Hat man das Skript ' | ||
+ | ./lines.sh < | ||
+ | |||
+ | Gehen wir nun genauer die einzelnen Zeilen durch. | ||
+ | #!/bin/bash | ||
+ | ## Kennen wir schon. | ||
+ | | ||
+ | ZEILEN=$(cat $1 | wc -l) | ||
+ | ## $(...) sagt, dass ' | ||
+ | ## Den Befehl ' | ||
+ | ## Beim Aufruf mit ' | ||
+ | ## Die folgende Pipe (' | ||
+ | ## Textdatei zählt. ' | ||
+ | ## der übergebenen Datei. | ||
+ | ## ZEILEN=... definiert eine neue (oder redefiniert eine bestehende) Variable ' | ||
+ | ## Hier wird also die Zahl der Zeilen der übergebenen Datei bestimmt und in der Variable ' | ||
+ | | ||
+ | echo "Die Datei $1 hat ${ZEILEN} Zeilen." | ||
+ | ## Dies ist einfach eine Ausgabe. Man kann die Inhalte der Variablen ausgeben mit vorangehendem $-Zeichen. | ||
+ | ## Hier muss man allerdings auf den Kontext achten. in einer "" | ||
+ | ## oder wenn man den String gar nicht mit Anführungszeichen klammert. (s. oben) | ||
+ | ## Zu diesem Thema (Escaping) folgt unten noch mehr. | ||
+ | |||
+ | Kommen wir nun zum Shell-Skript, | ||
+ | #!/bin/bash | ||
+ | | ||
+ | ls -1l | sed ' | ||
+ | | ||
+ | if [ "$(cat dummy.foo | wc -l)" == 0 ] | ||
+ | then | ||
+ | echo "No files matching pattern found." | ||
+ | else | ||
+ | cat dummy.foo | grep -v " | ||
+ | fi | ||
+ | | ||
+ | if [ -e dummy.foo ] | ||
+ | then | ||
+ | rm dummy.foo | ||
+ | fi | ||
+ | |||
+ | Das ist noch recht einfach und basiert nur auf bekanntem Gedöhns deswegen kommentiere ich das jetzt nicht erheblich weiter. Man achte allerdings auf den Backslash vor dem ' | ||
+ | ls -1l | sed ' | ||
+ | Er deutet an, dass das folgende Zeichen " | ||
+ | |||
+ | Escaping funktioniert je nach Kontext ein wenig unterschiedlich und ist eine beliebte Fehlerquelle. Es würde hier zu weit führen, sie hier en detail zu erklären. Am einfachsten ist es, wenn man hier " | ||
+ | |||
+ | Des Weiteren sollte es zwischenzeitlich möglich sein, die Funktionalität der anderen Zeilen selber zu ermitteln oder auch einfach zu verstehen. ^^ | ||
+ | |||
+ | Zu Task 2: | ||
+ | #!/bin/bash | ||
+ | | ||
+ | if [ " | ||
+ | then | ||
+ | echo " | ||
+ | GREPSTRING=" | ||
+ | elif [ " | ||
+ | then | ||
+ | echo " | ||
+ | GREPSTRING=" | ||
+ | elif [ " | ||
+ | then | ||
+ | echo " | ||
+ | GREPSTRING=" | ||
+ | else | ||
+ | echo "Wrong parameter passed. Using default" | ||
+ | GREPSTRING=" | ||
+ | fi | ||
+ | | ||
+ | ls -1l | sed ' | ||
+ | | ||
+ | if [ "$(cat dummy.foo | wc -l)" == 0 ] | ||
+ | then | ||
+ | echo "No files matching pattern found." | ||
+ | else | ||
+ | cat dummy.foo | grep -v " | ||
+ | fi | ||
+ | | ||
+ | if [ -e dummy.foo ] | ||
+ | then | ||
+ | rm dummy.foo | ||
+ | fi | ||
+ | |||
+ | Task 3: | ||
+ | #!/bin/bash | ||
+ | | ||
+ | if [ " | ||
+ | then | ||
+ | GREPCMD=" | ||
+ | else | ||
+ | GREPCMD=" | ||
+ | fi | ||
+ | | ||
+ | if [ " | ||
+ | then | ||
+ | echo " | ||
+ | GREPSTRING=" | ||
+ | elif [ " | ||
+ | then | ||
+ | echo " | ||
+ | GREPSTRING=" | ||
+ | elif [ " | ||
+ | then | ||
+ | echo " | ||
+ | GREPSTRING=" | ||
+ | else | ||
+ | echo "Wrong parameter passed. Using default" | ||
+ | GREPSTRING=" | ||
+ | fi | ||
+ | | ||
+ | ls -1l | sed ' | ||
+ | | ||
+ | if [ "$(cat dummy.foo | wc -l)" == 0 ] | ||
+ | then | ||
+ | echo "No files matching pattern found." | ||
+ | else | ||
+ | cat dummy.foo | grep -v " | ||
+ | fi | ||
+ | | ||
+ | if [ -e dummy.foo ] | ||
+ | then | ||
+ | rm dummy.foo | ||
+ | fi | ||
+ | |||
+ | |||
+ | ====== Skripting: Bilder ====== | ||
+ | |||
+ | |||
+ | < | ||
+ | |||
+ | for f in *.png | ||
+ | do | ||
+ | convert -density 300 -units PixelsPerInch ${f} ${f%.png}.eps | ||
+ | done | ||
+ | |||
+ | for f in *.eps ; do epstopdf ${f} ; done | ||
+ | |||
+ | pdftk baby{0..26}.pdf cat output combined.pdf | ||
+ | </ | ||
+ | |||
+ | ====== Shell-Konfiguration und Customization -- Aliase, Shell-Voids und die .< | ||
+ | |||
+ | |||
+ | Da diese Aufgabe weitgehend Recherche ist, beschränke ich mich nur auf den letzten Punkt. | ||
+ | |||
+ | < | ||
+ | wget http:// | ||
+ | } | ||
+ | </ | ||
+ | publicip | ||
+ | in der Shell aufgerufen werden kann. | ||
+ | |||
+ | Im deinem Homeverzeichnis liegt eine (versteckte) Datei .bashrc (bzw. .zshrc, etc.) in die Aliase, Shell-Voids, | ||
+ | |||
+ | |||
+ | ====== Programmieren: | ||
+ | |||
+ | |||
+ | Das Programm ' | ||
+ | g++ intro.cpp | ||
+ | Dies liefert ein ausführbares Programm mit dem Namen ' | ||
+ | ./a.out | ||
+ | gestartet werden kann. | ||
+ | |||
+ | Optional kann man auch | ||
+ | g++ intro.cpp -o < | ||
+ | zum compillieren verwenden, was als Ausgabe statt der ' | ||
+ | ./< | ||
+ | aufzurufen ist. | ||
+ | |||
+ | Dieses Programm gibt im Wesentlichen zwei Textzeilen aus, aber während das eine eine " | ||
+ | |||
+ | Um nun beide Ausgaben in eine Datei zu leiten, ist ein simples '>' | ||
+ | |||
+ | Das impliziert bereits, dass es noch eine andere als die Standardausgabe ' | ||
+ | |||
+ | Um //beide// Ausgaben zu pipen, kann man '&>' | ||
+ | ./< | ||
+ | Für weitere Kombinationen von Umleitungen kann man sich auf die Website [[http:// | ||
+ | |||
+ | Das Programm ' | ||
+ | g++ sequenziell.cpp -o sequenziell | ||
+ | Der Aufruf erfolgt mit | ||
+ | ./ | ||
+ | Dieses Programm ist primär dazu da um zu zeigen, wie man an ein selbstgeschriebenes Programm Parameter übergeben kann. Und Überraschung! Das geht wie bei Shell-Skripten. ^^ | ||
+ | |||
+ | |||
+ | ====== Programmieren: | ||
+ | |||
+ | |||
+ | Das Programm ' | ||
+ | sudo apt-get install gcc versuchen. | ||
+ | |||
+ | Das reicht aber noch nicht aus. Wenn man versucht, einfach mit | ||
+ | g++ parallel.cpp -o parallel | ||
+ | zu compillieren, | ||
+ | / | ||
+ | parallel.cpp: | ||
+ | parallel.cpp: | ||
+ | parallel.cpp: | ||
+ | parallel.cpp: | ||
+ | collect2: error: ld returned 1 exit status | ||
+ | Das Problem ist, dass der Compiler nicht weiß, was er mit dieser Zeile tun soll: | ||
+ | #include < | ||
+ | Hier würden die omp-Methoden deklariert und die entsprechende Datei wird schlicht nicht gefunden. | ||
+ | |||
+ | Dies ändert man mit dem **Compilerflag** ' | ||
+ | g++ -fopenmp parallel.cpp -o parallel | ||
+ | |||
+ | Nun kann man mit | ||
+ | ./parallel .5 100000000 | ||
+ | das Programm aufrufen. | ||
+ | |||
+ | Wenn man nun ein zweites Terminal startet kann man zum Beispiel mit ' | ||
+ | |||
+ | Die Laufzeiten verrät einem der Befehl ' | ||
+ | time ./parallel .5 100000000 | ||
+ | bzw.: | ||
+ | time ./ | ||