Shell Quoting verstehen

Axel Beckert

Symlink.ch / ISG D-PHYS, ETH Zürich

abe@noone.org
http://noone.org/abe/

Übersicht

  • Was ist Quoting?
  • Wozu brauche ich das?
  • Die drei Ebenen des Shell Quotings
  • Beispiel
  • Auswertungsreihenfolge am Beispiel der Bourne Shell
  • Zusammenfassung
  • Ressourcen

Was ist Quoting?

  • Quoting ist das Entfernen der besonderen Bedeutung bestimmter Zeichen in Zeichenketten, sodass diese literal verwendet werden.
  • Setzt man hierzu ein Zeichen vor das zu quotende Zeichen, wird gerne auch von Escaping gesprochen, obwohl dieser Begriff eigentlich eine umfangreichere Bedeutung hat.
  • Vermutlich am häufigsten gequotet wird das Leerzeichen.

Wozu brauche ich Quoting?

  • mv Ein Lied.mp3 Ein-Lied.mp3
  • fgrep -rc Changelog (Oder wie lösche ich eine Datei mit Namen "-rf ."?)
  • echo <Ctrl-C> muss man auch irgendwie quoten.

Die drei Ebenen des Shell Quotings

  • Terminal- und Schnittstellen-Quoting
  • Kommandozeilen-Quoting — das eigentliche Shell Quoting
  • Anwendungsquoting

Terminal- und Schnittstellen-Quoting

  • Quoting von Zeichen oder Tastendrücke (z.B. Ctrl-C, Ctrl-Z, etc.), die von Terminal (z.B. VT52) oder Anwendung bzw. interaktiver Shell (z.B. Emacs, Bash/Readline, etc.) direkt interpretiert werden.
  • Quoting oft mit Ctrl-V oder Ctrl-Q.
  • Shell: echo <Ctrl-V><Ctrl-C> muss man auch irgendwie quoten.
  • Emacs und Konsorten: Ein <Ctrl-Q><Ctrl-C> muss man auch irgendwie quoten.
  • Viele vi-Klone: Ein <Ctrl-C> muss man im Insert-Modus nicht extra quoten.

Umkonfigurieren:

  • bash/readline via .inputrc: Control-v: quoted-insert
  • tcsh via .tcshrc: bindkey -b ^v quoted-insert
  • GNU Emacs via .emacs: (global-set-key "\C-q" 'quoted-insert)

Quoting zwischen Benutzer und Shell

  • ssh: ~ muss in einer ssh-Session am Zeilenanfang durch ~~ (bei toter Tilde mit ~<Leerzeichen>~<Leerzeichen>) gequotet werden, falls sie zusammen mit dem nächsten Tastendruck ein ssh-Kommando (z.B. ~? oder ~^Z) ergibt.
  • screen: Ein ^A muss in einem Screen durch <Ctrl-A> <A> gequotet werden.

Kommandozeilen-Quoting

  • Quoting von Zeichen, die die Shell zum Trennen von Parametern, als Wildcard, für Ein- und Ausgabe-Umleitung, als Variablen oder als Quoting-Zeichen interpretieren würde.
  • Umschliessen mit Gänsefüsschen oder einfachen Anführungszeichen.
  • Escaping mit Backslash: Nimmt dem darauffolgenden Zeichen seine besondere Bedeutung (Ausnahmefall: Zeilenumbruch).
  • Expansion von Wildcards mit set -f abschalten (nur bash)

Unterschied zwischen "..." und '...'

  • "..." verhindert die Interpretation von Wildcards, Ein- und Ausgabe-Umleitung, einfachen Anführungszeichen, Leerzeichen, Tab und Zeilenumbruch.
  • '...' verhindert die besondere Interpretation aller Zeichen (inkl. Backslash) ausser einfachen Anführungszeichen selbst, d.h. '\'' geht nicht. (Ausnahme: Quotet kein Ausrufezeichen in der tcsh → History-Expansion dort auch innerhalb von einfachen Anführungszeichen.)

Anwendungsquoting

  • Quoting von Parametern sodass die Anwendung diese nicht als Option oder sonstwie besonderen Parameter betrachtet.
  • Von Anwendung zu Anwendung verschieden, jedoch oft gleich oder ähnlich.
  • Kommen die gleichen Quoting-Zeichen wie beim Kommandozeilen-Quoting vor, muss tlw. doppelt gequotet werden.
  • Manchmal einfach nicht möglich → schlecht programmiert.

Oft benötigtes Anwendungsquoting

  • ./- statt - für Dateien, die mit Minus beginnen: mv ./-foo foo
  • -- als Abschluss der Optionen-Liste (u.a. GNU Utilities): fgrep -- -rc Changelog
  • ./ vor Dateinamen mit Doppelpunkt bei scp und tar: tar cvzf ./bla:fasel.tgz blafasel; scp ./bla:fasel.tgz host:bla:fasel.tgz

Beispiel

Wir wollen eine Datei umbenennen, deren Name aus einem Minus (»-«), einer Pipe (»|«) und einem Ctrl-C (»^C«) besteht: mv -|^C foobar

  1. Parameter, die mit »-« beginnen, sieht mv als Optionen.
    Quoting mit vorangestelltem »./«: mv ./-|^C foobar
  2. »|« ist ein Sonderzeichen der Shell für die Umleitung von Ein- und Ausgabe. Quoting mit vorangestelltem Backslash »\«: mv ./-\|^C foobar
  3. Ctrl-C wird von der Shell abgefangen und bricht die Eingabe ab. Quoting mit vorangestelltem Ctrl-V: mv ./-\|^V^C foobar

Auswertungsreihenfolge am Bsp. der sh

  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 Inhalte und Backquoting (»`...`«, tlw. auch »$(...)«) durch Output.
  3. Nochmals Aufsplitten an Leerzeichen, Zeilenumbrüchen und Tabs, etc. (ausser bei "`...`" oder "$VAR")
  4. Globbing (Auswerten von Wildcards)
  5. Quoting (beim Parsen erkannte Anführungszeichen und Backslashes) entfernen.

Zusammenfassung

  • Beim Quoting immer erst überlegen, auf welcher Ebene das Quoting notwendig ist.
  • Bei der Verwendung von Variablen oder Backticks immer daran denken, dass ein zweites Mal an Leerzeichen aufgesplittet wird → passend quoten.
  • ... dann klappt's auch mit dem Nachbarn. ;-)

Ressourcen

Danke

  • Uwe Waldmann
  • Eric A. Meyer für S5
  • Martin F. Krafft
  • Thomas Deutsch