Kommandozeilen verstehen und effizient nutzen

Chemnitzer Linux-Tage
4. März 2006

Axel Beckert
<abe@noone.org>
http://noone.org/abe/

ÜBERSICHT

Die Shell

Nützliche Tools für die Kommandozeile

Weitere Ressourcen

Was ist eine Shell?

»Shell« (engl. für Muschelschale, Gehäuse) ist der umgangssprachliche Begriff für einen Kommandozeileninterpreter (engl. command line interpreter — CLI), kann aber auch andere Progamme zum interaktiven Aufrufen von Befehlen meinen, z.B. den Windows Explorer, Konqueror, Nautilus, den Norton Commander oder den Midnight Commander.

Kommandozeilen-basierte Shells lesen eine (oder mehrere) Zeilen Text ein, interpretieren diese als Kommando und führen es aus. Im folgenden wird der Begriff Shell mit einem Kommandozeileninterpreter gleichgesetzt.

Auf Unix-Systemen hat jeder Benutzer seine sog. Login-Shell, die Shell, die automatisch aufgerufen wird, wenn sich der User einloggt — egal ob lokal an der Console oder von einem anderen Rechner per SSH. Die Login-Shell kann meist mit dem Befehl chsh geändert werden.

Unter MS-DOS befindet sich der Benutzer nach dem Booten direkt in einer Shell. Unter Windows bekommt man eine Shell meist über das Anwählen des Punktes im Startmenü Eingabeaufforderung.

Eine kleine Übersicht über gängige Shells

Unix

DOS / Windows

Typische Funktionen heutiger Shells

Shell-Syntax: Eine kurze Übersicht (1)

Befehle kombinieren

Ein- und Ausgabe umleiten

Ausgabe als Argumente verwenden

Shell-Syntax: Eine kurze Übersicht (2)

Schleifen in bash, zsh und ksh

     > while true; do echo -n .; sleep 1; done;
     > until false; do echo -n .; sleep 1; done;
     > for i in 1 2 3; do echo $i; sleep 1; done
     > for (( i=1 ; i < 4 ; i++ )) ; do echo $i ; done (nicht ksh)

Schleifen in tcsh, csh

Die Schlüsselkommandos while (...), for (...), foreach (...) und end müssen jeweils in einer eigene Zeile stehen. In der History wird jeweils nur die erste Zeile des Kommandos gespeichert. Die mehrfache Verwendung einer (t)csh-Schleife auf der Kommandozeile ist daher nicht möglich.


     > while (1)
     while? echo -n .; sleep 1;
     while? end

     > foreach i (1 2 3)
     foreach? echo $i; sleep 1;
     foreach? end

Warum braucht man Quoting und wie funktioniert es?

Bestimmte Tasten bzw. Zeichen haben am Terminal, auf der Kommandozeile oder für Anwendungen besondere Bedeutungen, werden manchmal aber auch ohne diese Sonderbedeutung gebraucht. Sie müssen dann "escaped" oder "gequotet" werden.

Die drei Ebenen des Quotens

  1. Terminal
  2. Shell
  3. Anwendung

Nehmen wir z.B. eine Datei, deren Name aus einem Minus (»-«), einem Pipe-Zeichen (»|«) und einem Ctrl-C (»^C«) besteht und die wir umbenennen wollen: mv -|^C foobar
 

  1. Parameter, die mit »-« beginnen, sieht mv als Optionen.
    Quoting mit vorangestelltem »./«: mv ./-|^C foobar
  2. Das Pipe-Zeichen »|« ist ein Sonderzeichen der Shell für die Umleitung von Ein- und Ausgabe.
    Quoting mit vorangestelltem Backslash »\«: mv ./-\|^C foobar
  3. Ctrl-C wird vom Terminal abgefangen und sendet statt dem Zeichen selbst einen Interrupt an das laufende Programm, in diesem Fall die Shell.
    Quoting mit vorangestelltem Ctrl-V: mv ./-\|^V^C foobar

Terminal-Quoting

Shell-Quoting

Anwendungs-Quoting

Auswertungsreihenfolge am Beispiel der Bourne Shell

  1. Syntax des Kommandos analysieren (Parsen): Aufsplitten in Parameter, Quoting, Umleitung von Ein- und Ausgabe, Erkennen (aber nicht Auswerten) von Variablen
  2. Ersetzen von Variablen durch ihre Inhalte und Backquoting (»`...`«, neuere Shells auch »$(...)«) durch den entsprechenden Output
  3. Nochmals Aufsplitten an Leerzeichen, Zeilenumbrüchen, Tabs, etc.
  4. Globbing (Auswerten von Wildcards)
  5. Quoting (beim Parsen erkannte Single Quotes, Double Quotes und Backslashes) entfernen.

History Expansion und Completion

Übliche, aber oft ineffiziente Nutzung der History

History Expansion: Die richtige Zeile

  !!        Letzte Kommandozeile
  !3        Dritte Kommandozeile
  !-2       Vorletzte Kommandozeile
  !foobar   Letzte Kommandozeile, die mit »foobar« begann
  !#        Alles, was bisher in dieser Zeile getippt wurde.
  !?foobar  Letzte Kommandozeile, die »foobar« beinhaltete

History Expansion: Der richtige Parameter

  :*    Alle Parameter, z.B. !!:*
  :^    Erster Parameter, z.B. !less:^
  :$    Letzter Parameter, z.B. !3:$
  :2    Zweiter Parameter, z.B. !-2:2
  :2-4  Zweiter bis vierter Parameter, z.B. !#:-2

History Expansion: Modifizieren

  :h  entfernt letzte Pfadkomponente, z.B. /foo/bar → /foo
  :t  entfernt Pfad von einer Datei, z.B. /foo/bar → bar
  :r  entfernt letzte Dateiendung, z.B. foo.x.y → :r:r → foo
  :e  entfernt alles bis auf die Dateiendung, z.B. foo.bar → .bar
  :u  Großbuchstaben: tcsh erster, zsh alle
  :l  Kleinbuchstaben: tcsh erster, zsh alle
  :p  Ergebnis nur ausgeben, nicht ausführen
  :q  Ergebnis quoten, keine weiteren Ersetzungen
  :x  Ergebnis quoten, keine weiteren Ersetzungen, Parameter an Blanks
      aufsplitten

  :s/a/b/     »a« einmal durch »b« ersetzen
  :gs/a/b/    Alle »a« durch »b« ersetzen
  :as/xx/x/   Im ersten Wort solange wie möglich »xx« durch »x« ersetzen
              (nur tcsh und csh, Gefahr von Endlosschleifen!)
  :ags/xx/x/  Solange wie möglich »xx« durch »x« ersetzen (tcsh, csh)

History Expansion: Kurzformen

  !^, !$, !:2, !*  Erster, letzter, zweiter bzw. alle Parameter des
                   letzten Befehls. Entspricht !!:^, !!:$, !!:2, !!:*
  ^a^b             Ersetze einmal »a« durch »b« im letzten Befehl.
                   Entspricht !!:s/a/b

History Expansion: Beispiele

Ohne History Expansion

> tar cvf foobar-1.2.3woody4_i386.tar foobar > gzip -9v foobar-1.2.3woody4_i386.tar > mv foobar-1.2.3woody4_i386.tar.gz foobar-1.2.3woody4_i386.tgz > mkdir backup > mv foobar-1.2.3woody4_i386.tgz backup > mv backup Backup > cd Backup

Mit History Expansion

> tar cvf foobar-1.2.3woody4_i386.tar foobar > gzip -9v !:2 > mv !$.gz !$:r.tgz > mkdir backup > mv !mv:$ !$ > mv !$ !$:s/b/B > cd !$

Sonstige History-Tricks

History ignoriert mit Leerzeichen beginnende Zeilen

Zeilen, die mit einem Leerzeichen beginnen, werden nicht in der History gespeichert. (Nur bash und zsh, optional.)

bash> HISTCONTROL=ignorespace zsh> setopt HIST_IGNORE_SPACE > echo foo foo > echo bar bar > !! echo foo foo

Kommandozeile in Editor editieren

Mit fc (für "Fix Command" — "Repariere Kommando") kann man bereits eingegebene Kommandozeilen editieren und erneut ausführen. (Nur bash, zsh und ksh.)

Hilfreiche Tastenkürzel rund um die History

In der History interaktiv suchen (Think Emacs)

Worte aus der History einfügen

Häufiges Hin und Her zwischen Verzeichnissen

(Zurück in) Das letzte Verzeichnis

Der Directory Stack

Funktioniert unter bash, tcsh, zsh und z.T. auch in der cmd.exe.
 

Unbekanntere Wildcards und Ähnliches

  > ls
  foo.a   foo.b   foo.b~  foo.c   foo.c~
  > ls foo.[ab]
  foo.a   foo.b
  > ls *[^~]
  foo.a   foo.b  foo.c
  > unset nonomatch
  > touch bar.[fg]
  touch: No match.
  > set nonomatch
  > touch bla.[fg]
  > touch fnord.{f,g}
  > ls
  bla.[fg]   fnord.f   fnord.g   foo.a   foo.b   foo.b~  foo.c   foo.c~

Job Control

Welcher Job?

Job Control abgekürzt

Nützliche Shell-Builtins

Globale Aliasse der zsh

> alias -g T='| tail' > fgrep bla /var/log/messages T > alias -g ...='../..' > cd ...

Achtung! Bei unvorsichtiger Verwendung gefährlich!

Nützliche Tools für die Kommandozeile (1)

Dateien bearbeiten mit sed

Problem: sed -e 's/foo/bar/' datei > datei endet mit Datenverlust.

Lösung: Option Inline-Edit (bei Perl, ssed oder neuerem GNU sed):

> sed -e 's/foo/bar/' -i datei > perl -pe 's/foo/bar/' -i datei

Ausgabe eines Befehles gleichzeitig mitloggen und ansehen

Problem: Man will einerseits direkt die Ausgabe eines Befehls sehen, aber auch in eine Datei mitloggen.

Lösung: Output durch tee dateiname (Mnemonic: T-Kreuzung) pipen: z.B. fgrep 127.0.0.1 /var/log/access.log | tee localhost.log

Mitloggen von In- und Output von Shell-Kommandos

Problem: Man macht umfangreiche Installations- oder Upgrade-Arbeiten in der Shell und will das alles mitprotokollieren.

Lösung: Das Tool script (Paket "bsdutils" bei Debian) startet eine Subshell und protokolliert jeden In- und Output in eine Logdatei.

Nützliche Tools für die Kommandozeile (2.1): screen

  • "Window-Manager" für Text-Modus
  • mehrere Shells in einem Textfenster, Vollbild oder geteilt
  • Rechner wechseln ohne Programme beenden zu müssen.
  • Interaktive Text-Modus-Programme (z.B. MP3-Player, IRC, ICQ, gdb) oder Compile-Jobs laufen lassen ohne permanent eingeloggt zu sein.
  • Von mehreren Shells aus gleichzeitig auf die gleichen Text-Anwendungen zugreifen (nur bei selbem Benutzer).
  • Copy & Paste sowie Zurückscrollen im Textmodus

Aufruf

  • Screen Starten: screen
  • Laufende und detached Screens auflisten: screen -ls
  • Wieder verbinden: screen -r
  • Wieder verbinden und andere Verbindung ausloggen: screen -r -d
  • Verbinden oder Starten, falls kein screen detached ist: screen -R
  • Remote Power Detach: screen -R -D
  • Zusätzlich mit bestehender Session verbinden: screen -x

Nützliche Tools für die Kommandozeile (2.2): screen

Tastaturkommandos

  • Ctrl-A a: Ein "Ctrl-A" eingeben (z.B. zum Zeilenanfang gehen)
  • Ctrl-A ?: Hilfe / Anzeige der Tastaturkommandos
  • Ctrl-A C / Ctrl-A Ctrl-C: Neues Fenster mit Shell
  • Ctrl-A Ctrl-A: Zurück zu letztem Fenster
  • Ctrl-A Space     / Ctrl-A n / Ctrl-A Ctrl-N: Nächstes Fenster
  • Ctrl-A Backspace / Ctrl-A p / Ctrl-A Ctrl-P: Vorheriges Fenster
  • Ctrl-A 0 / Ctrl-A 1 / etc.: Gehe zu Fenster 0, 1, etc.
  • Ctrl-A d / Ctrl-A Ctrl-D: Detach screen
  • Ctrl-A x / Ctrl-A Ctrl-X: Lock screen
  • Ctrl-A t / Ctrl-A Ctrl-T: Uhrzeit und Load anzeigen
  • Ctrl-A Shift-A: Fenstertitel setzen
  • Ctrl-A w: Fensterliste anzeigen
  • Ctrl-A ": Auswahlliste aller Fenster mitsamt Titel anzeigen
  • Ctrl-A Shift-S: Fenster aufteilen
  • Ctrl-A Tab: Zwischen aufgeteilten Fenstern wechseln
  • Ctrl-A Shift-Q: Aktuelles Fenster als einziges anzeigen
  • Ctrl-A [ / Ctrl-A Ctrl-[: Copy & Paste starten. Anfang und Endpunkt jeweils mit Enter markieren, Navigation mit Cursortasten, Block mit c und C)
  • Ctrl-A ] / Ctrl-A Ctrl-]: Paste
  • Ctrl-A h: Screenshot ("Hardcopy")

Nützliche Tools für die Kommandozeile (3)

Umbenennen vieler Dateien auf einmal

Problem: Da unter Unix die Shell die Wildcards auswertet, geht mv *.jpg *.jpeg im Gegensatz zu DOS nicht.

Lösung: Multiple Move (mmv) oder Perl-Skript Rename.

> mmv '*.jpg' '#1.jpeg' > mmv '*---*' '#1 - #2' Debian: > rename 's/jpg$/jpeg/' *.jpg > rename 's/_/ /g' *.mp3 SuSE: > rename jpg jpeg *.jpg

Sonstiges

  • gpm
  • loco, colordiff, colormake, colorgcc
  • cut -c-80 (textutils)
  • less -S, less -N, less +G, less +F, less +/xyz

Links

Danke

  • Den entsprechenden Entwicklern für bash, tcsh, zsh und screen.
  • Lou Montulli, Michael Grobe und Charles Rezac für Lynx
  • dem Debian-Projekt für Debian GNU/Linux

Letzte Änderung an den Quellen: 2006-05-24 23:56:51
Letzte Generierung: 2006-05-24 23:57:03
Generiert von abe@bijou mit WML 2.0.8 (30-Oct-2001)
$Id: shell-efficiency-clt.wml 71 2006-05-24 21:56:49Z abe $