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[Bearbeiten]

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[Bearbeiten]

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

Ergänzung des Dateinamens[Bearbeiten]

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[Bearbeiten]

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[Bearbeiten]

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[Bearbeiten]

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[Bearbeiten]

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[Bearbeiten]

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[Bearbeiten]

  • 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[Bearbeiten]

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)[Bearbeiten]

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[Bearbeiten]

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[Bearbeiten]

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[Bearbeiten]