Nützliches für die Kommandozeile

Aus Info-Theke
Version vom 19. März 2023, 08:22 Uhr von Hamatoma (Diskussion | Beiträge) (→‎Die geschweiften Klammern)
(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)
Zur Navigation springen Zur Suche springen

Übersicht über das Konsolen-Tutorial

Zerlegung in Eingabeelemente

Eine Shell zerlegt die Eingabe in einzelne Eingabeelemente, die dann mit den unten beschriebenen Ersetzungen bearbeitet werden.

  • Ein String ist eine mit Stringtrennern eingeschlossene Zeichenfolge.
  • Stringtrenner sind einfacher und doppelter Apostroph: ' und ".
  • Ein Wort ist die jeweils längstmögliche Zeichenfolge ohne Trennzeichen
  • Trennzeichen sind in der Variablen $IFS festgelegt, standardmäßig Leerzeichen, TAB und NEWLINE.
  • Ist ein Eingabelement ein String, ist es kein Wort
echo "1 oder 2" Beispiele 'gefällig?'

Die Shell erkennt 4 Eingabeelemente:

  1. echo
  2. "1 oder 2"
  3. Beispiele
  4. 'gefällig?'

Ersetzungen

Die Bash kennt eine ganze Reihe von Abkürzungen und Ersetzungen:

Ergänzung des Dateinamens

Kommen in einem Wort (nicht String) die Zeichen *, [] oder ? vor, wird dieses Wort durch alle Dateinamen ersetzt, die auf das dadurch gegebene Muster passen. Muster deshalb, weil die oben genannten Platzhalter auf mehrere Dateinamen passen können.

Die Bedeutung der Platzhalter:

  • *: Es können beliebig viele Zeichen an dieser Stelle sein, also auch gar kein Zeichen.
  • ?: Es ist genau ein Zeichen vorhanden.
  • [<liste>]: Es kommt genau ein Zeichen aus der Liste vor. Die Liste besteht aus einer Aufzählung von Einzelzeichen und von Bereichen, wobei letztere durch Anfang, '-' und Ende gebildet werden.
    • [aeiou]: Es kommt genau ein Vokal vor
    • [0-9a-fA-F]: Es kommt genau eine Hexziffer vor
  • [^<liste>]: Es kommt kein Zeichen aus der Liste vor.
    • [^0-9]: Ein Zeichen, das keine Ziffer ist
    • [^-._]: Ein Zeichen, aber nicht '-', '.' oder '_'

Beispiele

Voraussetzung für Nachmachen schaffen:

 mkdir -p /tmp/bashtest/dir ; cd /tmp/bashtest ; touch a1.txt a2.txt alles.txt nix.txt a10.txt dir/b1.txt dir/b2.txt

Fängt mit a an, hört mit .txt auf:

 echo a*.txt
a10.txt a1.txt a2.txt alles.txt

Fängt mit zwei Zeichen an, hört mit .txt auf:

 echo ??.txt
a1.txt a2.txt

Da Verzeichnisse unter Unixoiden genauso Dateien sind, funktioniert auch:

Verzeichnis fängt mit d an, im Dateinamen kommt eine '1' oder '2' vor:

 echo d*/*[12]*
dir/b1.txt dir/b2.txt

Aufgabe: Gib einen Ausdruck an, mit dem diese Ausgabe erzeugt wird:

alles.txt nix.txt

Negation

Manchmal ist es nützlich, Ausnahmen angeben zu können. Das geht mit !(<muster>):

 echo !(??.*)

Alles, was nicht 2 Zeichen vor .txt hat:

a10.txt alles.txt dir nix.txt

Jedes Wort einzeln

Die Shell expandiert jedes Wort einzeln. Es werden also keine Dupletten ausgesiebt.

 echo !(*.txt) a* ??.txt
dir a10.txt a1.txt a2.txt alles.txt a1.txt a2.txt
  • Das erste Wort erzeugt dir
  • Das zweite Wort erzeugt a10.txt a1.txt a2.txt alles.txt
  • Das 3.te Wort erzeugt a1.txt a2.txt

Generelle Ausnahmen

Mit der Variablen $GLOBIGNORE kann Muster angeben, getrennt mit ':'. Jede Datei, die auf eines dieser Muster passt, erscheint nicht in der Expansion.

 GLOBIGNORE=*1.*:?i*
 echo *
a10.txt a2.txt alles.txt

Die geschweiften Klammern

Mit geschweiften Klammern können Wörter durch Kombination erzeugt werden. Dies ist eine rein textuelle Operation und hat nichts mit Dateinamen zu tun!

Die erste Form nutzt Aufzählungen:

 echo Fall{1,2,5}
Fall1 Fall2 Fall5

Die zweite Form operiert auf Intervallen, evt. mit Schrittweite:

 echo Fall_{1..4}
 echo Plan_{10..16..2}
# auch mehrfach (dann alle Kombinatinen):
 echo X{a..f}{0..2}
Fall_1 Fall_2 Fall_3 Fall_4
Plan_10 Plan_12 Plan_14 Plan_16
Xa0 Xa1 Xa2 Xb0 Xb1 Xb2 Xc0 Xc1 Xc2 Xd0 Xd1 Xd2 Xe0 Xe1 Xe2 Xf0 Xf1 Xf2

Tilde

  • Steht das Zeichen ~ am Anfang eines Wortes (nicht Strings), wird diese durch die Variable $HOME (das Heimatverzeichnis des angemeldeten Benutzers) ersetzt.
  • Steht am Anfang ein ~+, findet eine Ersetzung mit $PWD (aktuelles Verzeichnis) statt.
  • Beginnt das Wort mit ~-, wird $OLDPW eingesetzt (Vorgänger des aktuellen Verzeichnisses)
 cd /tmp ; cd /tmp/bashtest
 echo ~ XXX ~+/dir YYY ~-/bash*
/home/hm XXX /tmp/bashtest/dir YYY /tmp/bashtest

Die Tilde-Ersetzung wird zuerst durchgeführt, dann erfolgt noch eine Ergänzung der Dateienamen.

Anwendungsbeispiele

Alle Textdateien des aktuellen Verzeichnisses in den Ordner merken im Heimatverzeichnis legen:

 mkdir ~/merken ; ln -s ~+/*.txt ~/merken

Hinweis: Das Kommando ln benötigt in diesem Fall absolute Pfade.

Ein vorausgegangenes cd (change directory) rückgängig machen:

 cd ~-

Expansion verhindern (Quoting)

Was machen wir, wenn wir keine Dateinamen- oder Geschweiftklammer-Expansion wollen? Dazu gibt es 2 Methoden:

  • Vor die Sonderzeichen einen Backslash \ setzen: echo geht es noch\?
  • Aus dem Wort einen String machen:
    • echo "Geht es noch?"
    • echo 'Geht es noch?'

Anwendungsbeispiel

Das prominenteste Beispiel ist wohl die Verwendung von -exec im Kommando find. Mit dieser Option kann man mit allen gefundenen Dateien "was machen". An der Stelle, an der die Datei in der Ausgabe erscheinen soll, ist der Platzhalter {} einzusetzen, das Ende der Ausgabe ist mit ; zu markieren.

Wir wollen die Anzahl der Wörter in allen Textdateien im Unterverzeichnis dir zählen:

 find dir -name *.txt -exec wc -w {};
find: Der Pfad muß vor dem Suchkriterium stehen: a2.txt

Was ist passiert? Schauen wir der Shell zu, was sie macht:

 set -x
 find dir -name *.txt -exec wc -w {} ;
+ find dir -name a10.txt a2.txt alles.txt -exec wc -w '{}'
find: Der Pfad muß vor dem Suchkriterium stehen: a2.txt

Die Bash hat den Ausdruck *.txt expandiert (in a10.txt a2.txt alles.txt), damit stimmt die Syntax von find nicht mehr. Also müssen wir die Expansion verhindern durch Stringbildung "*.txt".

Aber wo ist der Strichpunkt am Ende geblieben? Die Bash hat den Strichpunkt als Trenner zum nächsten Kommando aufgefasst und entfernt. Daher müssen wir quoten, z.B. mit \;

 find dir -name "*.txt" -exec wc -w {} \;
 set +x
+ find dir -name '*.txt' -exec wc -w '{}' ';'
0 dir/b1.txt
0 dir/b2.txt

Jetzt leistet find das Gewünschte.

Hinweis: Oft findet man in Beispielen von find, dass auch {} gequotet wird. In der Bash ist das, wie oben gesehen, nicht notwendig: Die geschweiften Klammern werden nur ersetzt, wenn sich darin eine Liste befindet.

Strings und Variablenersetzung

Der Unterschied von und "": Variablen werden innerhalb "" ersetzt, in nicht:

 echo "Ich bin in $HOME zu Hause"
Ich bin in /home/hm zu Hause
 echo '$HOME ist das Heimatverzeichnis'
$HOME ist das Heimatverzeichnis

Nächstes Kapitel