Content from Einführung in die Shell


Zuletzt aktualisiert am 2025-10-23 | Diese Seite bearbeiten

Geschätzte Zeit: 5 Minuten

Übersicht

Fragen

  • Was ist eine Befehlsshell und warum sollte ich sie benutzen?

Ziele

  • Erklären Sie, wie die Shell mit der Tastatur, dem Bildschirm, dem Betriebssystem und den Programmen der Benutzer zusammenhängt.
  • Erklären Sie, wann und warum Befehlszeilenschnittstellen anstelle von grafischen Schnittstellen verwendet werden sollten.

Hintergrund

Menschen und Computer interagieren in der Regel auf viele verschiedene Arten, z. B. über Tastatur und Maus, Touchscreen-Schnittstellen oder mit Spracherkennungssystemen. Die am weitesten verbreitete Art der Interaktion mit Personalcomputern ist die grafische Benutzeroberfläche (GUI). Bei einer GUI werden Anweisungen per Mausklick und über menügesteuerte Interaktionen erteilt.

Während die visuelle Hilfe einer grafischen Benutzeroberfläche das Erlernen intuitiv macht, lässt sich diese Art der Übermittlung von Anweisungen an einen Computer nur sehr schlecht skalieren. Stellen Sie sich folgende Aufgabe vor: Für eine Literaturrecherche müssen Sie die dritte Zeile von eintausend Textdateien in eintausend verschiedenen Verzeichnissen kopieren und in eine einzige Datei einfügen. Mit einer grafischen Benutzeroberfläche würden Sie nicht nur stundenlang an Ihrem Schreibtisch herumklicken, sondern möglicherweise auch einen Fehler bei der Erledigung dieser sich wiederholenden Aufgabe begehen. An dieser Stelle kommt die Unix-Shell zum Einsatz. Die Unix-Shell ist sowohl eine Befehlszeilenschnittstelle (CLI) als auch eine Skriptsprache, mit der solche sich wiederholenden Aufgaben automatisch und schnell erledigt werden können. Mit den richtigen Befehlen kann die Shell Aufgaben mit oder ohne Änderungen so oft wiederholen, wie wir wollen. Mit der Shell kann die Aufgabe im Literaturbeispiel in Sekundenschnelle erledigt werden.

Die Shell

Die Shell ist ein Programm, in das Benutzer Befehle eingeben können. Mit der Shell ist es möglich, komplizierte Programme wie Klimamodellierungssoftware aufzurufen oder einfache Befehle, die ein leeres Verzeichnis mit nur einer Zeile Code erstellen. Die populärste Unix-Shell ist Bash (die Bourne Again SHell — so genannt, weil sie von einer Shell abgeleitet ist, die von Stephen Bourne geschrieben wurde). Bash ist die Standard-Shell in den meisten modernen Unix-Implementierungen und in den meisten Paketen, die Unix-ähnliche Werkzeuge für Windows bereitstellen. Beachten Sie, dass “Git Bash” eine Software ist, die es Windows-Benutzern ermöglicht, eine Bash-ähnliche Schnittstelle für die Interaktion mit Git zu verwenden.

Die Verwendung der Shell erfordert einige Mühe und Zeit, um sie zu erlernen. Während eine grafische Benutzeroberfläche (GUI) Ihnen Auswahlmöglichkeiten bietet, werden diese bei der Befehlszeilenschnittstelle (CLI) nicht automatisch angeboten, so dass Sie einige Befehle wie neue Vokabeln in einer Sprache, die Sie lernen, lernen müssen. Anders als bei einer gesprochenen Sprache reicht jedoch eine kleine Anzahl von “Wörtern” (d. h. Befehlen) aus, um weit zu kommen, und wir werden uns heute mit diesen wenigen wichtigen Wörtern beschäftigen.

Die Grammatik einer Shell ermöglicht es Ihnen, vorhandene Tools zu leistungsfähigen Pipelines zu kombinieren und große Datenmengen automatisch zu verarbeiten. Sequenzen von Befehlen können in ein Skript geschrieben werden, was die Reproduzierbarkeit von Arbeitsabläufen verbessert.

Darüber hinaus ist die Kommandozeile oft die einfachste Möglichkeit, mit entfernten Rechnern und Supercomputern zu interagieren. Die Vertrautheit mit der Shell ist nahezu unverzichtbar, um eine Vielzahl von spezialisierten Tools und Ressourcen, einschließlich Hochleistungscomputersystemen, zu nutzen. Da Cluster und Cloud-Computing-Systeme für die wissenschaftliche Datenverarbeitung immer beliebter werden, wird die Fähigkeit, mit der Shell zu interagieren, zu einer notwendigen Fähigkeit. Wir können auf den hier behandelten Kommandozeilenfähigkeiten aufbauen, um eine breite Palette wissenschaftlicher Fragen und rechnerischer Herausforderungen anzugehen.

Fangen wir an.

Wenn die Shell zum ersten Mal geöffnet wird, erscheint ein Prompt, das anzeigt, dass die Shell auf Eingaben wartet.

BASH

$

Die Shell verwendet normalerweise $ als Eingabeaufforderung, kann aber auch ein anderes Symbol verwenden. In den Beispielen dieser Lektion zeigen wir den Prompt als $. Am wichtigsten ist, dass Sie nicht den Prompt eingeben, wenn Sie Befehle eingeben. Geben Sie nur den Befehl ein, der auf die Eingabeaufforderung folgt. Diese Regel gilt sowohl in dieser Lektion als auch in Lektionen aus anderen Quellen. Beachten Sie auch, dass Sie, nachdem Sie einen Befehl eingegeben haben, die Eingabetaste drücken müssen, um ihn auszuführen.

Auf die Eingabeaufforderung folgt ein Textcursor, ein Zeichen, das die Position angibt, an der Ihre Eingaben erscheinen werden. Der Cursor ist normalerweise ein blinkender oder fester Block, kann aber auch ein Unterstrich oder eine Pipe sein. Sie haben ihn vielleicht schon einmal in einem Texteditor-Programm gesehen, zum Beispiel

Beachten Sie, dass Ihre Eingabeaufforderung ein wenig anders aussehen könnte. Insbesondere setzen die meisten gängigen Shell-Umgebungen standardmäßig Ihren Benutzernamen und den Rechnernamen vor das $. Eine solche Eingabeaufforderung könnte z.B. so aussehen:

BASH

nelle@localhost $

Die Eingabeaufforderung kann sogar noch mehr als das enthalten. Machen Sie sich keine Sorgen, wenn Ihr Prompt nicht nur aus einem kurzen $ besteht. Diese Lektion hängt nicht von diesen zusätzlichen Informationen ab, und sie sollten Ihnen auch nicht im Weg stehen. Der einzige wichtige Punkt, auf den Sie sich konzentrieren sollten, ist das Zeichen $ selbst, und wir werden später sehen, warum.

Versuchen wir es also mit unserem ersten Befehl, ls, was kurz für listing (also “auflisten”) ist. Dieser Befehl listet den Inhalt des aktuellen Verzeichnisses auf:

BASH

$ ls

AUSGABE

Desktop     Downloads   Movies      Pictures
Documents   Library     Music       Public
Wichtig

Befehl nicht gefunden

Wenn die Shell kein Programm finden kann, dessen Name dem von Ihnen eingegebenen Befehl entspricht, gibt sie eine Fehlermeldung aus, z. B:

BASH

$ ks

AUSGABE

ks: command not found

Dies kann passieren, wenn der Befehl falsch eingegeben wurde oder wenn das entsprechende Programm nicht installiert ist.

Nelle’s Pipeline: Ein typisches Problem


Nelle Nemo, eine Meeresbiologin, ist gerade von einer sechsmonatigen Untersuchung des Nordpazifischen Wirbels zurückgekehrt, wo sie Proben von gallertartigen Meereslebewesen im Great Pacific Garbage Patch genommen hat. Sie hat 1520 Proben, die sie durch ein Testgerät laufen ließ, um die relative Häufigkeit von 300 Proteinen zu messen. Sie muss diese 1520 Dateien durch ein imaginäres Programm namens goostats.sh laufen lassen. Zusätzlich zu dieser riesigen Aufgabe muss sie die Ergebnisse bis Ende des Monats aufschreiben, damit ihr Artikel in einer Sonderausgabe der Aquatic Goo Letters erscheinen kann.

Wenn Nelle sich dafür entscheidet, goostats.sh von Hand über eine grafische Benutzeroberfläche auszuführen, muss sie eine Datei 1520 Mal auswählen und öffnen. Wenn goostats.sh 30 Sekunden braucht, um jede Datei auszuführen, wird der gesamte Prozess mehr als 12 Stunden von Nelles Aufmerksamkeit in Anspruch nehmen. Mit der Shell kann Nelle stattdessen ihrem Computer diese banale Aufgabe übertragen, während sie sich auf das Schreiben ihrer Arbeit konzentriert.

In den nächsten Lektionen wird untersucht, wie Nelle dies erreichen kann. Genauer gesagt, wird in den Lektionen erklärt, wie sie eine Befehlsshell verwenden kann, um das Programm goostats.sh auszuführen, wobei Schleifen verwendet werden, um die sich wiederholenden Schritte der Eingabe von Dateinamen zu automatisieren, so dass ihr Computer arbeiten kann, während sie ihre Arbeit schreibt.

Wenn sie einmal eine Verarbeitungspipeline zusammengestellt hat, kann sie diese bei jeder weiteren Datenerfassung wieder verwenden.

Um ihre Aufgabe zu erfüllen, muss Nelle wissen, wie man:

  • zu einer Datei/Verzeichnis navigieren
  • Erstellen einer Datei/eines Verzeichnisses
  • Prüfen der Länge einer Datei
  • Befehle aneinanderreihen
  • Abrufen einer Reihe von Dateien
  • Iteration über Dateien
  • ein Shell-Skript ausführen, das ihre Pipeline enthält
Hauptpunkte
  • Eine Shell ist ein Programm, dessen Hauptzweck darin besteht, Befehle zu lesen und andere Programme auszuführen.
  • Diese Lektion verwendet Bash, die Standard-Shell in vielen Unix-Implementierungen.
  • Programme können in der Bash durch Eingabe von Befehlen an der Eingabeaufforderung ausgeführt werden.
  • Die Hauptvorteile der Shell sind ihr hohes Verhältnis von ausgeführten Aktionen zu Tasteneingaben, ihre Unterstützung bei der Automatisierung wiederkehrender Aufgaben und ihre Fähigkeit, auf vernetzte Rechner zuzugreifen.
  • Eine große Herausforderung bei der Verwendung der Shell kann darin bestehen, zu wissen, welche Befehle ausgeführt werden müssen und wie sie auszuführen sind.

Content from Dateien und Verzeichnisse durchsuchen


Zuletzt aktualisiert am 2025-10-23 | Diese Seite bearbeiten

Geschätzte Zeit: 40 Minuten

Übersicht

Fragen

  • Wie kann ich mich auf meinem Computer bewegen?
  • Wie kann ich sehen, welche Dateien und Verzeichnisse ich habe?
  • Wie kann ich den Ort einer Datei oder eines Verzeichnisses auf meinem Computer angeben?

Ziele

  • Erkläre die Gemeinsamkeiten und Unterschiede zwischen einer Datei und einem Verzeichnis.
  • Übersetzt einen absoluten Pfad in einen relativen Pfad und umgekehrt.
  • Konstruieren Sie absolute und relative Pfade, die bestimmte Dateien und Verzeichnisse identifizieren.
  • Verwenden Sie Optionen und Argumente, um das Verhalten eines Shell-Befehls zu ändern.
  • Demonstrieren Sie die Verwendung der Tabulatorvervollständigung und erklären Sie ihre Vorteile.

Die Einführung und Navigation im Dateisystem in der Shell (behandelt im Abschnitt Navigieren in Dateien und Verzeichnissen) kann verwirrend sein. Sie können sowohl das Terminal als auch den GUI-Dateiexplorer nebeneinander geöffnet haben, damit die Lernenden den Inhalt und die Dateistruktur sehen können, während sie das Terminal zum Navigieren im System verwenden.

Der Teil des Betriebssystems, der für die Verwaltung von Dateien und Verzeichnissen zuständig ist, wird Dateisystem genannt. Es organisiert unsere Daten in Dateien, die Informationen enthalten, und Verzeichnissen (auch ‘Ordner’ genannt), die Dateien oder andere Verzeichnisse enthalten.

Mehrere Befehle werden häufig zum Erstellen, Überprüfen, Umbenennen und Löschen von Dateien und Verzeichnissen verwendet. Um sie zu erforschen, gehen wir zu unserem geöffneten Shell-Fenster.

Zuerst wollen wir herausfinden, wo wir uns befinden, indem wir einen Befehl namens pwd ausführen (das steht für ‘print working directory’). Verzeichnisse sind wie Orte - zu jeder Zeit, während wir die Shell benutzen, sind wir an genau einem Ort, der unser aktuelles Arbeitsverzeichnis genannt wird. Die meisten Befehle lesen und schreiben Dateien im aktuellen Arbeitsverzeichnis, d.h. ‘hier’, daher ist es wichtig zu wissen, wo man sich befindet, bevor man einen Befehl ausführt.pwd zeigt Ihnen, wo Sie sich befinden:

BASH

$ pwd

AUSGABE

/Users/nelle

Hier ist die Antwort des Computers /Users/nelle, was Nelles Home-Verzeichnis ist:

Wichtig

Variation des Homeverzeichnisses

Der Pfad zum Homeverzeichnis sieht auf verschiedenen Betriebssystemen unterschiedlich aus. Unter Linux kann er wie /home/nelle aussehen, und unter Windows wird er ähnlich wie C:\Documents and Settings\nelle oder C:\Users\nelle sein. (Beachten Sie, dass es bei verschiedenen Windows-Versionen etwas anders aussehen kann.) In den zukünftigen Beispielen haben wir die Mac-Ausgabe als Standard verwendet - die Linux- und Windows-Ausgabe kann leicht abweichen, sollte aber im Allgemeinen ähnlich sein.

Wir nehmen auch an, dass Ihr pwd-Befehl das Homeverzeichnis Ihres Benutzers zurückgibt. Wenn pwd etwas anderes zurückgibt, müssen Sie möglicherweise mit cd dorthin navigieren, oder einige Befehle in dieser Lektion werden nicht wie geschrieben funktionieren. Siehe Andere Verzeichnisse erforschen für weitere Details über den cd Befehl.

Um zu verstehen, was ein “Homeverzeichnis” ist, schauen wir uns an, wie das Dateisystem als Ganzes organisiert ist. Für dieses Beispiel werden wir das Dateisystem auf dem Computer unserer Wissenschaftlerin Nelle darstellen. Nach dieser Veranschaulichung werden Sie Befehle lernen, um Ihr eigenes Dateisystem zu erforschen, das ähnlich aufgebaut sein wird, aber nicht exakt identisch ist.

Auf Nelle’s Computer sieht das Dateisystem wie folgt aus:

Das Dateisystem besteht aus einem Stammverzeichnis, das Unterverzeichnisse mit den Namen bin, data, users und tmp enthält

Das Dateisystem sieht aus wie ein auf dem Kopf stehender Baum. Das oberste Verzeichnis ist das Rootverzeichnis, das alles andere enthält. Wir verweisen auf es mit einem Schrägstrich, /, allein; dieses Zeichen ist der führende Schrägstrich in /Users/nelle.

Innerhalb dieses Verzeichnisses gibt es mehrere andere Verzeichnisse: bin (in dem einige eingebaute Programme gespeichert werden), data (für verschiedene Datendateien), Users (in dem sich die persönlichen Verzeichnisse der Benutzer befinden), tmp (für temporäre Dateien, die nicht langfristig gespeichert werden müssen), und so weiter.

Wir wissen, dass unser aktuelles Arbeitsverzeichnis /Users/nelle innerhalb von /Users gespeichert ist, weil /Users der erste Teil seines Namens ist. Ebenso wissen wir, dass /Users innerhalb des Stammverzeichnisses / gespeichert ist, weil sein Name mit / beginnt.

Wichtig

Schrägstriche

Beachten Sie, dass es zwei Bedeutungen für das Zeichen / gibt. Wenn es am Anfang eines Datei- oder Verzeichnisnamens erscheint, bezieht es sich auf das Stammverzeichnis. Wenn es innerhalb eines Pfades erscheint, ist es nur ein Trennzeichen.

Unterhalb von /Users finden wir ein Verzeichnis für jeden Benutzer mit einem Konto auf Nelles Rechner, ihre Kollegen imhotep und larry.

{alt=“Wie andere Verzeichnisse sind Home-Verzeichnisse Unterverzeichnisse unterhalb von”/Users” wie “/Users/imhotep”, “/Users/larry” oder”/Users/nelle”“}

Die Dateien des Benutzers imhotep werden in /Users/imhotep gespeichert, die des Benutzers larry in /Users/larry und die von Nelle in /Users/nelle. Nelle ist der Benutzer in unseren Beispielen hier; daher bekommen wir /Users/nelle als unser Homeverzeichnis. Wenn Sie eine neue Eingabeaufforderung öffnen, befinden Sie sich normalerweise zunächst in Ihrem Homeverzeichnis.

Jetzt wollen wir den Befehl lernen, mit dem wir den Inhalt unseres eigenen Dateisystems sehen können. Wir können sehen, was sich in unserem Homeverzeichnis befindet, indem wir ls ausführen:

BASH

$ ls

AUSGABE

Applications Documents    Library      Music        Public
Desktop      Downloads    Movies       Pictures

(Auch hier können die Ergebnisse leicht abweichen, je nachdem, wie Sie Ihr Dateisystem angepasst haben und unter welchem Betriebssystem Sie arbeiten)

ls gibt die Namen der Dateien und Verzeichnisse im aktuellen Verzeichnis aus. Wir können die Ausgabe verständlicher machen, indem wir die Option -F verwenden, die ls anweist, die Ausgabe zu klassifizieren, indem es den Datei- und Verzeichnisnamen eine Markierung hinzufügt, um anzuzeigen, worum es sich handelt:

  • ein nachgestelltes / zeigt an, dass dies ein Verzeichnis ist
  • @ zeigt einen Link an
  • * zeigt eine ausführbare Datei an

Abhängig von den Standardeinstellungen Ihrer Shell, kann die Shell auch Farben verwenden, um anzuzeigen, ob jeder Eintrag eine Datei oder ein Verzeichnis ist.

BASH

$ ls -F

AUSGABE

Applications/ Documents/    Library/      Music/        Public/
Desktop/      Downloads/    Movies/       Pictures/

Hier können wir sehen, dass das Homeverzeichnis nur Unterverzeichnisse enthält. Alle Namen in der Ausgabe, die kein Klassifizierungssymbol haben, sind Dateien im aktuellen Arbeitsverzeichnis.

Wichtig

Löschen des Terminals

Wenn Ihr Bildschirm zu unübersichtlich wird, können Sie Ihr Terminal mit dem Befehl clear leeren. Du kannst immer noch auf vorherige Befehle zugreifen, indem du und verwendest, um dich Zeile für Zeile zu bewegen, oder indem du in deinem Terminal scrollst.

Hilfe erhalten

ls hat eine Menge anderer Optionen. Es gibt zwei übliche Wege, um herauszufinden, wie man einen Befehl benutzt und welche Optionen er akzeptiert — Abhängig von Ihrer Umgebung könnten Sie feststellen, dass nur einer dieser Wege funktioniert:

  1. Wir können die Option --help an jeden Befehl übergeben (verfügbar unter Linux und Git Bash), zum Beispiel:

BASH

$ ls --help
  1. Wir können sein Handbuch mit man lesen (verfügbar unter Linux und macOS):

BASH

$ man ls

Wir werden beide Möglichkeiten im Folgenden beschreiben.

Wichtig

Hilfe für eingebaute Befehle

Einige Befehle sind in die Bash-Shell eingebaut, anstatt als separate Programme im Dateisystem zu existieren. Ein Beispiel ist der Befehl cd (Verzeichnis wechseln). Wenn Sie eine Meldung wie No manual entry for cd erhalten, versuchen Sie stattdessen help cd. Mit dem Befehl help erhalten Sie Nutzungsinformationen für Bash built-ins.

Die --help Option

Die meisten Bash-Befehle und -Programme, die für die Ausführung innerhalb der Bash geschrieben wurden, unterstützen eine Option --help, die weitere Informationen zur Verwendung des Befehls oder Programms anzeigt.

BASH

$ ls --help

AUSGABE

Usage: ls [OPTION]... [FILE]...
List information about the FILEs (the current directory by default).
Sort entries alphabetically if neither -cftuvSUX nor --sort is specified.

Mandatory arguments to long options are mandatory for short options, too.
  -a, --all                  do not ignore entries starting with .
  -A, --almost-all           do not list implied . and ..
      --author               with -l, print the author of each file
  -b, --escape               print C-style escapes for nongraphic characters
      --block-size=SIZE      scale sizes by SIZE before printing them; e.g.,
                               '--block-size=M' prints sizes in units of
                               1,048,576 bytes; see SIZE format below
  -B, --ignore-backups       do not list implied entries ending with ~
  -c                         with -lt: sort by, and show, ctime (time of last
                               modification of file status information);
                               with -l: show ctime and sort by name;
                               otherwise: sort by ctime, newest first
  -C                         list entries by columns
      --color[=WHEN]         colorize the output; WHEN can be 'always' (default
                               if omitted), 'auto', or 'never'; more info below
  -d, --directory            list directories themselves, not their contents
  -D, --dired                generate output designed for Emacs' dired mode
  -f                         do not sort, enable -aU, disable -ls --color
  -F, --classify             append indicator (one of */=>@|) to entries
...        ...        ...
Wichtig

Wann man kurze oder lange Optionen verwenden sollte

Wenn Optionen sowohl als kurze als auch als lange Optionen existieren:

  • Verwenden Sie die Option short, wenn Sie Befehle direkt in die Shell eingeben, um die Anzahl der Tastenanschläge zu minimieren und Ihre Aufgabe schneller zu erledigen.
  • Verwenden Sie die Option long in Skripten, um Klarheit zu schaffen. Sie wird viele Male gelesen und nur einmal eingegeben.
Wichtig

Nicht unterstützte Kommandozeilenoptionen

Wenn Sie versuchen, eine Option zu verwenden, die nicht unterstützt wird, geben ls und andere Befehle normalerweise eine Fehlermeldung ähnlich der folgenden aus:

BASH

$ ls -j

FEHLER

ls: invalid option -- 'j'
Try 'ls --help' for more information.

Der man Befehl

Die andere Möglichkeit, etwas über ls zu erfahren, ist die Eingabe von

BASH

$ man ls

Dieser Befehl verwandelt Ihr Terminal in eine Seite mit einer Beschreibung des Befehls ls und seiner Optionen.

Um durch die man-Seiten zu navigieren, können Sie und benutzen, um sich zeilenweise zu bewegen, oder b und Leertaste ausprobieren, um eine ganze Seite vor- und zurückzuspringen. Um nach einem Zeichen oder Wort in den man-Seiten zu suchen, verwenden Sie /, gefolgt von dem Zeichen oder Wort, das Sie suchen. Manchmal führt eine Suche zu mehreren Treffern. In diesem Fall können Sie zwischen den Treffern mit N (vorwärts) und Shift+N (rückwärts) wechseln.

Um die man Seiten zu beenden, drücken Sie q.

Wichtig

Manual pages on the web

Natürlich gibt es noch eine dritte Möglichkeit, auf die Hilfe für Befehle zuzugreifen: die Suche im Internet über Ihren Webbrowser. Wenn Sie die Internetsuche verwenden, hilft es, den Ausdruck unix man page in Ihre Suchanfrage aufzunehmen, um relevante Ergebnisse zu finden.

GNU bietet Links zu seinen Handbüchern, einschließlich der core GNU utilities, die viele in dieser Lektion vorgestellte Befehle abdeckt.

Aufgabe

Weitere ls-Optionen erforschen

Sie können auch zwei Optionen gleichzeitig verwenden. Was bewirkt der Befehl ls, wenn er mit der Option -l verwendet wird? Was ist, wenn Sie sowohl die Option -l als auch die Option -h verwenden?

Ein Teil der Ausgabe bezieht sich auf Eigenschaften, die wir in dieser Lektion nicht behandeln (z.B. Dateiberechtigungen und Besitzverhältnisse), aber der Rest sollte trotzdem nützlich sein.

Die Option -l bewirkt, dass ls ein llanges Listenformat verwendet, das nicht nur die Datei-/Verzeichnisnamen, sondern auch zusätzliche Informationen wie die Dateigröße und den Zeitpunkt der letzten Änderung anzeigt. Wenn Sie sowohl die Option -h als auch die Option -l verwenden, macht dies die Dateigröße ‘hmenschlich lesbar’, d.h. es wird etwas wie 5.3K statt 5369 angezeigt.

Aufgabe

Auflistung in umgekehrter chronologischer Reihenfolge

Standardmäßig listet ls den Inhalt eines Verzeichnisses in alphabetischer Reihenfolge nach Namen auf. Der Befehl ls -t listet die Einträge nicht alphabetisch, sondern nach dem Zeitpunkt der letzten Änderung auf. Der Befehl ls -r listet den Inhalt eines Verzeichnisses in umgekehrter Reihenfolge auf. Welche Datei wird zuletzt angezeigt, wenn Sie die Optionen -t und -r kombinieren? Hinweis: Möglicherweise müssen Sie die Option -l verwenden, um das Datum der letzten Änderung zu sehen.

Die zuletzt geänderte Datei wird zuletzt aufgelistet, wenn -rt verwendet wird. Dies kann sehr nützlich sein, um die letzten Bearbeitungen zu finden oder um zu überprüfen, ob eine neue Ausgabedatei geschrieben wurde.

Andere Verzeichnisse erforschen

Wir können ls nicht nur für das aktuelle Arbeitsverzeichnis verwenden, sondern auch, um den Inhalt eines anderen Verzeichnisses aufzulisten. Schauen wir uns unser Desktop-Verzeichnis an, indem wir ls -F Desktop ausführen, d.h. den Befehl ls mit der Option -F und dem [Argument][Argumente] Desktop. Das Argument Desktop sagt ls, dass wir eine Auflistung von etwas anderem als unserem aktuellen Arbeitsverzeichnis wollen:

BASH

$ ls -F Desktop

AUSGABE

shell-lesson-data/

Beachten Sie, dass dieser Befehl einen Fehler zurückgibt, wenn ein Verzeichnis namens Desktop in Ihrem aktuellen Arbeitsverzeichnis nicht existiert. Normalerweise existiert ein Desktop-Verzeichnis in Ihrem Home-Verzeichnis, von dem wir annehmen, dass es das aktuelle Arbeitsverzeichnis Ihrer Bash-Shell ist.

Ihre Ausgabe sollte eine Liste aller Dateien und Unterverzeichnisse in Ihrem Desktop-Verzeichnis sein, einschließlich des shell-lesson-data-Verzeichnisses, das Sie im [Setup für diese Lektion] (../learners/setup.md) heruntergeladen haben. (Auf den meisten Systemen wird der Inhalt des Verzeichnisses Desktop in der Shell als Symbole in einer grafischen Benutzeroberfläche hinter allen offenen Fenstern angezeigt. Prüfen Sie, ob dies bei Ihnen der Fall ist.)

Die hierarchische Organisation von Dingen hilft uns, den Überblick über unsere Arbeit zu behalten. Es ist zwar möglich, Hunderte von Dateien in unserem Home-Verzeichnis abzulegen, so wie es möglich ist, Hunderte von gedruckten Papieren auf unserem Schreibtisch zu stapeln, aber es ist viel einfacher, Dinge zu finden, wenn sie in sinnvoll benannten Unterverzeichnissen organisiert sind.

Jetzt, da wir wissen, dass sich das Verzeichnis shell-lesson-data in unserem Desktop-Verzeichnis befindet, können wir zwei Dinge tun.

Zunächst können wir mit der gleichen Strategie wie zuvor seinen Inhalt betrachten, indem wir einen Verzeichnisnamen an ls übergeben:

BASH

$ ls -F Desktop/shell-lesson-data

AUSGABE

exercise-data/  north-pacific-gyre/

Zweitens können wir unseren Standort in ein anderes Verzeichnis ändern, so dass wir uns nicht mehr in unserem Homeverzeichnis befinden.

Der Befehl zum Wechseln des Verzeichnisses lautet cd, gefolgt von einem Verzeichnisnamen, um das Arbeitsverzeichnis zu wechseln.cd steht für “Verzeichnis wechseln”, was ein wenig irreführend ist. Der Befehl wechselt nicht das Verzeichnis, sondern das aktuelle Arbeitsverzeichnis der Shell. Mit anderen Worten, er ändert die Einstellungen der Shell, in welchem Verzeichnis wir uns befinden. Der Befehl cd ist vergleichbar mit einem Doppelklick auf einen Ordner in einer grafischen Oberfläche, um in diesen Ordner zu gelangen.

Nehmen wir an, wir wollen in das Verzeichnis exercise-data wechseln, das wir oben gesehen haben. Wir können die folgende Reihe von Befehlen verwenden, um dorthin zu gelangen:

BASH

$ cd Desktop
$ cd shell-lesson-data
$ cd exercise-data

Diese Befehle verschieben uns von unserem Home-Verzeichnis in unser Desktop-Verzeichnis, dann in das Verzeichnis shell-lesson-data und dann in das Verzeichnis exercise-data. Sie werden feststellen, dass cd nichts ausgibt. Das ist normal. Viele Shell-Befehle geben bei erfolgreicher Ausführung nichts auf dem Bildschirm aus. Wenn wir aber pwd danach ausführen, können wir sehen, dass wir jetzt in /Users/nelle/Desktop/shell-lesson-data/exercise-data sind.

Wenn wir jetzt ls -F ohne Argumente ausführen, listet es den Inhalt von /Users/nelle/Desktop/shell-lesson-data/exercise-data auf, weil wir uns jetzt dort befinden:

BASH

$ pwd

AUSGABE

/Users/nelle/Desktop/shell-lesson-data/exercise-data

BASH

$ ls -F

AUSGABE

alkanes/  animal-counts/  creatures/  numbers.txt  writing/

Wir wissen jetzt, wie wir im Verzeichnisbaum nach unten gehen (d.h. wie wir in ein Unterverzeichnis gehen), aber wie gehen wir nach oben (d.h. wie verlassen wir ein Verzeichnis und gehen in sein übergeordnetes Verzeichnis)? Wir könnten das Folgende versuchen:

BASH

$ cd shell-lesson-data

FEHLER

-bash: cd: shell-lesson-data: No such file or directory

Aber wir bekommen einen Fehler! Woran liegt das?

Mit unseren bisherigen Methoden kann cd nur Unterverzeichnisse innerhalb deines aktuellen Verzeichnisses sehen. Es gibt verschiedene Möglichkeiten, Verzeichnisse oberhalb Ihres aktuellen Standorts zu sehen; wir beginnen mit der einfachsten.

Es gibt eine Abkürzung in der Shell, um eine Verzeichnisebene höher zu gehen. Es funktioniert wie folgt:

BASH

$ cd ..

.. ist ein spezieller Verzeichnisname, der “das Verzeichnis, das dieses enthält” bedeutet, oder einfacher ausgedrückt, das Elternteil des aktuellen Verzeichnisses. Sicherlich, wenn wir pwd nach cd .. ausführen, sind wir wieder in /Users/nelle/Desktop/shell-lesson-data:

BASH

$ pwd

AUSGABE

/Users/nelle/Desktop/shell-lesson-data

Das spezielle Verzeichnis .. wird normalerweise nicht angezeigt, wenn wir ls ausführen. Wenn wir es anzeigen wollen, können wir die Option -a zu ls -F hinzufügen:

BASH

$ ls -F -a

AUSGABE

./  ../  exercise-data/  north-pacific-gyre/

-a steht für ‘show all’ (einschließlich versteckter Dateien); es zwingt ls dazu, uns Datei- und Verzeichnisnamen zu zeigen, die mit . beginnen, wie z.B. .. (was sich, wenn wir in /Users/nelle sind, auf das Verzeichnis /Users bezieht). Wie Sie sehen können, zeigt es auch ein anderes spezielles Verzeichnis an, das einfach . heißt, was “das aktuelle Arbeitsverzeichnis” bedeutet. Es mag überflüssig erscheinen, einen Namen dafür zu haben, aber wir werden bald einige Anwendungen dafür sehen.

Beachten Sie, dass in den meisten Kommandozeilen-Tools mehrere Optionen mit einem einzigen - und ohne Leerzeichen zwischen den Optionen kombiniert werden können; ls -F -a ist äquivalent zu ls -Fa.

Wichtig

Andere versteckte Dateien

Zusätzlich zu den versteckten Verzeichnissen .. und . sehen Sie möglicherweise auch eine Datei namens .bash_profile. Diese Datei enthält normalerweise Einstellungen für die Shell-Konfiguration. Sie können auch andere Dateien und Verzeichnisse sehen, die mit . beginnen. Dies sind normalerweise Dateien und Verzeichnisse, die zur Konfiguration verschiedener Programme auf Ihrem Computer verwendet werden. Das Präfix . wird verwendet, um zu verhindern, dass diese Konfigurationsdateien das Terminal überladen, wenn ein Standardbefehl ls verwendet wird.

Diese drei Befehle sind die grundlegenden Befehle zum Navigieren im Dateisystem Ihres Computers: pwd, ls, und cd. Lassen Sie uns einige Variationen dieser Befehle untersuchen. Was passiert, wenn Sie cd allein eingeben, ohne ein Verzeichnis anzugeben?

BASH

$ cd

Wie kann man überprüfen, was passiert ist? pwd gibt uns die Antwort!

BASH

$ pwd

AUSGABE

/Users/nelle

Es hat sich herausgestellt, dass cd ohne ein Argument Sie zu Ihrem Homeverzeichnis zurückbringt, was großartig ist, wenn Sie sich in Ihrem eigenen Dateisystem verirrt haben.

Versuchen wir, zu dem Verzeichnis exercise-data von vorhin zurückzukehren. Letztes Mal haben wir drei Befehle benutzt, aber wir können die Liste der Verzeichnisse, die wir nach exercise-data verschieben wollen, in einem Schritt zusammenstellen:

BASH

$ cd Desktop/shell-lesson-data/exercise-data

Überprüfen Sie, ob wir an den richtigen Ort umgezogen sind, indem Sie pwd und ls -F ausführen.

Wenn wir vom Datenverzeichnis eine Ebene nach oben gehen wollen, können wir cd .. verwenden. Es gibt aber auch eine andere Möglichkeit, in ein beliebiges Verzeichnis zu wechseln, unabhängig davon, wo Sie sich gerade befinden.

Bislang haben wir bei der Angabe von Verzeichnisnamen oder sogar eines Verzeichnispfades (wie oben) relative Pfade verwendet. Wenn Sie einen relativen Pfad mit einem Befehl wie ls oder cd verwenden, wird versucht, diesen Ort von der Stelle aus zu finden, an der wir uns befinden, und nicht von der Root des Dateisystems.

Es ist jedoch möglich, den absoluten Pfad zu einem Verzeichnis anzugeben, indem man den gesamten Pfad vom Stammverzeichnis aus einbezieht, was durch einen führenden Schrägstrich angezeigt wird. Der führende Schrägstrich sagt dem Computer, dass er den Pfad vom Stammverzeichnis des Dateisystems aus verfolgen soll, so dass er sich immer auf genau ein Verzeichnis bezieht, egal wo wir uns befinden, wenn wir den Befehl ausführen.

So können wir von überall im Dateisystem in unser shell-lesson-data-Verzeichnis wechseln (auch innerhalb von exercise-data). Um den absoluten Pfad zu finden, den wir suchen, können wir pwd verwenden und dann das Stück extrahieren, das wir nach shell-lesson-data verschieben wollen.

BASH

$ pwd

AUSGABE

/Users/nelle/Desktop/shell-lesson-data/exercise-data

BASH

$ cd /Users/nelle/Desktop/shell-lesson-data

Führen Sie pwd und ls -F aus, um sicherzustellen, dass wir uns in dem Verzeichnis befinden, das wir erwarten.

Wichtig

Zwei weitere Abkürzungen

Die Shell interpretiert eine Tilde (~) am Anfang eines Pfades als “das Homeverzeichnis des aktuellen Benutzers”. Wenn zum Beispiel das Homeverzeichnis von Nelle /Users/nelle ist, dann ist ~/data äquivalent zu /Users/nelle/data. Das funktioniert nur, wenn es das erste Zeichen im Pfad ist; here/there/~/elsewhere ist nicht here/there/Users/nelle/elsewhere.

Eine weitere Abkürzung ist das Zeichen - (Bindestrich).cd übersetzt- in das vorherige Verzeichnis, in dem ich mich befand, was schneller ist, als sich an den vollständigen Pfad zu erinnern und ihn dann einzugeben. Dies ist ein sehr effizienter Weg, um zwischen zwei Verzeichnissen hin und her zu wechseln – d.h. wenn Sie cd - zweimal ausführen, landen Sie wieder im Ausgangsverzeichnis.

Der Unterschied zwischen cd .. und cd - ist, dass ersteres Sie nach oben bringt, während letzteres Sie zurück bringt.


Versuchen Sie es! Navigieren Sie zuerst zu ~/Desktop/shell-lesson-data (Sie sollten bereits dort sein).

BASH

$ cd ~/Desktop/shell-lesson-data

Dann cd in das exercise-data/creatures Verzeichnis

BASH

$ cd exercise-data/creatures

Wenn Sie nun folgendes ausführen

BASH

$ cd -

Sie werden sehen, dass Sie sich wieder in ~/Desktop/shell-lesson-data befinden. Führen Sie cd - erneut aus und Sie befinden sich wieder in ~/Desktop/shell-lesson-data/exercise-data/creatures

Aufgabe

Absolute vs. Relative Pfade

Welchen der folgenden Befehle könnte Nelle ausgehend von /Users/nelle/data verwenden, um zu ihrem Homeverzeichnis zu navigieren, das /Users/nelle ist?

  1. cd .
  2. cd /
  3. cd /home/nelle
  4. cd ../..
  5. cd ~
  6. cd home
  7. cd ~/data/..
  8. cd
  9. cd ..
  1. Nein: . steht für das aktuelle Verzeichnis.
  2. Nein: / steht für das Stammverzeichnis.
  3. Nein: Nelle’s Homeverzeichnis ist /Users/nelle.
  4. Nein: Dieser Befehl geht zwei Ebenen nach oben, d.h. er endet mit /Users.
  5. Ja: ~ steht für das Homeverzeichnis des Benutzers, in diesem Fall /Users/nelle.
  6. Nein: Dieser Befehl würde in ein Verzeichnis home im aktuellen Verzeichnis navigieren, wenn es existiert.
  7. Ja: unnötig kompliziert, aber korrekt.
  8. Ja: Abkürzung, um zum Homeverzeichnis des Benutzers zurückzukehren.
  9. Ja: geht eine Ebene höher.
Aufgabe

Relative Pfadauflösung

Wenn pwd /Users/thing anzeigt, was zeigt dann ls -F ../backup im untenstehenden Dateisystemdiagramm an?

  1. ../backup: No such file or directory
  2. 2012-12-01 2013-01-08 2013-01-27
  3. 2012-12-01/ 2013-01-08/ 2013-01-27/
  4. original/ pnas_final/ pnas_sub/

{alt=“Ein Verzeichnisbaum unterhalb des Users-Verzeichnisses, in dem”/Users” die Verzeichnisse “backup” und “thing” enthält; “/Users/backup” enthält “original”, “pnas_final” und “pnas_sub”; “/Users/thing” enthält “backup”; und “/Users/thing/backup” enthält “2012-12-01”, “2013-01-08” und “2013-01-27”“}

  1. Nein: Es gibt ein Verzeichnis backup in /Users.
  2. Nein: das ist der Inhalt von Users/thing/backup, aber mit .. haben wir nach einer Ebene weiter oben gefragt.
  3. Nein: siehe vorherige Erklärung.
  4. Ja: ../backup/ verweist auf /Users/backup/.
Aufgabe

Einsichten in ls

Wenn pwd /Users/backup anzeigt und -r ls anweist, die Dinge in umgekehrter Reihenfolge anzuzeigen, welche(r) Befehl(e) führt/führen dann zu folgender Ausgabe?

AUSGABE

pnas_sub/ pnas_final/ original/

{alt=“Ein Verzeichnisbaum unterhalb des Users-Verzeichnisses, in dem”/Users” die Verzeichnisse “backup” und “thing” enthält; “/Users/backup” enthält “original”, “pnas_final” und “pnas_sub”; “/Users/thing” enthält “backup”; und “/Users/thing/backup” enthält “2012-12-01”, “2013-01-08” und “2013-01-27”“}

  1. ls pwd
  2. ls -r -F
  3. ls -r -F /Users/backup
  1. Nein: pwd ist nicht der Name eines Verzeichnisses.
  2. Ja: ls ohne Verzeichnisargument listet Dateien und Verzeichnisse im aktuellen Verzeichnis auf.
  3. Ja: verwendet explizit den absoluten Pfad.

Allgemeine Syntax eines Shell-Befehls


Wir haben nun Befehle, Optionen und Argumente kennengelernt, aber es ist vielleicht sinnvoll, einige Begriffe zu formalisieren.

Betrachten Sie den folgenden Befehl als ein allgemeines Beispiel für einen Befehl, den wir in seine Bestandteile zerlegen werden:

BASH

$ ls -F /
Allgemeine Syntax eines Shell-Befehls

ls ist der Befehl, mit einer Option -F und einem Argument /. Wir haben bereits Optionen kennengelernt, die entweder mit einem einzelnen Bindestrich beginnen (-), bekannt als kurze Optionen, oder mit zwei Bindestrichen (--), bekannt als lange Optionen. [Optionen] ändern das Verhalten eines Befehls und Argumente] sagen dem Befehl, womit er arbeiten soll (z.B. Dateien und Verzeichnisse). Manchmal werden Optionen und Argumente auch als Parameter bezeichnet. Ein Befehl kann mit mehr als einer Option und mehr als einem Argument aufgerufen werden, aber ein Befehl benötigt nicht immer ein Argument oder eine Option.

Manchmal sieht man, dass Optionen als Schalter oder Flags bezeichnet werden, besonders bei Optionen, die kein Argument benötigen. In dieser Lektion werden wir bei dem Begriff Option bleiben.

Jeder Teil ist durch Leerzeichen getrennt. Wenn Sie das Leerzeichen zwischen ls und -F weglassen, wird die Shell nach einem Befehl namens ls-F suchen, den es nicht gibt. Auch die Großschreibung kann wichtig sein. Zum Beispiel zeigt ls -s die Größe von Dateien und Verzeichnissen neben den Namen an, während ls -S die Dateien und Verzeichnisse nach Größe sortiert, wie unten gezeigt:

BASH

$ cd ~/Desktop/shell-lesson-data
$ ls -s exercise-data

AUSGABE

total 28
 4 animal-counts   4 creatures  12 numbers.txt   4 alkanes   4 writing

Beachten Sie, dass die von ls -s zurückgegebenen Größen in Blöcken angegeben sind. Da diese für verschiedene Betriebssysteme unterschiedlich definiert sind, erhalten Sie möglicherweise nicht die gleichen Zahlen wie im Beispiel.

BASH

$ ls -S exercise-data

AUSGABE

animal-counts  creatures  alkanes  writing  numbers.txt

Wenn man das alles zusammennimmt, gibt uns der obige Befehl ls -F / eine Liste der Dateien und Verzeichnisse im Stammverzeichnis /. Ein Beispiel für die Ausgabe, die Sie mit dem obigen Befehl erhalten könnten, finden Sie unten:

BASH

$ ls -F /

AUSGABE

Applications/         System/
Library/              Users/
Network/              Volumes/

Nelle’s Pipeline: Organisieren von Dateien

Mit diesem Wissen über Dateien und Verzeichnisse ist Nelle bereit, die Dateien zu organisieren, die die Protein-Assay-Maschine erstellen wird.

Sie erstellt ein Verzeichnis mit dem Namen north-pacific-gyre (um sich daran zu erinnern, woher die Daten stammen), das die Datendateien von der Testmaschine und ihre Datenverarbeitungsskripte enthalten wird.

Jede ihrer physischen Proben ist gemäß der Konvention ihres Labors mit einer eindeutigen zehnstelligen ID gekennzeichnet, z. B. “NENE01729A”. Diese ID hat sie in ihrem Entnahmeprotokoll verwendet, um den Ort, die Zeit, die Tiefe und andere Merkmale der Probe aufzuzeichnen, daher beschließt sie, sie im Dateinamen jeder Datendatei zu verwenden. Da die Ausgabe des Prüfgeräts im Klartext erfolgt, nennt sie ihre Dateien NENE01729A.txt, NENE01812A.txt usw. Alle 1520 Dateien werden im selben Verzeichnis gespeichert.

Jetzt kann Nelle in ihrem aktuellen Verzeichnis shell-lesson-data sehen, welche Dateien sie hat, indem sie den Befehl benutzt:

BASH

$ ls north-pacific-gyre/

Dieser Befehl ist eine Menge zu tippen, aber sie kann die Shell die meiste Arbeit durch die sogenannte Tab-Vervollständigung erledigen lassen. Wenn sie tippt:

BASH

$ ls nor

und drückt dann Tab (die Tabulator-Taste auf ihrer Tastatur), vervollständigt die Shell automatisch den Verzeichnisnamen für sie:

BASH

$ ls north-pacific-gyre/

Erneutes Drücken von Tab bringt nichts, da es mehrere Möglichkeiten gibt; zweimaliges Drücken von Tab führt zu einer Liste aller Dateien.

Wenn Nelle dann G drückt und dann wieder Tab drückt, wird die Shell ‘goo’ anhängen, da alle Dateien, die mit ‘g’ beginnen, die ersten drei Zeichen ‘goo’ gemeinsam haben.

BASH

$ ls north-pacific-gyre/goo

Um alle diese Dateien zu sehen, kann sie Tab noch zweimal drücken.

BASH

ls north-pacific-gyre/goo
goodiff.sh   goostats.sh

Dies wird Tab-Vervollständigung genannt, und wir werden es im weiteren Verlauf in vielen anderen Tools sehen.

Hauptpunkte
  • Das Dateisystem ist für die Verwaltung von Informationen auf der Festplatte zuständig.
  • Informationen werden in Dateien gespeichert, die wiederum in Verzeichnissen (Ordnern) abgelegt sind.
  • Verzeichnisse können auch andere Verzeichnisse speichern, die dann einen Verzeichnisbaum bilden.
  • pwd gibt das aktuelle Arbeitsverzeichnis des Benutzers aus.
  • ls [path] gibt eine Auflistung einer bestimmten Datei oder eines bestimmten Verzeichnisses aus; ls allein listet das aktuelle Arbeitsverzeichnis auf.
  • cd [path] ändert das aktuelle Arbeitsverzeichnis.
  • Die meisten Befehle nehmen Optionen an, die mit einem einzelnen - beginnen.
  • Verzeichnisnamen in einem Pfad werden unter Unix mit / getrennt, unter Windows jedoch mit \.
  • / allein ist das Stammverzeichnis des gesamten Dateisystems.
  • Ein absoluter Pfad gibt einen Ort an, der von der Root des Dateisystems ausgeht.
  • Ein relativer Pfad gibt einen Ort an, der vom aktuellen Ort ausgeht.
  • . allein bedeutet ‘das aktuelle Verzeichnis’; .. bedeutet ‘das Verzeichnis über dem aktuellen’.

Content from Arbeiten mit Dateien und Verzeichnissen


Zuletzt aktualisiert am 2025-10-23 | Diese Seite bearbeiten

Geschätzte Zeit: 50 Minuten

Übersicht

Fragen

  • Wie kann ich Dateien und Verzeichnisse erstellen, kopieren und löschen?
  • Wie kann ich Dateien bearbeiten?

Ziele

  • Löschen, Kopieren und Verschieben von angegebenen Dateien und/oder Verzeichnissen.
  • Erstellen Sie Dateien in dieser Hierarchie mit einem Editor oder durch Kopieren und Umbenennen vorhandener Dateien.
  • Erstellen Sie eine Verzeichnishierarchie, die einem vorgegebenen Diagramm entspricht.

Erstellen von Verzeichnissen


Wir wissen jetzt, wie wir Dateien und Verzeichnisse erkunden können, aber wie erstellen wir sie überhaupt?

In dieser Folge lernen wir das Erstellen und Verschieben von Dateien und Verzeichnissen am Beispiel des Verzeichnisses exercise-data/writing.

Erster Schritt: sehen, wo wir sind und was wir bereits haben

Wir sollten uns immer noch im Verzeichnis shell-lesson-data auf dem Desktop befinden, was wir mit überprüfen können:

BASH

$ pwd

AUSGABE

/Users/nelle/Desktop/shell-lesson-data

Als nächstes werden wir in das Verzeichnis exercise-data/writing wechseln und sehen, was es enthält:

BASH

$ cd exercise-data/writing/
$ ls -F

AUSGABE

haiku.txt  LittleWomen.txt

Erstellen Sie ein Verzeichnis

Erstellen wir ein neues Verzeichnis namens thesis mit dem Befehl mkdir thesis (der keine Ausgabe hat):

BASH

$ mkdir thesis

Wie der Name schon vermuten lässt, bedeutet mkdir ‘make directory’ (‘Verzeichnis erstellen’). Da thesis ein relativer Pfad ist (d.h. keinen führenden Schrägstrich hat, wie /what/ever/thesis), wird das neue Verzeichnis im aktuellen Arbeitsverzeichnis erstellt:

BASH

$ ls -F

AUSGABE

haiku.txt  LittleWomen.txt  thesis/

Da wir das Verzeichnis thesis gerade erst erstellt haben, befindet sich darin noch nichts:

BASH

$ ls -F thesis

Beachten Sie, dass mkdir nicht darauf beschränkt ist, einzelne Verzeichnisse auf einmal zu erstellen. Die Option -p erlaubt mkdir, ein Verzeichnis mit verschachtelten Unterverzeichnissen in einem einzigen Vorgang zu erstellen:

BASH

$ mkdir -p ../project/data ../project/results

Die Option -R zum ls Befehl listet alle verschachtelten Unterverzeichnisse innerhalb eines Verzeichnisses auf. Lassen Sie uns ls -FR verwenden, um rekursiv die neue Verzeichnishierarchie aufzulisten, die wir gerade im Verzeichnis project erstellt haben:

BASH

$ ls -FR ../project

AUSGABE

../project/:
data/  results/

../project/data:

../project/results:
Wichtig

Zwei Möglichkeiten, das Gleiche zu tun

Die Verwendung der Shell zur Erstellung eines Verzeichnisses unterscheidet sich nicht von der Verwendung eines Datei-Explorers. Wenn Sie das aktuelle Verzeichnis mit dem grafischen Dateiexplorer Ihres Betriebssystems öffnen, wird das Verzeichnis thesis auch dort erscheinen. Während die Shell und der Dateiexplorer zwei verschiedene Wege sind, mit den Dateien zu interagieren, sind die Dateien und Verzeichnisse selbst die gleichen.

Wichtig

Gute Namen für Dateien und Verzeichnisse

Komplizierte Namen von Dateien und Verzeichnissen können Ihnen das Leben schwer machen, wenn Sie auf der Kommandozeile arbeiten. Hier geben wir Ihnen ein paar nützliche Tipps für die Namen Ihrer Dateien und Verzeichnisse.

  1. Verwenden Sie keine Leerzeichen.

Leerzeichen können einen Namen aussagekräftiger machen, aber da Leerzeichen verwendet werden, um Argumente auf der Kommandozeile zu trennen, ist es besser, sie in Namen von Dateien und Verzeichnissen zu vermeiden. Sie können stattdessen - oder _ verwenden (z.B. north-pacific-gyre/ anstelle von north pacific gyre/). Um dies zu testen, versuchen Sie mkdir north pacific gyre einzugeben und sehen Sie, welches Verzeichnis (oder Verzeichnisse!) erstellt wird, wenn Sie mit ls -F prüfen.

  1. Beginnen Sie den Namen nicht mit - (Bindestrich).

Befehle behandeln Namen, die mit - beginnen, als Optionen.

  1. Bleiben Sie bei Buchstaben, Zahlen, . (Punkt), - (Bindestrich) und _ (Unterstrich).

Viele andere Zeichen haben in der Kommandozeile eine besondere Bedeutung. Wir werden in dieser Lektion einige davon kennenlernen. Es gibt Sonderzeichen, die dazu führen können, dass Ihr Befehl nicht wie erwartet funktioniert, und die sogar zu Datenverlust führen können.

Wenn Sie auf Namen von Dateien oder Verzeichnissen verweisen müssen, die Leerzeichen oder andere Sonderzeichen enthalten, sollten Sie den Namen in einfache Anführungszeichen einschließen ('').

Lernende können manchmal in Befehlszeilen-Texteditoren wie Vim, Emacs oder Nano gefangen sein. Das Schließen des Terminalemulators und das Öffnen eines neuen kann frustrierend sein, da die Lernenden erneut zum richtigen Ordner navigieren müssen. Unsere Empfehlung, um dieses Problem zu entschärfen, ist, dass die Lehrkräfte während der Workshops denselben Texteditor wie die Lernenden verwenden sollten (in den meisten Fällen Nano).

Erstellen einer Textdatei

Wechseln wir unser Arbeitsverzeichnis mit cd in thesis und erstellen mit dem Texteditor Nano eine Datei namens draft.txt:

BASH

$ cd thesis
$ nano draft.txt
Wichtig

Welcher Editor?

Wenn wir sagen, ‘nano ist ein Texteditor’, dann meinen wir wirklich ‘Text’. Er kann nur mit einfachen Zeichendaten arbeiten, nicht mit Tabellen, Bildern oder anderen menschenfreundlichen Medien. Wir verwenden ihn in den Beispielen, weil er einer der am wenigsten komplexen Texteditoren ist. Aufgrund dieser Eigenschaft ist er jedoch möglicherweise nicht leistungsfähig oder flexibel genug für die Arbeit, die Sie nach diesem Workshop erledigen müssen. Auf Unix-Systemen (wie Linux und macOS) verwenden viele Programmierer Emacs oder Vim (die beide mehr Zeit zum Erlernen benötigen) oder einen grafischen Editor wie Gedit oder VScode. Unter Windows können Sie auch Notepad++ verwenden. Windows hat auch einen eingebauten Editor namens notepad, der von der Befehlszeile aus auf die gleiche Weise wie nano für die Zwecke dieser Lektion ausgeführt werden kann.

Unabhängig davon, welchen Editor Sie verwenden, müssen Sie wissen, wo er Dateien sucht und speichert. Wenn Sie ihn von der Shell aus starten, wird er (wahrscheinlich) Ihr aktuelles Arbeitsverzeichnis als Standardverzeichnis verwenden. Wenn Sie das Startmenü Ihres Computers verwenden, speichert er die Dateien möglicherweise stattdessen in Ihrem Desktop- oder Dokumentenverzeichnis. Sie können dies ändern, indem Sie beim ersten Mal, wenn Sie “Speichern unter…” wählen, in ein anderes Verzeichnis wechseln

Geben wir ein paar Zeilen Text ein.

Screenshot des Nano-Texteditors in Aktion mit dem Text It's not publish or perish any more, it's share and thrive

Wenn wir mit unserem Text zufrieden sind, können wir Strg+O drücken (drücken Sie die Strg oder Steuerung Taste und, während Sie sie gedrückt halten, drücken Sie die O Taste), um unsere Daten auf die Festplatte zu schreiben. Wir werden aufgefordert, einen Namen für die Datei anzugeben, die unseren Text enthalten soll. Drücken Sie Return, um die vorgeschlagene Vorgabe draft.txt zu übernehmen.

Sobald unsere Datei gespeichert ist, können wir Strg+X verwenden, um den Editor zu verlassen und zur Shell zurückzukehren.

Wichtig

Steuerung, Strg, oder ^ Taste

Die Steuerungstaste wird auch als ‘Strg’-Taste bezeichnet. Es gibt verschiedene Möglichkeiten, die Verwendung der Steuerungstaste zu beschreiben. Zum Beispiel können Sie eine Anweisung sehen, die Steuertaste zu drücken und, während Sie sie gedrückt halten, die X-Taste zu drücken, die wie folgt beschrieben wird:

  • Strg-X
  • Strg+X
  • Strg-X
  • Strg+X
  • ^X
  • C-x

In nano sehen Sie am unteren Rand des Bildschirms ^G Get Help ^O WriteOut. Das bedeutet, dass du Control-G benutzen kannst, um Hilfe zu bekommen und Control-O, um deine Datei zu speichern.

nano hinterlässt nach dem Beenden keine Ausgabe auf dem Bildschirm, aber ls zeigt nun, dass wir eine Datei namens draft.txt erstellt haben:

BASH

$ ls

AUSGABE

draft.txt
Aufgabe

Dateien auf eine andere Weise erstellen

Wir haben gesehen, wie man Textdateien mit dem Editor nano erstellt. Versuchen Sie nun den folgenden Befehl:

BASH

$ touch my_file.txt
  1. Was hat der Befehl touch bewirkt? Wenn Sie sich Ihr aktuelles Verzeichnis mit dem GUI-Dateiexplorer ansehen, wird die Datei dann angezeigt?

  2. Benutze ls -l, um die Dateien zu untersuchen. Wie groß ist my_file.txt?

  3. Wann würden Sie eine Datei auf diese Weise erstellen wollen?

  1. Der Befehl touch erzeugt eine neue Datei namens my_file.txt in Ihrem aktuellen Verzeichnis. Sie können diese neu erzeugte Datei beobachten, indem Sie ls an der Eingabeaufforderung eingeben. die Datei my_file.txt kann auch in Ihrem GUI-Dateiexplorer angezeigt werden.

  2. Wenn Sie die Datei mit ls -l untersuchen, beachten Sie, dass die Größe von my_file.txt 0 Bytes beträgt. Mit anderen Worten, sie enthält keine Daten. Wenn Sie my_file.txt mit Ihrem Texteditor öffnen, ist sie leer.

  3. Einige Programme erzeugen nicht selbst Ausgabedateien, sondern setzen voraus, dass bereits leere Dateien erzeugt wurden. Wenn das Programm ausgeführt wird, sucht es nach einer vorhandenen Datei, um sie mit seiner Ausgabe zu füllen. Mit dem Befehl touch können Sie auf effiziente Weise eine leere Textdatei erzeugen, die von solchen Programmen verwendet werden kann.

Diskussion

Dateien auf eine andere Weise erstellen (continued)

Um spätere Verwirrung zu vermeiden, empfehlen wir, die soeben erstellte Datei zu entfernen, bevor Sie mit dem Rest der Episode fortfahren, da sonst die zukünftigen Ausgaben von denen in der Lektion abweichen können. Verwenden Sie dazu den folgenden Befehl:

BASH

$ rm my_file.txt
Wichtig

What’s In A Name?

Sie haben vielleicht bemerkt, dass alle Dateien von Nelle “irgendetwas dot irgendetwas” heißen, und in diesem Teil der Lektion haben wir immer die Erweiterung .txt verwendet. Dies ist nur eine Konvention; wir können eine Datei mythesis oder fast alles andere nennen, was wir wollen. Die meisten Leute verwenden jedoch meist zweiteilige Namen, um ihnen (und ihren Programmen) zu helfen, verschiedene Arten von Dateien zu unterscheiden. Der zweite Teil eines solchen Namens wird Dateinamenerweiterung genannt und gibt an, welche Art von Daten die Datei enthält: .txt signalisiert eine einfache Textdatei, .pdf weist auf ein PDF-Dokument hin, .cfg ist eine Konfigurationsdatei mit Parametern für ein Programm oder ein anderes, .png ist ein PNG-Bild, und so weiter.

Dies ist nur eine Konvention, wenn auch eine wichtige. Dateien enthalten lediglich Bytes; es liegt an uns und unseren Programmen, diese Bytes gemäß den Regeln für einfache Textdateien, PDF-Dokumente, Konfigurationsdateien, Bilder usw. zu interpretieren.

Ein PNG-Bild eines Wals als whale.mp3 zu benennen, verwandelt es nicht irgendwie auf magische Weise in eine Aufnahme von Walgesang, obwohl es möglicherweise das Betriebssystem veranlasst, die Datei mit einem Musikabspielprogramm zu assoziieren. In diesem Fall, wenn jemand in einem Dateiexplorer-Programm auf whale.mp3 doppelklickt, wird der Musik-Player automatisch (und fälschlicherweise) versuchen, die Datei whale.mp3 zu öffnen.

Dateien und Verzeichnisse verschieben


Rückkehr in das Verzeichnis shell-lesson-data/exercise-data/writing,

BASH

$ cd ~/Desktop/shell-lesson-data/exercise-data/writing

In unserem thesis Verzeichnis haben wir eine Datei draft.txt, was kein besonders informativer Name ist, also ändern wir den Namen der Datei mit mv, was kurz für ‘move’ (‘verschieben’) ist:

BASH

$ mv thesis/draft.txt thesis/quotes.txt

Das erste Argument gibt an, was wir verschieben, während das zweite angibt, wohin es gehen soll. In diesem Fall verschieben wir thesis/draft.txt nach thesis/quotes.txt, was den gleichen Effekt hat wie das Umbenennen der Datei. Sicherlich zeigt uns ls, dass thesis nun eine Datei namens quotes.txt enthält:

BASH

$ ls thesis

AUSGABE

quotes.txt

Man muss vorsichtig sein, wenn man den Namen der Zieldatei angibt, da mv stillschweigend jede existierende Datei mit demselben Namen überschreibt, was zu Datenverlust führen kann. Standardmäßig wird mv vor dem Überschreiben von Dateien nicht nach einer Bestätigung fragen. Eine zusätzliche Option, mv -i (oder mv --interactive), veranlasst mv jedoch, eine solche Bestätigung zu verlangen.

Beachten Sie, dass mv auch bei Verzeichnissen funktioniert.

Lass uns quotes.txt in das aktuelle Arbeitsverzeichnis verschieben. Wir verwenden wieder mv, aber dieses Mal geben wir nur den Namen eines Verzeichnisses als zweites Argument an, um mv mitzuteilen, dass wir den Dateinamen behalten, aber die Datei an einen neuen Ort verschieben wollen. (Deshalb heißt der Befehl ‘move’.) In diesem Fall ist der Verzeichnisname, den wir verwenden, der spezielle Verzeichnisname ., den wir bereits erwähnt haben.

BASH

$ mv thesis/quotes.txt .

Der Effekt ist, dass die Datei von dem Verzeichnis, in dem sie sich befand, in das aktuelle Arbeitsverzeichnis verschoben wird. ls zeigt uns nun, dass thesis leer ist:

BASH

$ ls thesis

AUSGABE

$

Alternativ können wir bestätigen, dass die Datei quotes.txt nicht mehr im Verzeichnis thesis vorhanden ist, indem wir explizit versuchen, sie aufzulisten:

BASH

$ ls thesis/quotes.txt

FEHLER

ls: cannot access 'thesis/quotes.txt': No such file or directory

ls mit einem Dateinamen oder Verzeichnis als Argument listet nur die angeforderte Datei oder das Verzeichnis auf. Wenn die als Argument angegebene Datei nicht existiert, gibt die Shell einen Fehler zurück, wie wir oben gesehen haben. Wir können dies benutzen, um zu sehen, dass quotes.txt jetzt in unserem aktuellen Verzeichnis vorhanden ist:

BASH

$ ls quotes.txt

AUSGABE

quotes.txt
Aufgabe

Verschieben von Dateien in einen neuen Ordner

Nachdem sie die folgenden Befehle ausgeführt hat, stellt Jamie fest, dass sie die Dateien sucrose.dat und maltose.dat in den falschen Ordner gelegt hat. Die Dateien hätten in den Ordner raw gelegt werden müssen.

BASH

$ ls -F
 analyzed/ raw/
$ ls -F analyzed
fructose.dat glucose.dat maltose.dat sucrose.dat
$ cd analyzed

Füllen Sie die Felder aus, um diese Dateien in den Ordner raw/ zu verschieben (d.h. in den Ordner, in den sie vergessen hat, sie abzulegen)

BASH

$ mv sucrose.dat maltose.dat ____/____

BASH

$ mv sucrose.dat maltose.dat ../raw

Erinnern Sie sich, dass sich .. auf das übergeordnete Verzeichnis (d.h. eines über dem aktuellen Verzeichnis) und . auf das aktuelle Verzeichnis bezieht.

Kopieren von Dateien und Verzeichnissen


Der Befehl cp funktioniert ähnlich wie mv, nur dass er eine Datei kopiert, anstatt sie zu verschieben. Wir können überprüfen, ob er das Richtige getan hat, indem wir ls mit zwei Pfaden als Argumente verwenden — wie die meisten Unix-Befehle kann ls mehrere Pfade auf einmal erhalten:

BASH

$ cp quotes.txt thesis/quotations.txt
$ ls quotes.txt thesis/quotations.txt

AUSGABE

quotes.txt   thesis/quotations.txt

Wir können auch ein Verzeichnis und seinen gesamten Inhalt kopieren, indem wir die Option recursive -r verwenden, z.B. um ein Verzeichnis zu sichern:

BASH

$ cp -r thesis thesis_backup

Wir können das Ergebnis überprüfen, indem wir den Inhalt der beiden Verzeichnisse thesis und thesis_backup auflisten:

BASH

$ ls thesis thesis_backup

AUSGABE

thesis:
quotations.txt

thesis_backup:
quotations.txt

Es ist wichtig, das -r-Flag einzuschließen. Wenn Sie ein Verzeichnis kopieren wollen und diese Option weglassen, werden Sie eine Meldung sehen, dass das Verzeichnis weggelassen wurde, weil -r not specified.

BASH

$ cp thesis thesis_backup
cp: -r not specified; omitting directory 'thesis'
Aufgabe

Umbenennen von Dateien

Angenommen, Sie haben in Ihrem aktuellen Verzeichnis eine Textdatei erstellt, die eine Liste der statistischen Tests enthält, die Sie für die Analyse Ihrer Daten benötigen, und sie statstics.txt genannt

Nachdem Sie diese Datei erstellt und gespeichert haben, stellen Sie fest, dass Sie den Dateinamen falsch geschrieben haben! Sie möchten den Fehler korrigieren. Welchen der folgenden Befehle können Sie dazu verwenden?

  1. cp statstics.txt statistics.txt
  2. mv statstics.txt statistics.txt
  3. mv statstics.txt .
  4. cp statstics.txt .
  1. Nein. Dies würde zwar eine Datei mit dem richtigen Namen erstellen, aber die falsch benannte Datei ist noch im Verzeichnis vorhanden und müsste gelöscht werden.
  2. Ja, das würde funktionieren, um die Datei umzubenennen.
  3. Nein, der Punkt(.) zeigt an, wohin die Datei verschoben werden soll, gibt aber keinen neuen Dateinamen an; identische Dateinamen können nicht erstellt werden.
  4. Nein, der Punkt(.) gibt an, wohin die Datei kopiert werden soll, liefert aber keinen neuen Dateinamen; identische Dateinamen können nicht erstellt werden.
Aufgabe

Verschieben und Kopieren

Was ist die Ausgabe des abschließenden Befehls ls in der unten gezeigten Reihenfolge?

BASH

$ pwd

AUSGABE

/Users/jamie/data

BASH

$ ls

AUSGABE

proteins.dat

BASH

$ mkdir recombined
$ mv proteins.dat recombined/
$ cp recombined/proteins.dat ../proteins-saved.dat
$ ls
  1. proteins-saved.dat recombined
  2. recombined
  3. proteins.dat recombined
  4. proteins-saved.dat

Wir beginnen im Verzeichnis /Users/jamie/data und erstellen einen neuen Ordner namens recombined. Die zweite Zeile verschiebt (mv) die Datei proteins.dat in den neuen Ordner (recombined). Die dritte Zeile erstellt eine Kopie der Datei, die wir gerade verschoben haben. Der knifflige Teil hier ist, wohin die Datei kopiert wurde. Erinnern Sie sich, dass .. “eine Ebene höher gehen” bedeutet, also befindet sich die kopierte Datei jetzt in /Users/jamie. Beachten Sie, dass .. in Bezug auf das aktuelle Arbeitsverzeichnis interpretiert wird, nicht in Bezug auf den Ort der kopierten Datei. Das einzige, was mit ls (in /Users/jamie/data) angezeigt wird, ist also der neu zusammengestellte Ordner.

  1. Nein, siehe Erklärung oben. proteins-saved.dat befindet sich in /Users/jamie
  2. Ja
  3. Nein, siehe Erklärung oben. proteins.dat befindet sich in /Users/jamie/data/recombined
  4. Nein, siehe Erklärung oben. proteins-saved.dat befindet sich in /Users/jamie

Entfernen von Dateien und Verzeichnissen


Kehren wir zum Verzeichnis shell-lesson-data/exercise-data/writing zurück und räumen wir dieses Verzeichnis auf, indem wir die Datei quotes.txt entfernen, die wir erstellt haben. Der Unix-Befehl, den wir dafür verwenden, ist rm (kurz für ‘remove’):

BASH

$ rm quotes.txt

Wir können bestätigen, dass die Datei mit ls verschwunden ist:

BASH

$ ls quotes.txt

FEHLER

ls: cannot access 'quotes.txt': No such file or directory
Wichtig

Deleting Is Forever

Die Unix-Shell hat keinen Papierkorb, aus dem wir gelöschte Dateien wiederherstellen können (obwohl die meisten grafischen Oberflächen von Unix dies tun). Wenn wir Dateien löschen, werden sie stattdessen aus dem Dateisystem entfernt, damit ihr Speicherplatz auf der Festplatte wiederverwendet werden kann. Es gibt zwar Tools zum Auffinden und Wiederherstellen gelöschter Dateien, aber es gibt keine Garantie, dass sie in jeder Situation funktionieren, da der Computer den Speicherplatz der Datei möglicherweise sofort wiederverwendet.

Aufgabe

Sichere Verwendung von rm

Was passiert, wenn wir rm -i thesis_backup/quotations.txt ausführen? Warum sollten wir diesen Schutz haben, wenn wir rm verwenden?

AUSGABE

rm: remove regular file 'thesis_backup/quotations.txt'? y

Die Option -i fragt vor (jedem) Löschen nach (verwenden Sie Y, um das Löschen zu bestätigen oder N, um die Datei zu behalten). Die Unix-Shell hat keinen Mülleimer, so dass alle gelöschten Dateien für immer verschwinden werden. Mit der Option -i können wir überprüfen, dass wir nur die Dateien löschen, die wir auch wirklich löschen wollen.

Wenn wir versuchen, das Verzeichnis thesis mit rm thesis zu entfernen, erhalten wir eine Fehlermeldung:

BASH

$ rm thesis

FEHLER

rm: cannot remove 'thesis': Is a directory

Das passiert, weil rm standardmäßig nur bei Dateien funktioniert, nicht bei Verzeichnissen.

rm kann ein Verzeichnis mitsamt seinem Inhalt entfernen, wenn wir die rekursive Option -r verwenden, und es wird dies ohne jegliche Bestätigungsaufforderung tun:

BASH

$ rm -r thesis

Da es keine Moeglichkeit gibt, mit der Shell geloeschte Dateien wiederherzustellen, sollte rm -r mit grosser Vorsicht verwendet werden (man koennte die interaktive Option rm -r -i hinzufuegen).

Operationen mit mehreren Dateien und Verzeichnissen


Oftmals muss man mehrere Dateien auf einmal kopieren oder verschieben. Dies kann durch die Angabe einer Liste einzelner Dateinamen oder durch die Angabe eines Namensmusters mit Wildcards geschehen. Wildcards sind Sonderzeichen, die verwendet werden können, um unbekannte Zeichen oder Zeichensätze bei der Navigation im Unix-Dateisystem darzustellen.

Aufgabe

Kopieren mit mehreren Dateinamen

Für diese Übung können Sie die Befehle im Verzeichnis shell-lesson-data/exercise-data testen.

Was macht cp im folgenden Beispiel, wenn mehrere Dateinamen und ein Verzeichnisname angegeben werden?

BASH

$ mkdir backup
$ cp creatures/minotaur.dat creatures/unicorn.dat backup/

Was macht cp im folgenden Beispiel, wenn drei oder mehr Dateinamen angegeben werden?

BASH

$ cd creatures
$ ls -F

AUSGABE

basilisk.dat  minotaur.dat  unicorn.dat

BASH

$ cp minotaur.dat unicorn.dat basilisk.dat

Wenn mehr als ein Dateiname gefolgt von einem Verzeichnisnamen angegeben wird (d.h. das Zielverzeichnis muss das letzte Argument sein), kopiert cp die Dateien in das genannte Verzeichnis.

Wenn drei Dateinamen angegeben werden, gibt cp einen Fehler wie den folgenden aus, weil es einen Verzeichnisnamen als letztes Argument erwartet.

FEHLER

cp: target 'basilisk.dat' is not a directory

Verwendung von Platzhaltern für den gleichzeitigen Zugriff auf mehrere Dateien

Wichtig

Wildcards

* ist eine Wildcard, die für null oder mehr andere Zeichen steht. Betrachten wir das Verzeichnis shell-lesson-data/exercise-data/alkanes: *.pdb steht für ethane.pdb, propane.pdb und jede Datei, die mit ‘.pdb’ endet. Auf der anderen Seite repräsentiert p*.pdb nur pentane.pdb und propane.pdb, weil das ‘p’ am Anfang nur Dateinamen repräsentieren kann, die mit dem Buchstaben ‘p’ beginnen.

? ist auch ein Platzhalter, aber er steht für genau ein Zeichen. So könnte ?ethane.pdb für methane.pdb stehen, während *ethane.pdb sowohl für ethane.pdb als auch für methane.pdb steht.

Wildcards können in Kombination miteinander verwendet werden. Zum Beispiel gibt ???ane.pdb drei Zeichen an, gefolgt von ane.pdb, was cubane.pdb ethane.pdb octane.pdb ergibt.

Wenn die Shell einen Platzhalter sieht, expandiert sie diesen, um eine Liste passender Dateinamen zu erstellen, bevor sie den vorangehenden Befehl ausführt. Ausnahmsweise, wenn ein Platzhalterausdruck mit keiner Datei übereinstimmt, übergibt die Bash den Ausdruck als Argument an den Befehl, wie er ist. Wenn Sie beispielsweise ls *.pdf im Verzeichnis alkanes eingeben (das nur Dateien enthält, deren Namen auf .pdb enden), erhalten Sie die Fehlermeldung, dass es keine Datei namens *.pdf gibt. Im Allgemeinen sehen Befehle wie wc und ls jedoch die Listen der Dateinamen, die auf diese Ausdrücke passen, aber nicht die Platzhalter selbst. Es ist die Shell, nicht die anderen Programme, die die Wildcards expandiert.

Aufgabe

Auflisten der Dateinamen, die einem Muster entsprechen

Welche(r) ls-Befehl(e) erzeugt/erzeugen diese Ausgabe, wenn er/sie im Verzeichnis alkanes ausgeführt wird/werden?

ethane.pdb methane.pdb

  1. ls *t*ane.pdb
  2. ls *t?ne.*
  3. ls *t??ne.pdb
  4. ls ethane.*

Die Lösung lautet 3.

1. zeigt alle Dateien an, deren Namen null oder mehr Zeichen (*) gefolgt von dem Buchstaben t, dann null oder mehr Zeichen (*) gefolgt von ane.pdb enthalten. Dies ergibt ethane.pdb methane.pdb octane.pdb pentane.pdb.

2. zeigt alle Dateien, deren Namen mit null oder mehr Zeichen beginnen (*), gefolgt von dem Buchstaben t, dann ein einzelnes Zeichen (?), dann ne. gefolgt von null oder mehr Zeichen (*). Dies ergibt octane.pdb und pentane.pdb, aber keine Übereinstimmung mit etwas, das auf thane.pdb endet.

3. behebt die Probleme von Option 2, indem zwei Zeichen (??) zwischen t und ne gefunden werden. Dies ist die Lösung.

4. zeigt nur Dateien, die mit ethane. beginnen.

Aufgabe

Mehr über Wildcards

Sam hat ein Verzeichnis mit Kalibrierungsdaten, Datensätzen und Beschreibungen der Datensätze:

BASH

.
├── 2015-10-23-calibration.txt
├── 2015-10-23-dataset1.txt
├── 2015-10-23-dataset2.txt
├── 2015-10-23-dataset_overview.txt
├── 2015-10-26-calibration.txt
├── 2015-10-26-dataset1.txt
├── 2015-10-26-dataset2.txt
├── 2015-10-26-dataset_overview.txt
├── 2015-11-23-calibration.txt
├── 2015-11-23-dataset1.txt
├── 2015-11-23-dataset2.txt
├── 2015-11-23-dataset_overview.txt
├── backup
│   ├── calibration
│   └── datasets
└── send_to_bob
    ├── all_datasets_created_on_a_23rd
    └── all_november_files

Bevor sie zu einer weiteren Exkursion aufbricht, möchte sie ihre Daten sichern und einige Datensätze an ihren Kollegen Bob schicken. Sam verwendet die folgenden Befehle, um diese Aufgabe zu erledigen:

BASH

$ cp *dataset* backup/datasets
$ cp ____calibration____ backup/calibration
$ cp 2015-____-____ send_to_bob/all_november_files/
$ cp ____ send_to_bob/all_datasets_created_on_a_23rd/

Hilf Sam, indem du die Lücken ausfüllst.

Die resultierende Verzeichnisstruktur sollte wie folgt aussehen

BASH

.
├── 2015-10-23-calibration.txt
├── 2015-10-23-dataset1.txt
├── 2015-10-23-dataset2.txt
├── 2015-10-23-dataset_overview.txt
├── 2015-10-26-calibration.txt
├── 2015-10-26-dataset1.txt
├── 2015-10-26-dataset2.txt
├── 2015-10-26-dataset_overview.txt
├── 2015-11-23-calibration.txt
├── 2015-11-23-dataset1.txt
├── 2015-11-23-dataset2.txt
├── 2015-11-23-dataset_overview.txt
├── backup
│   ├── calibration
│   │   ├── 2015-10-23-calibration.txt
│   │   ├── 2015-10-26-calibration.txt
│   │   └── 2015-11-23-calibration.txt
│   └── datasets
│       ├── 2015-10-23-dataset1.txt
│       ├── 2015-10-23-dataset2.txt
│       ├── 2015-10-23-dataset_overview.txt
│       ├── 2015-10-26-dataset1.txt
│       ├── 2015-10-26-dataset2.txt
│       ├── 2015-10-26-dataset_overview.txt
│       ├── 2015-11-23-dataset1.txt
│       ├── 2015-11-23-dataset2.txt
│       └── 2015-11-23-dataset_overview.txt
└── send_to_bob
    ├── all_datasets_created_on_a_23rd
    │   ├── 2015-10-23-dataset1.txt
    │   ├── 2015-10-23-dataset2.txt
    │   ├── 2015-10-23-dataset_overview.txt
    │   ├── 2015-11-23-dataset1.txt
    │   ├── 2015-11-23-dataset2.txt
    │   └── 2015-11-23-dataset_overview.txt
    └── all_november_files
        ├── 2015-11-23-calibration.txt
        ├── 2015-11-23-dataset1.txt
        ├── 2015-11-23-dataset2.txt
        └── 2015-11-23-dataset_overview.txt

BASH

$ cp *calibration.txt backup/calibration
$ cp 2015-11-* send_to_bob/all_november_files/
$ cp *-23-dataset* send_to_bob/all_datasets_created_on_a_23rd/
Aufgabe

Organisieren von Verzeichnissen und Dateien

Jamie arbeitet an einem Projekt und stellt fest, dass ihre Dateien nicht sehr gut organisiert sind:

BASH

$ ls -F

AUSGABE

analyzed/  fructose.dat    raw/   sucrose.dat

Die Dateien fructose.dat und sucrose.dat enthalten die Ausgabe ihrer Datenanalyse. Welche(n) Befehl(e), der/die in dieser Lektion behandelt wurde(n), muss sie ausführen, damit die folgenden Befehle die gezeigte Ausgabe erzeugen?

BASH

$ ls -F

AUSGABE

analyzed/   raw/

BASH

$ ls analyzed

AUSGABE

fructose.dat    sucrose.dat

BASH

mv *.dat analyzed

Jamie muss ihre Dateien fructose.dat und sucrose.dat in das Verzeichnis analyzed verschieben. Die Shell expandiert *.dat, um alle .dat-Dateien im aktuellen Verzeichnis zu finden. Der Befehl mv verschiebt dann die Liste der .dat-Dateien in das Verzeichnis “analyzed”.

Aufgabe

Reproduzieren einer Ordnerstruktur

Sie beginnen ein neues Experiment und möchten die Verzeichnisstruktur Ihres vorherigen Experiments duplizieren, damit Sie neue Daten hinzufügen können.

Angenommen, das vorherige Experiment befindet sich in einem Ordner namens 2016-05-18, der einen Ordner data enthält, der wiederum Ordner namens raw und processed enthält, die Datendateien enthalten. Das Ziel ist es, die Ordnerstruktur des Ordners 2016-05-18 in einen Ordner namens 2016-05-20 zu kopieren, so dass die endgültige Verzeichnisstruktur wie folgt aussieht:

AUSGABE

2016-05-20/
└── data
   ├── processed
   └── raw

Welcher der folgenden Befehle würde dieses Ziel erreichen? Was würden die anderen Befehle bewirken?

BASH

$ mkdir 2016-05-20
$ mkdir 2016-05-20/data
$ mkdir 2016-05-20/data/processed
$ mkdir 2016-05-20/data/raw

BASH

$ mkdir 2016-05-20
$ cd 2016-05-20
$ mkdir data
$ cd data
$ mkdir raw processed

BASH

$ mkdir 2016-05-20/data/raw
$ mkdir 2016-05-20/data/processed

BASH

$ mkdir -p 2016-05-20/data/raw
$ mkdir -p 2016-05-20/data/processed

BASH

$ mkdir 2016-05-20
$ cd 2016-05-20
$ mkdir data
$ mkdir raw processed

Die ersten beiden Befehlssätze erreichen dieses Ziel. Der erste Satz verwendet relative Pfade, um das oberste Verzeichnis vor den Unterverzeichnissen zu erstellen.

Der dritte Satz von Befehlen gibt einen Fehler, weil das Standardverhalten von mkdir kein Unterverzeichnis eines nicht existierenden Verzeichnisses erstellt: die Ordner der Zwischenebene müssen zuerst erstellt werden.

Der vierte Satz von Befehlen erreicht dieses Ziel. Denken Sie daran, dass die Option -p, gefolgt von einem Pfad zu einem oder mehreren Verzeichnissen, mkdir veranlasst, alle dazwischen liegenden Unterverzeichnisse zu erstellen, wie es erforderlich ist.

Der letzte Satz von Befehlen erzeugt die Verzeichnisse “raw” und “processed” auf derselben Ebene wie das Verzeichnis “data”.

Hauptpunkte
  • cp [old] [new] kopiert eine Datei.
  • mkdir [path] ein neues Verzeichnis erstellt.
  • mv [old] [new] verschiebt (benennt) eine Datei oder ein Verzeichnis um.
  • rm [path] entfernt (löscht) eine Datei.
  • * passt auf null oder mehr Zeichen in einem Dateinamen, also passt *.txt auf alle Dateien, die auf .txt enden.
  • ? passt auf jedes einzelne Zeichen in einem Dateinamen, also passt ?.txt auf a.txt, aber nicht auf any.txt.
  • Die Verwendung des Steuerschlüssels kann auf viele Arten beschrieben werden, einschließlich Ctrl-X, Control-X und ^X.
  • Die Shell hat keinen Mülleimer: Wenn etwas gelöscht ist, ist es wirklich weg.
  • Die meisten Dateinamen sind something.extension. Die Erweiterung ist nicht erforderlich und garantiert nichts, wird aber normalerweise verwendet, um die Art der Daten in der Datei anzugeben.
  • Abhängig von der Art Ihrer Arbeit benötigen Sie möglicherweise einen leistungsfähigeren Texteditor als Nano.

Content from Pipes und Filter


Zuletzt aktualisiert am 2025-10-23 | Diese Seite bearbeiten

Geschätzte Zeit: 35 Minuten

Übersicht

Fragen

  • Wie kann ich vorhandene Befehle kombinieren, um eine gewünschte Ausgabe zu erzeugen?
  • Wie kann ich nur einen Teil der Ausgabe anzeigen?

Ziele

  • Erklären Sie den Vorteil der Verknüpfung von Befehlen mit Pipes und Filtern.
  • Kombiniere Sequenzen von Befehlen, um eine neue Ausgabe zu erhalten
  • Leite die Ausgabe eines Befehls in eine Datei um.
  • Erkläre, was normalerweise passiert, wenn ein Programm oder eine Pipeline keine Eingaben zu verarbeiten hat.

Nachdem wir nun ein paar grundlegende Befehle kennen, können wir uns endlich der mächtigsten Eigenschaft der Shell zuwenden: der Leichtigkeit, mit der sie uns erlaubt, bestehende Programme auf neue Weise zu kombinieren. Wir beginnen mit dem Verzeichnis shell-lesson-data/exercise-data/alkanes, das sechs Dateien enthält, die einige einfache organische Moleküle beschreiben. Die Erweiterung .pdb zeigt an, dass diese Dateien im Protein Data Bank Format sind, einem einfachen Textformat, das den Typ und die Position jedes Atoms im Molekül angibt.

BASH

$ ls

AUSGABE

cubane.pdb    methane.pdb    pentane.pdb
ethane.pdb    octane.pdb     propane.pdb

Lassen Sie uns einen Beispielbefehl ausführen:

BASH

$ wc cubane.pdb

AUSGABE

20  156 1158 cubane.pdb

wc ist der ‘word count’ Befehl: er zählt die Anzahl der Zeilen, Wörter und Zeichen in Dateien (und gibt die Werte in dieser Reihenfolge von links nach rechts zurück).

Wenn wir den Befehl wc *.pdb ausführen, passt das * in *.pdb auf null oder mehr Zeichen, so dass die Shell *.pdb in eine Liste aller .pdb Dateien im aktuellen Verzeichnis verwandelt:

BASH

$ wc *.pdb

AUSGABE

  20  156  1158  cubane.pdb
  12  84   622   ethane.pdb
   9  57   422   methane.pdb
  30  246  1828  octane.pdb
  21  165  1226  pentane.pdb
  15  111  825   propane.pdb
 107  819  6081  total

Beachten Sie, dass wc *.pdb auch die Gesamtzahl aller Zeilen in der letzten Zeile der Ausgabe anzeigt.

Wenn wir wc -l statt nur wc ausführen, zeigt die Ausgabe nur die Anzahl der Zeilen pro Datei:

BASH

$ wc -l *.pdb

AUSGABE

  20  cubane.pdb
  12  ethane.pdb
   9  methane.pdb
  30  octane.pdb
  21  pentane.pdb
  15  propane.pdb
 107  total

Die Optionen -m und -w können auch mit dem Befehl wc verwendet werden, um nur die Anzahl der Zeichen bzw. die Anzahl der Wörter anzuzeigen.

Wichtig

Warum passiert nichts?

Was passiert, wenn ein Befehl eine Datei verarbeiten soll, wir ihm aber keinen Dateinamen geben? Zum Beispiel, was passiert, wenn wir eingeben:

BASH

$ wc -l

schreibt, aber nach dem Befehl nicht *.pdb (oder irgendetwas anderes) einträgt? Da es keine Dateinamen hat, geht wc davon aus, dass es Eingaben an der Eingabeaufforderung verarbeiten soll, also sitzt es einfach da und wartet darauf, dass wir ihm interaktiv Daten geben. Von außen sehen wir jedoch nur, wie es dasitzt, und der Befehl scheint nichts zu tun.

Wenn Sie einen solchen Fehler machen, können Sie aus diesem Zustand herauskommen, indem Sie die Steuerungstaste (Strg) gedrückt halten und einmal den Buchstaben C drücken: Strg+C. Lassen Sie dann beide Tasten los.

Erfassen der Ausgabe von Befehlen


Welche dieser Dateien enthält die wenigsten Zeilen? Diese Frage ist leicht zu beantworten, wenn es nur sechs Dateien gibt, aber was wäre, wenn es 6000 wären? Unser erster Schritt zur Lösung besteht darin, den Befehl auszuführen:

BASH

$ wc -l *.pdb > lengths.txt

Das Größer-als-Symbol, >, weist die Shell an, die Ausgabe des Befehls in eine Datei umzuleiten, anstatt sie auf dem Bildschirm auszugeben. Dieser Befehl gibt keine Bildschirmausgabe aus, da alles, was wc gedruckt hätte, stattdessen in die Datei lengths.txt gelangt ist. Wenn die Datei vor der Ausgabe des Befehls nicht existiert, wird die Shell die Datei erstellen. Wenn die Datei bereits existiert, wird sie stillschweigend überschrieben, was zu Datenverlusten führen kann. Daher ist bei redirect-Befehlen Vorsicht geboten.

ls lengths.txt bestätigt, dass die Datei existiert:

BASH

$ ls lengths.txt

AUSGABE

lengths.txt

Wir können nun den Inhalt von lengths.txt mit cat lengths.txt auf den Bildschirm schicken. Der Befehl cat hat seinen Namen von ‘concatenate’, d.h. zusammenfügen, und er gibt den Inhalt von Dateien nacheinander aus. In diesem Fall gibt es nur eine Datei, also zeigt uns cat nur, was sie enthält:

BASH

$ cat lengths.txt

AUSGABE

  20  cubane.pdb
  12  ethane.pdb
   9  methane.pdb
  30  octane.pdb
  21  pentane.pdb
  15  propane.pdb
 107  total
Wichtig

Seitenweise Ausgabe

Aus Gründen der Bequemlichkeit und Konsistenz werden wir in dieser Lektion weiterhin den Befehl cat verwenden, der jedoch den Nachteil hat, dass er immer die gesamte Datei auf den Bildschirm ausgibt. In der Praxis ist der Befehl less (z.B. less lengths.txt) nützlicher. Dieser Befehl zeigt einen Bildschirminhalt der Datei an und hält dann an. Sie können mit der Leertaste einen Bildschirm vorwärts oder mit b einen Bildschirm zurück gehen. Drücken Sie q zum Beenden.

Filtern der Ausgabe


Als nächstes werden wir den Befehl sort benutzen, um den Inhalt der Datei lengths.txt zu sortieren. Aber zuerst werden wir eine Übung machen, um ein wenig über den Sortierbefehl zu lernen:

Aufgabe

Was macht sort -n?

Die Datei shell-lesson-data/exercise-data/numbers.txt enthält die folgenden Zeilen:

10
2
19
22
6

Wenn wir sort auf dieser Datei ausführen, ist die Ausgabe:

AUSGABE

10
19
2
22
6

Wenn wir sort -n auf dieselbe Datei anwenden, erhalten wir stattdessen Folgendes:

AUSGABE

2
6
10
19
22

Erkläre, warum -n diesen Effekt hat.

Die Option -n legt eine numerische statt einer alphanumerischen Sortierung fest.

Wir werden auch die Option -n verwenden, um anzugeben, dass die Sortierung numerisch statt alphanumerisch ist. Dadurch wird die Datei nicht verändert, sondern das sortierte Ergebnis auf den Bildschirm übertragen:

BASH

$ sort -n lengths.txt

AUSGABE

  9  methane.pdb
 12  ethane.pdb
 15  propane.pdb
 20  cubane.pdb
 21  pentane.pdb
 30  octane.pdb
107  total

Wir können die sortierte Liste von Zeilen in eine andere temporäre Datei namens sorted-lengths.txt stellen, indem wir > sorted-lengths.txt nach dem Befehl einfügen, genauso wie wir > lengths.txt benutzt haben, um die Ausgabe von wc in lengths.txt zu stellen. Wenn wir das getan haben, können wir einen weiteren Befehl namens head ausführen, um die ersten Zeilen in sorted-lengths.txt zu erhalten:

BASH

$ sort -n lengths.txt > sorted-lengths.txt
$ head -n 1 sorted-lengths.txt

AUSGABE

  9  methane.pdb

Die Verwendung von -n 1 mit head sagt ihm, dass wir nur die erste Zeile der Datei wollen; -n 20 würde die ersten 20 bekommen, und so weiter. Da sorted-lengths.txt die Längen unserer Dateien in der Reihenfolge vom kleinsten zum größten Wert enthält, muss die Ausgabe von head die Datei mit den wenigsten Zeilen sein.

Wichtig

Umleitung auf dieselbe Datei

Es ist eine sehr schlechte Idee, zu versuchen, die Ausgabe eines Befehls, der auf eine Datei wirkt, in dieselbe Datei umzuleiten. Zum Beispiel:

BASH

$ sort -n lengths.txt > lengths.txt

Wenn Sie so etwas tun, können Sie falsche Ergebnisse erhalten und/oder den Inhalt von lengths.txt löschen.

Aufgabe

Was bedeutet >>?

Wir haben die Verwendung von > gesehen, aber es gibt einen ähnlichen Operator >>, der etwas anders funktioniert. Wir werden die Unterschiede zwischen diesen beiden Operatoren kennenlernen, indem wir einige Zeichenketten ausgeben. Mit dem Befehl echo können wir Zeichenketten ausgeben, z.B.

BASH

$ echo The echo command prints text

AUSGABE

The echo command prints text

Testen Sie nun die folgenden Befehle, um den Unterschied zwischen den beiden Operatoren herauszufinden:

BASH

$ echo hello > testfile01.txt

und:

BASH

$ echo hello >> testfile02.txt

Tipp: Versuchen Sie, jeden Befehl zweimal hintereinander auszuführen und dann die Ausgabedateien zu untersuchen.

Im ersten Beispiel mit > wird die Zeichenkette ‘hello’ nach testfile01.txt geschrieben, aber die Datei wird jedes Mal überschrieben, wenn wir den Befehl ausführen.

Im zweiten Beispiel sehen wir, dass der >>-Operator auch ‘hallo’ in eine Datei schreibt (in diesem Fall testfile02.txt), aber die Zeichenkette an die Datei anhängt, wenn sie bereits existiert (d.h. wenn wir es zum zweiten Mal ausführen).

Aufgabe

Daten anhängen

Wir haben bereits den Befehl head kennengelernt, der Zeilen vom Anfang einer Datei ausgibt. der Befehl tail ist ähnlich, druckt aber stattdessen Zeilen vom Ende einer Datei aus.

Betrachten Sie die Datei shell-lesson-data/exercise-data/animal-counts/animals.csv. Wählen Sie nach diesen Befehlen die Antwort aus, die der Datei animals-subset.csv entspricht:

BASH

$ head -n 3 animals.csv > animals-subset.csv
$ tail -n 2 animals.csv >> animals-subset.csv
  1. Die ersten drei Zeilen von animals.csv
  2. Die letzten beiden Zeilen von animals.csv
  3. Die ersten drei Zeilen und die letzten zwei Zeilen von animals.csv
  4. Die zweite und dritte Zeile von animals.csv

Option 3 ist richtig. Damit Option 1 richtig ist, würden wir nur den Befehl head ausführen. Damit Option 2 richtig ist, würden wir nur den Befehl tail ausführen. Damit Option 4 richtig ist, müssen wir die Ausgabe von head in tail -n 2 leiten, indem wir head -n 3 animals.csv | tail -n 2 > animals-subset.csv ausführen

Übergabe der Ausgabe an einen anderen Befehl


In unserem Beispiel, in dem es darum geht, die Datei mit den wenigsten Zeilen zu finden, verwenden wir zwei Zwischendateien lengths.txt und sorted-lengths.txt, um die Ausgabe zu speichern. Das ist eine verwirrende Arbeitsweise, denn selbst wenn man einmal verstanden hat, was wc, sort und head tun, machen es diese Zwischendateien schwer zu verstehen, was vor sich geht. Wir können es einfacher machen, indem wir sort und head zusammen ausführen:

BASH

$ sort -n lengths.txt | head -n 1

AUSGABE

  9  methane.pdb

Der vertikale Balken, |, zwischen den beiden Befehlen wird pipe genannt. Er sagt der Shell, dass wir die Ausgabe des Befehls auf der linken Seite als Eingabe für den Befehl auf der rechten Seite verwenden wollen.

Dadurch ist die Datei sorted-lengths.txt überflüssig geworden.

Kombinieren mehrerer Befehle


Nichts hindert uns daran, Pipes hintereinander zu schalten. Wir können zum Beispiel die Ausgabe von wc direkt an sort schicken, und dann die resultierende Ausgabe an head. Dies macht Zwischendateien überflüssig.

Wir beginnen damit, eine Pipe zu benutzen, um die Ausgabe von wc nach sort zu schicken:

BASH

$ wc -l *.pdb | sort -n

AUSGABE

   9 methane.pdb
  12 ethane.pdb
  15 propane.pdb
  20 cubane.pdb
  21 pentane.pdb
  30 octane.pdb
 107 total

Wir können diese Ausgabe dann durch eine weitere Pipe an head schicken, so dass die gesamte Pipeline so aussieht:

BASH

$ wc -l *.pdb | sort -n | head -n 1

AUSGABE

   9  methane.pdb

Das ist genau so, als würde ein Mathematiker Funktionen wie log(3x) verschachteln und sagen ‘der Logarithmus von dreimal x’. In unserem Fall lautet der Algorithmus ‘Kopf der Sortierung der Zeilenzahl von *.pdb’.

Die Umleitung und die Pipes, die in den letzten Befehlen verwendet wurden, sind unten dargestellt:

{alt=“Redirects und Pipes von verschiedenen Befehlen:”wc -l *.pdb” leitet die Ausgabe an die Shell weiter. “wc -l *.pdb > lengths” leitet die Ausgabe in die Datei “lengths”. “wc -l *.pdb | sort -n | head -n 1” erstellt eine Pipeline, bei der die Ausgabe des “wc”-Befehls die Eingabe für den “sort”-Befehl ist, die Ausgabe des “sort”-Befehls die Eingabe für den “head”-Befehl ist und die Ausgabe des “head”-Befehls an die Shell geleitet wird”}

Aufgabe

Piping-Befehle zusammen

In unserem aktuellen Verzeichnis wollen wir die 3 Dateien mit der geringsten Anzahl von Zeilen finden. Welcher der unten aufgeführten Befehle würde funktionieren?

  1. wc -l * > sort -n > head -n 3
  2. wc -l * | sort -n | head -n 1-3
  3. wc -l * | head -n 3 | sort -n
  4. wc -l * | sort -n | head -n 3

Option 4 ist die Lösung. Das Pipe-Zeichen | wird verwendet, um die Ausgabe eines Befehls mit der Eingabe eines anderen zu verbinden.> wird verwendet, um die Standardausgabe in eine Datei umzuleiten. Probieren Sie es im Verzeichnis shell-lesson-data/exercise-data/alkanes aus!

Werkzeuge, die zusammenarbeiten sollen


Diese Idee der Verknüpfung von Programmen ist der Grund, warum Unix so erfolgreich ist. Anstatt riesige Programme zu erstellen, die versuchen, viele verschiedene Dinge zu tun, konzentrieren sich die Unix-Programmierer darauf, viele einfache Werkzeuge zu entwickeln, die jeweils eine Aufgabe gut erledigen und gut miteinander arbeiten. Dieses Programmiermodell wird “Pipes und Filter” genannt. Wir haben bereits Pipes gesehen; ein Filter ist ein Programm wie wc oder sort, das einen Eingabestrom in einen Ausgabestrom umwandelt. Fast alle Unix-Standardwerkzeuge können auf diese Weise arbeiten. Wenn sie nicht anders angewiesen werden, lesen sie von der Standardeingabe, machen etwas mit dem, was sie gelesen haben, und schreiben auf die Standardausgabe.

Der Schlüssel ist, dass jedes Programm, das Textzeilen von der Standardeingabe liest und Textzeilen in die Standardausgabe schreibt, mit jedem anderen Programm kombiniert werden kann, das sich ebenfalls so verhält. Sie können und sollten Ihre Programme auf diese Weise schreiben, damit Sie und andere Leute diese Programme in Pipes einbinden können, um ihre Leistung zu vervielfachen.

Aufgabe

Pipe Verständnisabfrage

Eine Datei namens animals.csv (im Ordner shell-lesson-data/exercise-data/animal-counts) enthält die folgenden Daten:

2012-11-05,deer,5
2012-11-05,rabbit,22
2012-11-05,raccoon,7
2012-11-06,rabbit,19
2012-11-06,deer,2
2012-11-06,fox,4
2012-11-07,rabbit,16
2012-11-07,bear,1

Welcher Text durchläuft jede der Pipes und die endgültige Umleitung in der folgenden Pipeline? Beachten Sie, dass der Befehl sort -r in umgekehrter Reihenfolge sortiert.

BASH

$ cat animals.csv | head -n 5 | tail -n 3 | sort -r > final.txt

Tipp: Bauen Sie die Pipeline nach und nach auf, um Ihr Verständnis zu testen

Der Befehl head extrahiert die ersten 5 Zeilen aus animals.csv. Dann werden die letzten 3 Zeilen mit dem Befehl tail aus den vorherigen 5 Zeilen extrahiert. Mit dem Befehl sort -r werden diese 3 Zeilen in umgekehrter Reihenfolge sortiert. Schließlich wird die Ausgabe in eine Datei umgeleitet: ,final.txt. Der Inhalt dieser Datei kann durch Ausführen von cat final.txt überprüft werden. Die Datei sollte die folgenden Zeilen enthalten:

2012-11-06,rabbit,19
2012-11-06,deer,2
2012-11-05,raccoon,7
Aufgabe

Pipe-Konstruktion

Betrachten Sie für die Datei animals.csv aus der vorherigen Übung den folgenden Befehl:

BASH

$ cut -d , -f 2 animals.csv

Der Befehl cut wird verwendet, um bestimmte Abschnitte jeder Zeile in der Datei zu entfernen oder “auszuschneiden”, und cut erwartet, dass die Zeilen durch ein Tab-Zeichen in Spalten getrennt sind. Ein Zeichen, das auf diese Weise verwendet wird, nennt man ein Begrenzungszeichen. Im obigen Beispiel verwenden wir die Option -d, um das Komma als Begrenzungszeichen anzugeben. Wir haben auch die Option -f verwendet, um anzugeben, dass wir das zweite Feld (Spalte) extrahieren wollen. Dies ergibt die folgende Ausgabe:

AUSGABE

deer
rabbit
raccoon
rabbit
deer
fox
rabbit
bear

Der Befehl uniq filtert benachbarte übereinstimmende Zeilen in einer Datei heraus. Wie könnten Sie diese Pipeline (mit uniq und einem anderen Befehl) erweitern, um herauszufinden, welche Tiere die Datei enthält (ohne Duplikate in ihren Namen)?

BASH

$ cut -d , -f 2 animals.csv | sort | uniq
Aufgabe

Welche Pipe?

Die Datei animals.csv enthält 8 Zeilen mit Daten, die wie folgt formatiert sind:

AUSGABE

2012-11-05,deer,5
2012-11-05,rabbit,22
2012-11-05,raccoon,7
2012-11-06,rabbit,19
...

Der uniq-Befehl hat eine -c-Option, die die Anzahl der Vorkommen einer Zeile in der Eingabe angibt. Angenommen, Ihr aktuelles Verzeichnis ist shell-lesson-data/exercise-data/animal-counts. Welchen Befehl würden Sie verwenden, um eine Tabelle zu erstellen, die die Gesamtzahl der einzelnen Tierarten in der Datei anzeigt?

  1. sort animals.csv | uniq -c
  2. sort -t, -k2,2 animals.csv | uniq -c
  3. cut -d, -f 2 animals.csv | uniq -c
  4. cut -d, -f 2 animals.csv | sort | uniq -c
  5. cut -d, -f 2 animals.csv | sort | uniq -c | wc -l

Option 4. ist die richtige Antwort. Wenn Sie Schwierigkeiten haben zu verstehen, warum, versuchen Sie die Befehle oder Unterabschnitte der Pipelines auszuführen (stellen Sie sicher, dass Sie sich im Verzeichnis shell-lesson-data/exercise-data/animal-counts befinden).

Nelle’s Pipeline: Prüfen von Dateien


Nelle hat ihre Proben durch die Testmaschinen laufen lassen und 17 Dateien in dem zuvor beschriebenen Verzeichnis north-pacific-gyre erstellt. Zur schnellen Überprüfung tippt Nelle, ausgehend vom Verzeichnis shell-lesson-data, ein:

BASH

$ cd north-pacific-gyre
$ wc -l *.txt

Die Ausgabe besteht aus 18 Zeilen, die wie folgt aussehen:

AUSGABE

300 NENE01729A.txt
300 NENE01729B.txt
300 NENE01736A.txt
300 NENE01751A.txt
300 NENE01751B.txt
300 NENE01812A.txt
... ...

Jetzt tippt sie dies:

BASH

$ wc -l *.txt | sort -n | head -n 5

AUSGABE

 240 NENE02018B.txt
 300 NENE01729A.txt
 300 NENE01729B.txt
 300 NENE01736A.txt
 300 NENE01751A.txt

Hoppla: eine der Dateien ist 60 Zeilen kürzer als die anderen. Als sie zurückgeht und nachsieht, stellt sie fest, dass sie den Test um 8 Uhr an einem Montagmorgen durchgeführt hat - wahrscheinlich hat jemand den Rechner am Wochenende benutzt und sie hat vergessen, ihn zurückzusetzen. Bevor sie die Probe erneut durchführt, prüft sie, ob irgendwelche Dateien zu viele Daten haben:

BASH

$ wc -l *.txt | sort -n | tail -n 5

AUSGABE

 300 NENE02040B.txt
 300 NENE02040Z.txt
 300 NENE02043A.txt
 300 NENE02043B.txt
5040 total

Diese Zahlen sehen gut aus — aber was macht das ‘Z’ dort in der drittletzten Zeile? Alle ihre Proben sollten mit “A” oder “B” gekennzeichnet sein; ihr Labor verwendet vereinbarungsgemäß “Z”, um Proben mit fehlenden Informationen zu kennzeichnen. Um andere Proben dieser Art zu finden, geht sie folgendermaßen vor:

BASH

$ ls *Z.txt

AUSGABE

NENE01971Z.txt    NENE02040Z.txt

Als sie das Protokoll auf ihrem Laptop überprüft, ist für keine der beiden Proben eine Tiefe aufgezeichnet. Da es zu spät ist, die Informationen auf andere Weise zu erhalten, muss sie diese beiden Dateien von ihrer Analyse ausschließen. Sie könnte sie mit rm löschen, aber es gibt tatsächlich einige Analysen, die sie später durchführen könnte, bei denen die Tiefe keine Rolle spielt. Stattdessen muss sie später darauf achten, Dateien mit den Platzhalterausdrücken NENE*A.txt NENE*B.txt auszuwählen.

Aufgabe

Unnötige Dateien entfernen

Angenommen, Sie möchten Ihre verarbeiteten Datendateien löschen und nur Ihre Rohdateien und das Verarbeitungsskript behalten, um Speicherplatz zu sparen. Die Rohdateien enden auf .dat und die verarbeiteten Dateien auf .txt. Welche der folgenden Möglichkeiten würde alle verarbeiteten Datendateien und nur die verarbeiteten Datendateien löschen?

  1. rm ?.txt
  2. rm *.txt
  3. rm * .txt
  4. rm *.*
  1. Dies würde .txt Dateien mit einstelligen Namen entfernen
  2. Dies ist die richtige Antwort
  3. Die Shell würde * so erweitern, dass es auf alles im aktuellen Verzeichnis passt, also würde der Befehl versuchen, alle passenden Dateien und eine zusätzliche Datei namens .txt zu entfernen
  4. Die Shell expandiert *.*, um alle Dateinamen zu finden, die mindestens ein . enthalten, einschließlich der verarbeiteten Dateien (.txt) und der Rohdateien (.dat)
Hauptpunkte
  • wc zählt Zeilen, Wörter und Zeichen in ihren Eingaben.
  • cat zeigt den Inhalt ihrer Eingänge an.
  • sort sortiert ihre Eingaben.
  • head zeigt die ersten 10 Zeilen seiner Eingabe standardmäßig ohne zusätzliche Argumente an.
  • tail zeigt die letzten 10 Zeilen seiner Eingabe standardmäßig ohne zusätzliche Argumente an.
  • command > [file] leitet die Ausgabe eines Befehls in eine Datei um (und überschreibt dabei den vorhandenen Inhalt).
  • command >> [file] hängt die Ausgabe eines Befehls an eine Datei an.
  • [first] | [second] ist eine Pipeline: die Ausgabe des ersten Befehls wird als Eingabe für den zweiten verwendet.
  • Die beste Art, die Shell zu benutzen, ist, Pipes zu benutzen, um einfache Einzweckprogramme (Filter) zu kombinieren.

Content from Schleifen


Zuletzt aktualisiert am 2025-10-23 | Diese Seite bearbeiten

Geschätzte Zeit: 50 Minuten

Übersicht

Fragen

  • Wie kann ich die gleichen Aktionen für viele verschiedene Dateien durchführen?

Ziele

  • Schreiben Sie eine Schleife, die einen oder mehrere Befehle separat auf jede Datei in einer Gruppe von Dateien anwendet.
  • Verfolgen Sie die Werte, die eine Schleifenvariable während der Ausführung der Schleife annimmt.
  • Erkläre den Unterschied zwischen dem Namen einer Variablen und ihrem Wert.
  • Erkläre, warum Leerzeichen und einige Satzzeichen nicht in Dateinamen verwendet werden sollten.
  • Demonstrieren Sie, wie Sie sehen können, welche Befehle kürzlich ausgeführt worden sind.
  • Wiederholung kürzlich ausgeführter Befehle, ohne sie neu zu tippen.

Schleifen sind ein Programmierkonstrukt, das es uns ermöglicht, einen Befehl oder eine Reihe von Befehlen für jedes Element in einer Liste zu wiederholen. Als solche sind sie der Schlüssel zur Produktivitätssteigerung durch Automatisierung. Ähnlich wie bei Platzhaltern und der Tabulatorvervollständigung reduziert die Verwendung von Schleifen auch die Anzahl der erforderlichen Eingaben (und damit die Anzahl der Tippfehler).

Angenommen, wir haben mehrere hundert Genomdateien mit den Namen basilisk.dat, minotaur.dat und unicorn.dat. Für dieses Beispiel verwenden wir das Verzeichnis exercise-data/creatures, das nur drei Beispieldateien enthält, aber die Prinzipien können auf viele weitere Dateien gleichzeitig angewendet werden.

Die Struktur dieser Dateien ist die gleiche: der gemeinsame Name, die Klassifizierung und das Aktualisierungsdatum werden in den ersten drei Zeilen angegeben, die DNA-Sequenzen in den folgenden Zeilen. Schauen wir uns die Dateien an:

BASH

$ head -n 5 basilisk.dat minotaur.dat unicorn.dat

Wir möchten die Klassifizierung für jede Art ausgeben, die in der zweiten Zeile jeder Datei angegeben ist. Für jede Datei müssten wir den Befehl head -n 2 ausführen und diesen an tail -n 1 weiterleiten. Wir werden eine Schleife verwenden, um dieses Problem zu lösen, aber sehen wir uns zunächst die allgemeine Form einer Schleife an, indem wir den folgenden Pseudocode verwenden:

BASH

# Das Wort „for“ kennzeichnet den Beginn eines „For-Schleifen“-Befehls.
for thing in list_of_things 
# Das Wort „do“ kennzeichnet den Beginn der Jobausführungsliste.
do 
    # Einrückungen innerhalb der Schleife sind nicht erforderlich, verbessern jedoch die Lesbarkeit.
    operation oder command welches $thing verwendet
# Das Wort „done“ kennzeichnet das Ende einer Schleife.
done  

und wir können dies auf unser Beispiel wie folgt anwenden:

BASH

$ for filename in basilisk.dat minotaur.dat unicorn.dat
> do
>     echo $filename
>     head -n 2 $filename | tail -n 1
> done

AUSGABE

basilisk.dat
CLASSIFICATION: basiliscus vulgaris
minotaur.dat
CLASSIFICATION: bos hominus
unicorn.dat
CLASSIFICATION: equus monoceros
Wichtig

Folgen Sie der Eingabeaufforderung

Der Shell-Prompt wechselt von $ zu > und wieder zurück, während wir in unserer Schleife tippen. Der zweite Prompt, >, ist anders, um uns daran zu erinnern, dass wir noch nicht mit der Eingabe eines kompletten Befehls fertig sind. Ein Semikolon, ;, kann verwendet werden, um zwei Befehle zu trennen, die in einer einzigen Zeile stehen.

Wenn die Shell das Schlüsselwort for sieht, weiß sie, dass sie einen Befehl (oder eine Gruppe von Befehlen) für jedes Element in einer Liste einmal wiederholen muss. Jedes Mal, wenn die Schleife läuft (Iteration genannt), wird ein Eintrag in der Liste der Reihe nach der Variablen zugewiesen, und die Befehle innerhalb der Schleife werden ausgeführt, bevor zum nächsten Eintrag in der Liste übergegangen wird. Innerhalb der Schleife fragen wir den Wert der Variable ab, indem wir ihr $ voranstellen. Das $ weist den Shell-Interpreter an, die Variable als Variablennamen zu behandeln und ihren Wert an ihrer Stelle zu ersetzen, anstatt sie als Text oder externen Befehl zu behandeln.

In diesem Beispiel besteht die Liste aus drei Dateinamen: basilisk.dat, minotaur.dat, und unicorn.dat. Jedes Mal, wenn die Schleife durchläuft, verwenden wir zunächst echo, um den Wert auszugeben, den die Variable $filename gerade hat. Dies ist für das Ergebnis nicht notwendig, aber für uns hier von Vorteil, um leichter folgen zu können. Als Nächstes führen wir den Befehl head in der Datei aus, auf die $filename gerade verweist. Beim ersten Durchlauf der Schleife ist $filename basilisk.dat. Der Interpreter führt den Befehl head auf basilisk.dat aus und leitet die ersten beiden Zeilen an den Befehl tail weiter, der dann die zweite Zeile von basilisk.dat ausgibt. Bei der zweiten Iteration wird $filename zu minotaur.dat. Dieses Mal lässt die Shell head auf minotaur.dat laufen und leitet die ersten beiden Zeilen an den Befehl tail weiter, der dann die zweite Zeile von minotaur.dat ausgibt. Bei der dritten Iteration wird $filename zu unicorn.dat, also führt die Shell den Befehl head auf dieser Datei aus, und tail auf der Ausgabe davon. Da die Liste nur drei Einträge enthielt, verlässt die Shell die for-Schleife.

Wichtig

Gleiche Symbole, unterschiedliche Bedeutungen

Hier sehen wir, dass > als Shell-Prompt verwendet wird, während > auch zur Umleitung der Ausgabe verwendet wird. In ähnlicher Weise wird $ als Shell-Prompt benutzt, aber, wie wir zuvor gesehen haben, wird es auch benutzt, um die Shell zu bitten, den Wert einer Variablen zu erhalten.

Wenn die Shell > oder $ ausgibt, erwartet sie, dass Sie etwas eingeben, und das Symbol ist ein Prompt.

Wenn Sie selbst > oder $ eintippen, ist das eine Anweisung von Ihnen, dass die Shell die Ausgabe umleiten oder den Wert einer Variablen holen soll.

Bei der Verwendung von Variablen ist es auch möglich, die Namen in geschweifte Klammern zu setzen, um den Variablennamen klar abzugrenzen: $filename entspricht ${filename}, ist aber anders als ${file}name. Diese Schreibweise finden Sie vielleicht auch in anderen Programmen.

Wir haben die Variable in dieser Schleife filename genannt, um ihren Zweck für den menschlichen Leser zu verdeutlichen. Der Shell selbst ist es egal, wie die Variable genannt wird; wenn wir diese Schleife so schreiben würden:

BASH

$ for x in basilisk.dat minotaur.dat unicorn.dat
> do
>     head -n 2 $x | tail -n 1
> done

oder:

BASH

$ for temperature in basilisk.dat minotaur.dat unicorn.dat
> do
>     head -n 2 $temperature | tail -n 1
> done

Es würde genau so funktionieren. Tun Sie das nicht. Programme sind nur dann nützlich, wenn die Leute sie verstehen können, daher erhöhen bedeutungslose Namen (wie x) oder irreführende Namen (wie temperature) die Wahrscheinlichkeit, dass das Programm nicht das tut, was seine Leser denken, dass es tut.

In den obigen Beispielen hätte man den Variablen (thing, filename, x und temperature) jeden anderen Namen geben können, solange er sowohl für die Person, die den Code schreibt, als auch für die Person, die ihn liest, sinnvoll ist.

Beachten Sie auch, dass Schleifen für andere Dinge als Dateinamen verwendet werden können, wie z.B. eine Liste von Zahlen oder eine Teilmenge von Daten.

Aufgabe

Schreiben Sie Ihre eigene Schleife

Wie würden Sie eine Schleife schreiben, die alle 10 Zahlen von 0 bis 9 als Echo ausgibt?

BASH

$ for loop_variable in 0 1 2 3 4 5 6 7 8 9
> do
>     echo $loop_variable
> done

AUSGABE

0
1
2
3
4
5
6
7
8
9
Aufgabe

Variablen in Schleifen

Diese Übung bezieht sich auf das Verzeichnis shell-lesson-data/exercise-data/alkanes. ls *.pdb gibt die folgende Ausgabe:

AUSGABE

cubane.pdb  ethane.pdb  methane.pdb  octane.pdb  pentane.pdb  propane.pdb

Was ist die Ausgabe des folgenden Codes?

BASH

$ for datafile in *.pdb
> do
>     ls *.pdb
> done

Wie lautet nun die Ausgabe des folgenden Codes?

BASH

$ for datafile in *.pdb
> do
>     ls $datafile
> done

Warum geben diese beiden Schleifen unterschiedliche Ergebnisse aus?

Der erste Codeblock gibt bei jeder Iteration der Schleife die gleiche Ausgabe. Bash erweitert den Platzhalter *.pdb innerhalb des Schleifenkörpers (sowie vor dem Start der Schleife), um alle Dateien zu finden, die auf .pdb enden, und listet sie dann mit ls auf. Die erweiterte Schleife würde wie folgt aussehen:

BASH

$ for datafile in cubane.pdb  ethane.pdb  methane.pdb  octane.pdb  pentane.pdb  propane.pdb
> do
>     ls cubane.pdb  ethane.pdb  methane.pdb  octane.pdb  pentane.pdb  propane.pdb
> done

AUSGABE

cubane.pdb  ethane.pdb  methane.pdb  octane.pdb  pentane.pdb  propane.pdb
cubane.pdb  ethane.pdb  methane.pdb  octane.pdb  pentane.pdb  propane.pdb
cubane.pdb  ethane.pdb  methane.pdb  octane.pdb  pentane.pdb  propane.pdb
cubane.pdb  ethane.pdb  methane.pdb  octane.pdb  pentane.pdb  propane.pdb
cubane.pdb  ethane.pdb  methane.pdb  octane.pdb  pentane.pdb  propane.pdb
cubane.pdb  ethane.pdb  methane.pdb  octane.pdb  pentane.pdb  propane.pdb

Der zweite Codeblock listet bei jeder Schleifeniteration eine andere Datei auf. Der Wert der Variable datafile wird mit $datafile ausgewertet und dann mit ls aufgelistet.

AUSGABE

cubane.pdb
ethane.pdb
methane.pdb
octane.pdb
pentane.pdb
propane.pdb
Aufgabe

Begrenzung von Dateimengen

Was wäre die Ausgabe, wenn die folgende Schleife im Verzeichnis shell-lesson-data/exercise-data/alkanes ausgeführt würde?

BASH

$ for filename in c*
> do
>     ls $filename
> done
  1. Es sind keine Dateien aufgelistet.
  2. Alle Dateien sind aufgelistet.
  3. Nur cubane.pdb, octane.pdb und pentane.pdb sind aufgeführt.
  4. Nur cubane.pdb ist aufgeführt.

4 ist die richtige Antwort.* passt auf null oder mehr Zeichen, so dass jeder Dateiname, der mit dem Buchstaben c beginnt, gefolgt von null oder mehr anderen Zeichen, gefunden wird.

Aufgabe

Begrenzung von Dateimengen (continued)

Wie würde sich die Ausgabe unterscheiden, wenn stattdessen dieser Befehl verwendet würde?

BASH

$ for filename in *c*
> do
>     ls $filename
> done
  1. Die gleichen Dateien würden aufgelistet werden.
  2. Diesmal werden alle Dateien aufgelistet.
  3. Diesmal werden keine Dateien aufgelistet.
  4. Die Dateien cubane.pdb und octane.pdb werden aufgelistet.
  5. Es wird nur die Datei octane.pdb aufgelistet.

4 ist die richtige Antwort.* passt auf null oder mehr Zeichen, also wird ein Dateiname mit null oder mehr Zeichen vor dem Buchstaben c und null oder mehr Zeichen nach dem Buchstaben c gefunden.

Aufgabe

Speichern in einer Datei in einer Schleife - Teil eins

Was ist die Auswirkung dieser Schleife im Verzeichnis shell-lesson-data/exercise-data/alkanes?

BASH

for alkanes in *.pdb
do
    echo $alkanes
    cat $alkanes > alkanes.pdb
done
  1. Druckt cubane.pdb, ethane.pdb, methane.pdb, octane.pdb, pentane.pdb und propane.pdb, und der Text von propane.pdb wird in einer Datei namens alkanes.pdb gespeichert.
  2. Druckt cubane.pdb, ethane.pdb und methane.pdb, und der Text aus allen drei Dateien wird zusammengefügt und in einer Datei namens alkanes.pdb gespeichert.
  3. Druckt cubane.pdb, ethane.pdb, methane.pdb, octane.pdb, und pentane.pdb, und der Text von propane.pdb wird in einer Datei namens alkanes.pdb gespeichert.
  4. Keine der oben genannten.
  1. Der Text aus jeder Datei wird der Reihe nach in die Datei alkanes.pdb geschrieben. Allerdings wird die Datei bei jedem Schleifendurchlauf überschrieben, so dass der endgültige Inhalt von alkanes.pdb der Text aus der Datei propane.pdb ist.
Aufgabe

Speichern in einer Datei in einer Schleife - Teil Zwei

Was wäre die Ausgabe der folgenden Schleife, ebenfalls im Verzeichnis shell-lesson-data/exercise-data/alkanes?

BASH

for datafile in *.pdb
do
    cat $datafile >> all.pdb
done
  1. Der gesamte Text von cubane.pdb, ethane.pdb, methane.pdb, octane.pdb und pentane.pdb würde verkettet und in einer Datei namens all.pdb gespeichert.
  2. Der Text von ethane.pdb wird in einer Datei namens all.pdb gespeichert.
  3. Der gesamte Text von cubane.pdb, ethane.pdb, methane.pdb, octane.pdb, pentane.pdb und propane.pdb würde konkateniert und in einer Datei namens all.pdb gespeichert.
  4. Der gesamte Text von cubane.pdb, ethane.pdb, methane.pdb, octane.pdb, pentane.pdb und propane.pdb würde auf dem Bildschirm ausgegeben und in einer Datei namens all.pdb gespeichert.

3 ist die richtige Antwort. >> hängt an eine Datei an, anstatt sie mit der umgeleiteten Ausgabe eines Befehls zu überschreiben. Da die Ausgabe des Befehls cat umgeleitet wurde, wird nichts auf dem Bildschirm ausgegeben.

Lassen Sie uns mit unserem Beispiel im Verzeichnis shell-lesson-data/exercise-data/creatures fortfahren. Hier ist eine etwas kompliziertere Schleife:

BASH

$ for filename in *.dat
> do
>     echo $filename
>     head -n 100 $filename | tail -n 20
> done

Die Shell beginnt mit der Expansion von *.dat, um die Liste der zu verarbeitenden Dateien zu erstellen. Der Schleifenkörper führt dann zwei Befehle für jede dieser Dateien aus. Der erste Befehl, echo, gibt seine Befehlszeilenargumente auf der Standardausgabe aus. Zum Beispiel:

BASH

$ echo hello there

druckt:

AUSGABE

hello there

Da die Shell in diesem Fall $filename als Name einer Datei expandiert, gibt echo $filename den Namen der Datei aus. Beachten Sie, dass wir dies nicht so schreiben können:

BASH

$ for filename in *.dat
> do
>     $filename
>     head -n 100 $filename | tail -n 20
> done

weil dann beim ersten Durchlauf der Schleife, wenn $filename zu basilisk.dat expandiert, die Shell versuchen würde, basilisk.dat als Programm auszuführen. Schließlich wählt die Kombination head und tail die Zeilen 81-100 aus der zu verarbeitenden Datei aus (vorausgesetzt, die Datei hat mindestens 100 Zeilen).

Wichtig

Leerzeichen in Namen

Leerzeichen werden verwendet, um die Elemente der Liste zu trennen, über die wir eine Schleife laufen lassen wollen. Wenn eines dieser Elemente ein Leerzeichen enthält, müssen wir es mit Anführungszeichen umgeben und dasselbe mit unserer Schleifenvariablen tun. Angenommen, unsere Datendateien sind benannt:

red dragon.dat
purple unicorn.dat

Um eine Schleife über diese Dateien zu ziehen, müssten wir doppelte Anführungszeichen wie folgt hinzufügen:

BASH

$ for filename in "red dragon.dat" "purple unicorn.dat"
> do
>     head -n 100 "$filename" | tail -n 20
> done

Es ist einfacher, Leerzeichen (oder andere Sonderzeichen) in Dateinamen zu vermeiden.

Die obigen Dateien existieren nicht, wenn wir also den obigen Code ausführen, kann der Befehl head sie nicht finden; die zurückgegebene Fehlermeldung zeigt jedoch den Namen der erwarteten Dateien an:

FEHLER

head: cannot open ‘red dragon.dat' for reading: No such file or directory
head: cannot open ‘purple unicorn.dat' for reading: No such file or directory

Versuchen Sie, die Anführungszeichen um $filename in der obigen Schleife zu entfernen, um den Effekt der Anführungszeichen auf Leerzeichen zu sehen. Beachten Sie, dass wir ein Ergebnis des Schleifenbefehls für unicorn.dat erhalten, wenn wir diesen Code im Verzeichnis creatures ausführen:

AUSGABE

head: cannot open ‘red' for reading: No such file or directory
head: cannot open ‘dragon.dat' for reading: No such file or directory
head: cannot open ‘purple' for reading: No such file or directory
CGGTACCGAA
AAGGGTCGCG
CAAGTGTTCC
...

Wir möchten jede der Dateien in shell-lesson-data/exercise-data/creatures ändern, aber auch eine Version der Originaldateien speichern. Wir wollen die Originaldateien in neue Dateien mit den Namen original-basilisk.dat und original-unicorn.dat kopieren. Wir können nicht verwenden:

BASH

$ cp *.dat original-*.dat

aus, denn das würde expandieren zu:

BASH

$ cp basilisk.dat minotaur.dat unicorn.dat original-*.dat

Dies würde unsere Dateien nicht sichern, stattdessen bekommen wir einen Fehler:

FEHLER

cp: target `original-*.dat' is not a directory

Dieses Problem tritt auf, wenn cp mehr als zwei Eingaben erhält. Wenn das passiert, erwartet es, dass die letzte Eingabe ein Verzeichnis ist, in das es alle Dateien kopieren kann, die ihm übergeben wurden. Da es im Verzeichnis creatures kein Verzeichnis namens original-*.dat gibt, erhalten wir einen Fehler.

Stattdessen können wir eine Schleife verwenden:

BASH

$ for filename in *.dat
> do
>     cp $filename original-$filename
> done

Diese Schleife führt den Befehl cp einmal für jeden Dateinamen aus. Beim ersten Mal, wenn sich $filename zu basilisk.dat ausdehnt, führt die Shell ihn aus:

BASH

cp basilisk.dat original-basilisk.dat

Das zweite Mal lautet der Befehl:

BASH

cp minotaur.dat original-minotaur.dat

Das dritte und letzte Mal lautet der Befehl:

BASH

cp unicorn.dat original-unicorn.dat

Da der Befehl cp normalerweise keine Ausgabe erzeugt, ist es schwer zu überprüfen, ob die Schleife korrekt funktioniert. Wir haben jedoch bereits gelernt, wie man Zeichenketten mit echo ausgibt, und wir können die Schleife so modifizieren, dass sie echo verwendet, um unsere Befehle auszugeben, ohne sie tatsächlich auszuführen. So können wir prüfen, welche Befehle in der unveränderten Schleife ausgeführt werden würden.

Das folgende Diagramm zeigt, was passiert, wenn die geänderte Schleife ausgeführt wird, und demonstriert, dass die vernünftige Verwendung von echo eine gute Debugging-Technik ist.

{alt=“Die for-Schleife”for filename in .dat; do echo cp \(filename original-\)filename;done” weist der Variablen “$filename” nacheinander die Namen aller “.dat”-Dateien in Ihrem aktuellen Verzeichnis zu und führt dann den Befehl aus. Mit den Dateien “basilisk.dat”, “minotaur.dat” und “unicorn.dat” im aktuellen Verzeichnis wird die Schleife nacheinander dreimal den Befehl echo aufrufen und drei Zeilen ausgeben: “cp basislisk.dat original-basilisk.dat”, dann “cp minotaur.datoriginal-minotaur.dat” und schließlich “cp unicorn.datoriginal-unicorn.dat”“}

Nelle’s Pipeline: Verarbeitung von Dateien


Nelle ist nun bereit, ihre Datendateien mit Hilfe von goostats.sh — einem von ihrem Betreuer geschriebenen Shell-Skript zu verarbeiten. Dieses Skript berechnet einige Statistiken aus einer Protein-Probendatei und nimmt zwei Argumente entgegen:

  1. eine Eingabedatei (die die Rohdaten enthält)
  2. eine Ausgabedatei (um die berechneten Statistiken zu speichern)

Da sie immer noch lernt, wie man die Shell benutzt, beschließt sie, die benötigten Befehle schrittweise aufzubauen. Ihr erster Schritt ist es, sicherzustellen, dass sie die richtigen Eingabedateien auswählen kann — erinnern Sie sich, das sind diejenigen, deren Namen auf ‘A’ oder ‘B’ enden, und nicht auf ‘Z’. Nelle wechselt in das Verzeichnis north-pacific-gyre und tippt:

BASH

$ cd
$ cd Desktop/shell-lesson-data/north-pacific-gyre
$ for datafile in NENE*A.txt NENE*B.txt
> do
>     echo $datafile
> done

AUSGABE

NENE01729A.txt
NENE01736A.txt
NENE01751A.txt

...
NENE02040B.txt
NENE02043B.txt

Ihr nächster Schritt besteht darin, zu entscheiden, wie die Dateien heißen sollen, die das Analyseprogramm goostats.sh erstellen wird. Es scheint einfach zu sein, den Namen jeder Eingabedatei mit “stats” voranzustellen, also modifiziert sie ihre Schleife, um dies zu tun:

BASH

$ for datafile in NENE*A.txt NENE*B.txt
> do
>     echo $datafile stats-$datafile
> done

AUSGABE

NENE01729A.txt stats-NENE01729A.txt
NENE01736A.txt stats-NENE01729A.txt
NENE01751A.txt stats-NENE01729A.txt
...
NENE02040B.txt stats-NENE02040B.txt
NENE02043B.txt stats-NENE02043B.txt

Sie hat goostats.sh noch nicht wirklich ausgeführt, aber jetzt ist sie sicher, dass sie die richtigen Dateien auswählen und die richtigen Ausgabedateinamen erzeugen kann.

Das wiederholte Eingeben von Befehlen wird jedoch mühsam, und Nelle hat Angst, Fehler zu machen, also drückt sie, anstatt ihre Schleife erneut einzugeben, . Daraufhin gibt die Shell die gesamte Schleife in einer Zeile wieder (mit Semikolons zur Trennung der Teile):

BASH

$ for datafile in NENE*A.txt NENE*B.txt; do echo $datafile stats-$datafile; done

Mit Hilfe des navigiert Nelle zu dem Befehl echo und ändert ihn in bash goostats.sh:

BASH

$ for datafile in NENE*A.txt NENE*B.txt; do bash goostats.sh $datafile stats-$datafile; done

Wenn sie Enter drückt, führt die Shell den geänderten Befehl aus. Es scheint jedoch nichts zu passieren - es gibt keine Ausgabe. Nach einem Moment wird Nelle klar, dass sie, da ihr Skript nichts mehr auf dem Bildschirm ausgibt, keine Ahnung hat, ob es läuft, geschweige denn wie schnell. Sie beendet den laufenden Befehl, indem sie Strg+C eintippt, verwendet , um den Befehl zu wiederholen, und ändert ihn so ab, dass er lautet:

BASH

$ for datafile in NENE*A.txt NENE*B.txt; do echo $datafile;
bash goostats.sh $datafile stats-$datafile; done
Wichtig

Anfang und Ende

Wir können an den Anfang einer Zeile in der Shell gehen, indem wir Strg+A eingeben und an das Ende mit Strg+E.

Wenn sie ihr Programm jetzt ausführt, produziert es alle fünf Sekunden oder so eine Zeile an Ausgabe:

AUSGABE

NENE01729A.txt
NENE01736A.txt
NENE01751A.txt
...

1518 mal 5 Sekunden, geteilt durch 60, sagt ihr, dass ihr Skript etwa zwei Stunden für die Ausführung brauchen wird. Als letzte Kontrolle öffnet sie ein weiteres Terminalfenster, geht in north-pacific-gyre und benutzt cat stats-NENE01729B.txt, um eine der Ausgabedateien zu untersuchen. Es sieht gut aus, also beschließt sie, sich einen Kaffee zu holen und ihre Lektüre fortzusetzen.

Wichtig

Diejenigen, die die “Geschichte” kennen, können wählen, sie zu wiederholen

Eine andere Möglichkeit, frühere Arbeiten zu wiederholen, ist die Verwendung des Befehls history, um eine Liste der letzten paar hundert Befehle zu erhalten, die ausgeführt wurden, und dann !123 (wobei ‘123’ durch die Befehlsnummer ersetzt wird) zu verwenden, um einen dieser Befehle zu wiederholen. Wenn Nelle zum Beispiel dies tippt:

BASH

$ history | tail -n 5

AUSGABE

456  for datafile in NENE*A.txt NENE*B.txt; do   echo $datafile stats-$datafile; done
457  for datafile in NENE*A.txt NENE*B.txt; do echo $datafile stats-$datafile; done
458  for datafile in NENE*A.txt NENE*B.txt; do bash goostats.sh $datafile stats-$datafile; done
459  for datafile in NENE*A.txt NENE*B.txt; do echo $datafile; bash goostats.sh $datafile
stats-$datafile; done
460  history | tail -n 5

dann kann sie goostats.sh auf den Dateien erneut ausführen, indem sie einfach !459 eingibt.

Wichtig

Andere History-Befehle

Es gibt eine Reihe anderer Kurzbefehle, um auf die Historie zuzugreifen.

  • Strg+R schaltet in den History-Suchmodus ‘reverse-i-search’ und findet den letzten Befehl in Ihrer History, der mit dem Text übereinstimmt, den Sie als nächstes eingeben. Drücken Sie Strg+R ein oder mehrere Male, um nach früheren Übereinstimmungen zu suchen. Sie können dann mit der linken und rechten Pfeiltaste diese Zeile auswählen und bearbeiten und dann Return drücken, um den Befehl auszuführen.
  • !! ruft den unmittelbar vorhergehenden Befehl auf (Sie können dies bequemer finden als )
  • !$ holt das letzte Wort des letzten Befehls. Das ist öfter nützlich als man denkt: nach bash goostats.sh NENE01729B.txt stats-NENE01729B.txt kann man less !$ eingeben, um sich die Datei stats-NENE01729B.txt anzusehen, was schneller ist als und die Befehlszeile zu bearbeiten.
Aufgabe

Durchführung eines Trockenlaufs

Eine Schleife ist eine Möglichkeit, viele Dinge auf einmal zu tun — oder viele Fehler auf einmal zu machen, wenn sie das Falsche tut. Eine Möglichkeit zu überprüfen, was eine Schleife tun würde, ist, die Befehle, die sie ausführen würde, zu echo, anstatt sie tatsächlich auszuführen.

Angenommen, wir wollen eine Vorschau auf die Befehle, die die folgende Schleife ausführen wird, ohne diese Befehle tatsächlich auszuführen:

BASH

$ for datafile in *.pdb
> do
>     cat $datafile >> all.pdb
> done

Was ist der Unterschied zwischen den beiden Schleifen unten, und welche würden wir ausführen wollen?

BASH

# Version 1
$ for datafile in *.pdb
> do
>     echo cat $datafile >> all.pdb
> done

BASH

# Version 2
$ for datafile in *.pdb
> do
>     echo "cat $datafile >> all.pdb"
> done

Die zweite Version ist die, die wir ausführen wollen. Sie gibt alles, was in den Anführungszeichen steht, auf dem Bildschirm aus, wobei der Name der Schleifenvariablen erweitert wird, da wir ihm ein Dollarzeichen vorangestellt haben. Sie verändert auch nicht die Datei all.pdb, da >> wörtlich als Teil einer Zeichenkette und nicht als Umleitungsanweisung behandelt wird.

Die erste Version hängt die Ausgabe des Befehls echo cat $datafile an die Datei all.pdb an. Diese Datei enthält nur die Liste; cat cubane.pdb, cat ethane.pdb, cat methane.pdb usw.

Probieren Sie beide Versionen aus, um die Ausgabe zu sehen! Öffnen Sie unbedingt die Datei all.pdb, um ihren Inhalt zu sehen.

Aufgabe

Verschachtelte Schleifen

Angenommen, wir wollen eine Verzeichnisstruktur einrichten, um einige Experimente zur Messung der Reaktionsgeschwindigkeitskonstanten mit verschiedenen Verbindungen und verschiedenen Temperaturen zu organisieren. Was wäre das Ergebnis des folgenden Codes:

BASH

$ for species in cubane ethane methane
> do
>     for temperature in 25 30 37 40
>     do
>         mkdir $species-$temperature
>     done
> done

Wir haben eine geschachtelte Schleife, d.h. innerhalb einer anderen Schleife, so dass für jede Art in der äußeren Schleife die innere Schleife (die geschachtelte Schleife) über die Liste der Temperaturen iteriert und für jede Kombination ein neues Verzeichnis erstellt.

Versuchen Sie, den Code selbst auszuführen, um zu sehen, welche Verzeichnisse erstellt werden!

Hauptpunkte
  • Eine for-Schleife wiederholt die Befehle einmal für jedes Ding in einer Liste.
  • Jede for-Schleife braucht eine Variable, die auf das Ding verweist, mit dem sie gerade arbeitet.
  • Verwenden Sie $name, um eine Variable zu expandieren (d.h. ihren Wert zu erhalten). auch ${name} kann verwendet werden.
  • Verwenden Sie keine Leerzeichen, Anführungszeichen oder Platzhalterzeichen wie ‘*’ oder ‘?’ in Dateinamen, da dies die Variablenexpansion erschwert.
  • Geben Sie den Dateien konsistente Namen, die leicht mit Wildcard-Mustern übereinstimmen, um die Auswahl für die Schleife zu vereinfachen.
  • Benutzen Sie die Pfeil-nach-oben-Taste, um durch die vorherigen Befehle zu blättern und sie zu bearbeiten und zu wiederholen.
  • Verwenden Sie Strg+R, um die zuvor eingegebenen Befehle zu durchsuchen.
  • Verwenden Sie history, um die letzten Befehle anzuzeigen, und ![number], um einen Befehl nach Nummer zu wiederholen.

Content from Shell-Skripte


Zuletzt aktualisiert am 2025-10-23 | Diese Seite bearbeiten

Geschätzte Zeit: 45 Minuten

Übersicht

Fragen

  • Wie kann ich Befehle speichern und wiederverwenden?

Ziele

  • Schreiben Sie ein Shell-Skript, das einen Befehl oder eine Reihe von Befehlen für einen festen Satz von Dateien ausführt.
  • Führen Sie ein Shell-Skript von der Kommandozeile aus.
  • Schreiben Sie ein Shell-Skript, das mit einer Reihe von Dateien arbeitet, die der Benutzer auf der Kommandozeile definiert.
  • Erstellen Sie Pipelines, die Shell-Skripte enthalten, die Sie und andere geschrieben haben.

Jetzt können wir endlich sehen, was die Shell zu einer so mächtigen Programmierumgebung macht. Wir werden die Befehle, die wir häufig wiederholen, in Dateien speichern, so dass wir alle diese Operationen später mit einem einzigen Befehl erneut ausführen können. Aus historischen Gründen wird ein Bündel von Befehlen, die in einer Datei gespeichert sind, gewöhnlich als Shell-Skript bezeichnet, aber täuschen Sie sich nicht — es sind eigentlich kleine Programme.

Durch das Schreiben von Shell-Skripten wird Ihre Arbeit nicht nur schneller, sondern Sie müssen auch nicht die gleichen Befehle immer wieder neu eingeben. Außerdem wird sie dadurch genauer (weniger Tippfehler) und reproduzierbarer. Wenn Sie später auf Ihre Arbeit zurückkommen (oder wenn jemand anderes Ihre Arbeit findet und darauf aufbauen möchte), können Sie die gleichen Ergebnisse reproduzieren, indem Sie einfach Ihr Skript ausführen, anstatt sich eine lange Liste von Befehlen zu merken oder neu einzugeben.

Beginnen wir damit, zu alkanes/ zurückzugehen und eine neue Datei zu erstellen, middle.sh, die unser Shell-Skript werden wird:

BASH

$ cd alkanes
$ nano middle.sh

Der Befehl nano middle.sh öffnet die Datei middle.sh mit dem Texteditor ‘nano’ (der in der Shell läuft). Wenn die Datei nicht existiert, wird sie erstellt. Wir können den Texteditor verwenden, um die Datei direkt zu bearbeiten, indem wir die folgende Zeile einfügen:

head -n 15 octane.pdb | tail -n 5

Dies ist eine Variation der Pipe, die wir zuvor konstruiert haben und die die Zeilen 11-15 der Datei octane.pdb auswählt. Erinnern Sie sich daran, dass wir es noch nicht als Befehl ausführen; wir binden die Befehle nur in eine Datei ein.

Dann speichern wir die Datei (Ctrl-O in nano) und beenden den Texteditor (Ctrl-X in nano). Überprüfen Sie, dass das Verzeichnis alkanes nun eine Datei namens middle.sh enthält.

Nachdem wir die Datei gespeichert haben, können wir die Shell bitten, die darin enthaltenen Befehle auszuführen. Unsere Shell heißt bash, also führen wir den folgenden Befehl aus:

BASH

$ bash middle.sh

AUSGABE

ATOM      9  H           1      -4.502   0.681   0.785  1.00  0.00
ATOM     10  H           1      -5.254  -0.243  -0.537  1.00  0.00
ATOM     11  H           1      -4.357   1.252  -0.895  1.00  0.00
ATOM     12  H           1      -3.009  -0.741  -1.467  1.00  0.00
ATOM     13  H           1      -3.172  -1.337   0.206  1.00  0.00

Die Ausgabe unseres Skripts ist genau das, was wir erhalten würden, wenn wir die Pipeline direkt ausführen würden.

Wichtig

Text vs. Was auch immer

Normalerweise bezeichnen wir Programme wie Microsoft Word oder LibreOffice Writer als “Texteditoren”, aber wir müssen etwas vorsichtiger sein, wenn es um die Programmierung geht. Microsoft Word verwendet standardmäßig .docx-Dateien, um nicht nur Text, sondern auch Formatierungsinformationen über Schriftarten, Überschriften und so weiter zu speichern. Diese zusätzlichen Informationen werden nicht als Zeichen gespeichert und bedeuten nichts für Tools wie head, das erwartet, dass Eingabedateien nur die Buchstaben, Ziffern und Satzzeichen einer normalen Computertastatur enthalten. Wenn Sie Programme bearbeiten, müssen Sie daher entweder einen reinen Texteditor verwenden oder darauf achten, dass Sie Dateien als reinen Text speichern.

Was, wenn wir Zeilen aus einer beliebigen Datei auswählen wollen? Wir könnten jedes Mal middle.sh editieren, um den Dateinamen zu ändern, aber das würde wahrscheinlich länger dauern, als den Befehl noch einmal in der Shell einzugeben und ihn mit einem neuen Dateinamen auszuführen. Lassen Sie uns stattdessen middle.sh editieren und es vielseitiger machen:

BASH

$ nano middle.sh

Ersetzen Sie nun in “nano” den Text octane.pdb durch die spezielle Variable namens $1:

head -n 15 "$1" | tail -n 5

Innerhalb eines Shell-Skripts bedeutet $1 “der erste Dateiname (oder ein anderes Argument) in der Befehlszeile”. Wir können unser Skript nun wie folgt ausführen:

BASH

$ bash middle.sh octane.pdb

AUSGABE

ATOM      9  H           1      -4.502   0.681   0.785  1.00  0.00
ATOM     10  H           1      -5.254  -0.243  -0.537  1.00  0.00
ATOM     11  H           1      -4.357   1.252  -0.895  1.00  0.00
ATOM     12  H           1      -3.009  -0.741  -1.467  1.00  0.00
ATOM     13  H           1      -3.172  -1.337   0.206  1.00  0.00

oder auf eine andere Datei wie diese:

BASH

$ bash middle.sh pentane.pdb

AUSGABE

ATOM      9  H           1       1.324   0.350  -1.332  1.00  0.00
ATOM     10  H           1       1.271   1.378   0.122  1.00  0.00
ATOM     11  H           1      -0.074  -0.384   1.288  1.00  0.00
ATOM     12  H           1      -0.048  -1.362  -0.205  1.00  0.00
ATOM     13  H           1      -1.183   0.500  -1.412  1.00  0.00
Wichtig

Doppelte Anführungszeichen um Argumente

Aus demselben Grund, aus dem wir die Schleifenvariable in doppelte Anführungszeichen setzen, umgeben wir $1 mit doppelten Anführungszeichen, falls der Dateiname zufällig Leerzeichen enthält.

Derzeit müssen wir jedes Mal middle.sh bearbeiten, wenn wir den Bereich der zurückgegebenen Zeilen anpassen wollen. Wir können das ändern, indem wir unser Skript so konfigurieren, dass es stattdessen drei Befehlszeilenargumente verwendet. Nach dem ersten Kommandozeilenargument ($1) ist jedes weitere Argument, das wir angeben, über die speziellen Variablen $1, $2, $3 zugänglich, die sich jeweils auf das erste, zweite und dritte Kommandozeilenargument beziehen.

Da wir dies wissen, können wir zusätzliche Argumente verwenden, um den Bereich der Zeilen zu definieren, die an head bzw. tail übergeben werden sollen:

BASH

$ nano middle.sh
head -n "$2" "$1" | tail -n "$3"

Wir können jetzt ausführen:

BASH

$ bash middle.sh pentane.pdb 15 5

AUSGABE

ATOM      9  H           1       1.324   0.350  -1.332  1.00  0.00
ATOM     10  H           1       1.271   1.378   0.122  1.00  0.00
ATOM     11  H           1      -0.074  -0.384   1.288  1.00  0.00
ATOM     12  H           1      -0.048  -1.362  -0.205  1.00  0.00
ATOM     13  H           1      -1.183   0.500  -1.412  1.00  0.00

Indem wir die Argumente für unseren Befehl ändern, können wir das Verhalten unseres Skripts ändern:

BASH

$ bash middle.sh pentane.pdb 20 5

AUSGABE

ATOM     14  H           1      -1.259   1.420   0.112  1.00  0.00
ATOM     15  H           1      -2.608  -0.407   1.130  1.00  0.00
ATOM     16  H           1      -2.540  -1.303  -0.404  1.00  0.00
ATOM     17  H           1      -3.393   0.254  -0.321  1.00  0.00
TER      18              1

Das funktioniert, aber es kann sein, dass die nächste Person, die middle.sh liest, einen Moment braucht, um herauszufinden, was es tut. Wir können unser Skript verbessern, indem wir einige Kommentare am Anfang hinzufügen:

BASH

$ nano middle.sh
# Zeilen aus der Mitte einer Datei auswählen.
# Verwendung: bash middle.sh Dateiname Endzeile Anzahl_Zeilen
head -n "$2" "$1" | tail -n "$3"

Ein Kommentar beginnt mit einem #-Zeichen und läuft bis zum Ende der Zeile. Der Computer ignoriert Kommentare, aber sie sind von unschätzbarem Wert für das Verständnis und die Verwendung von Skripten durch andere (auch durch Ihr zukünftiges Ich). Die einzige Einschränkung ist, dass Sie jedes Mal, wenn Sie das Skript ändern, überprüfen sollten, ob der Kommentar noch korrekt ist. Eine Erklärung, die den Leser in die falsche Richtung lenkt, ist schlimmer als gar keine.

Was, wenn wir viele Dateien in einer einzigen Pipeline verarbeiten wollen? Wenn wir zum Beispiel unsere .pdb-Dateien nach Länge sortieren wollen, würden wir folgendes eingeben:

BASH

$ wc -l *.pdb | sort -n

weil wc -l die Anzahl der Zeilen in den Dateien auflistet (erinnern Sie sich, dass wc für ‘word count’ steht, das Hinzufügen der Option -l bedeutet stattdessen ‘count lines’) und sort -n die Dinge numerisch sortiert. Wir könnten dies in eine Datei schreiben, aber dann würde es immer nur eine Liste von .pdb Dateien im aktuellen Verzeichnis sortieren. Wenn wir in der Lage sein wollen, eine sortierte Liste anderer Arten von Dateien zu erhalten, brauchen wir einen Weg, um all diese Namen in das Skript zu bekommen. Wir können nicht $1, $2 und so weiter verwenden, weil wir nicht wissen, wie viele Dateien es gibt. Stattdessen verwenden wir die spezielle Variable $@, was soviel bedeutet wie ‘Alle Befehlszeilenargumente für das Shell-Skript’. Wir sollten auch $@ in Anführungszeichen setzen, um den Fall von Argumenten mit Leerzeichen zu behandeln ("$@" ist eine spezielle Syntax und entspricht "$1" "$2" …).

Hier ist ein Beispiel:

BASH

$ nano sorted.sh
# Sort files by their length.
# Usage: bash sorted.sh one_or_more_filenames
wc -l "$@" | sort -n

BASH

$ bash sorted.sh *.pdb ../creatures/*.dat

AUSGABE

9 methane.pdb
12 ethane.pdb
15 propane.pdb
20 cubane.pdb
21 pentane.pdb
30 octane.pdb
163 ../creatures/basilisk.dat
163 ../creatures/minotaur.dat
163 ../creatures/unicorn.dat
596 total
Aufgabe

Einzigartige Arten auflisten

Leah hat mehrere hundert Datendateien, von denen jede wie folgt formatiert ist:

2013-11-05,deer,5
2013-11-05,rabbit,22
2013-11-05,raccoon,7
2013-11-06,rabbit,19
2013-11-06,deer,2
2013-11-06,fox,1
2013-11-07,rabbit,18
2013-11-07,bear,1

Ein Beispiel für diesen Dateityp findet sich in shell-lesson-data/exercise-data/animal-counts/animals.csv.

Wir können den Befehl cut -d , -f 2 animals.csv | sort | uniq verwenden, um die einzelnen Arten in animals.csv zu erzeugen. Um diese Befehlsfolge nicht jedes Mal abtippen zu müssen, kann ein Wissenschaftler stattdessen ein Shell-Skript schreiben.

Schreiben Sie ein Shell-Skript mit dem Namen species.sh, das eine beliebige Anzahl von Dateinamen als Befehlszeilenargumente annimmt und eine Variation des obigen Befehls verwendet, um eine Liste der einzelnen Arten zu drucken, die in jeder dieser Dateien separat vorkommen.

BASH

# Skript zum Auffinden einzigartiger Arten in CSV-Dateien, wobei „species“ das zweite Datenfeld ist.
# Dieses Skript akzeptiert eine beliebige Anzahl von Dateinamen als Befehlszeilenargumente.

# Über alle Dateien iterieren  
for file in $@
do
    echo "Einzigartige Arten in $file:"
    # Artennamen extrahieren
    cut -d , -f 2 $file | sort | uniq
done

Angenommen, wir haben gerade eine Reihe von Befehlen ausgeführt, die etwas Nützliches bewirkt haben - zum Beispiel die Erstellung eines Diagramms, das wir in einem Artikel verwenden möchten. Wir möchten das Diagramm später bei Bedarf erneut erstellen können, also wollen wir die Befehle in einer Datei speichern. Anstatt die Befehle erneut einzugeben (und sie möglicherweise falsch zu machen), können wir so vorgehen:

BASH

$ history | tail -n 5 > redo-figure-3.sh

Die Datei redo-figure-3.sh enthält jetzt:

297 bash goostats.sh NENE01729B.txt stats-NENE01729B.txt
298 bash goodiff.sh stats-NENE01729B.txt /data/validated/01729.txt > 01729-differences.txt
299 cut -d ',' -f 2-3 01729-differences.txt > 01729-time-series.txt
300 ygraph --format scatter --color bw --borders none 01729-time-series.txt figure-3.png
301 history | tail -n 5 > redo-figure-3.sh

Nach kurzer Arbeit in einem Editor, um die fortlaufenden Nummern der Befehle zu entfernen, und um die letzte Zeile zu entfernen, in der wir den Befehl history aufgerufen haben, haben wir eine völlig genaue Aufzeichnung, wie wir diese Figur erstellt haben.

Aufgabe

Warum Befehle in der Historie aufzeichnen, bevor sie ausgeführt werden?

Wenn Sie den Befehl ausführen:

BASH

$ history | tail -n 5 > recent.sh

Der letzte Befehl in der Datei ist der history-Befehl selbst, d.h. die Shell hat history zum Befehlsprotokoll hinzugefügt, bevor sie ihn tatsächlich ausführt. Tatsächlich fügt die Shell immer Befehle in das Protokoll ein, bevor sie ausgeführt werden. Warum, glauben Sie, tut sie das?

Wenn ein Befehl zu einem Absturz oder einem Hänger führt, könnte es nützlich sein, zu wissen, was dieser Befehl war, um das Problem zu untersuchen. Würde der Befehl erst nach seiner Ausführung aufgezeichnet werden, hätten wir im Falle eines Absturzes keine Aufzeichnung des zuletzt ausgeführten Befehls.

In der Praxis entwickeln die meisten Leute Shell-Skripte, indem sie Befehle an der Shell-Eingabeaufforderung ein paar Mal ausführen, um sicherzustellen, dass sie das Richtige tun, und sie dann zur Wiederverwendung in einer Datei speichern. Diese Arbeitsweise ermöglicht es den Leuten, das, was sie über ihre Daten und ihren Arbeitsablauf herausgefunden haben, mit einem Aufruf von history und ein wenig Bearbeitung zu recyceln, um die Ausgabe zu bereinigen und als Shell-Skript zu speichern.

Nelle’s Pipeline: Erstellen eines Skripts


Nelles Vorgesetzter bestand darauf, dass alle ihre Analysen reproduzierbar sein müssen. Am einfachsten ist es, alle Schritte in einem Skript festzuhalten.

Zuerst kehren wir in Nelles Projektverzeichnis zurück:

BASH

$ cd ../../north-pacific-gyre/

Sie erstellt eine Datei mit nano

BASH

$ nano do-stats.sh

…die folgendes enthält:

BASH

# Berechnen Sie Statistiken für Datendateien.
for datafile in "$@"
do
    echo $datafile
    bash goostats.sh $datafile stats-$datafile
done

Sie speichert dies in einer Datei mit dem Namen do-stats.sh, so dass sie nun die erste Stufe ihrer Analyse wiederholen kann, indem sie eingibt:

BASH

$ bash do-stats.sh NENE*A.txt NENE*B.txt

Sie kann auch dies tun:

BASH

$ bash do-stats.sh NENE*A.txt NENE*B.txt | wc -l

so dass die Ausgabe nur die Anzahl der verarbeiteten Dateien ist und nicht die Namen der verarbeiteten Dateien.

Eine Sache, die man bei Nelles Skript beachten sollte, ist, dass es die Person, die es ausführt, entscheiden lässt, welche Dateien verarbeitet werden sollen. Sie hätte es auch so schreiben können:

BASH

# Berechnen Sie die Statistiken für die Datendateien von Standort A und Standort B.
for datafile in NENE*A.txt NENE*B.txt
do
    echo $datafile
    bash goostats.sh $datafile stats-$datafile
done

Der Vorteil ist, dass dabei immer die richtigen Dateien ausgewählt werden: Sie muss nicht daran denken, die “Z”-Dateien auszuschließen. Der Nachteil ist, dass es immer nur diese Dateien auswählt — sie kann es nicht auf alle Dateien (einschließlich der ‘Z’-Dateien) oder auf die ‘G’- oder ‘H’-Dateien anwenden, die ihre Kollegen in der Antarktis produzieren, ohne das Skript zu bearbeiten. Wenn sie etwas abenteuerlicher sein wollte, könnte sie ihr Skript so ändern, dass es nach Befehlszeilenargumenten sucht und NENE*A.txt NENE*B.txt verwendet, wenn keine angegeben wurden. Natürlich führt dies zu einem weiteren Kompromiss zwischen Flexibilität und Komplexität.

Aufgabe

Variablen in Shell-Skripten

Stellen Sie sich vor, Sie haben im Verzeichnis alkanes ein Shell-Skript namens script.sh, das die folgenden Befehle enthält:

BASH

head -n $2 $1
tail -n $3 $1

Während du dich im Verzeichnis alkanes befindest, gibst du den folgenden Befehl ein:

BASH

$ bash script.sh '*.pdb' 1 1

Welche der folgenden Ausgaben würden Sie erwarten?

  1. Alle Zeilen zwischen der ersten und der letzten Zeile jeder Datei, die auf .pdb im Verzeichnis alkanes endet
  2. Die erste und die letzte Zeile jeder Datei, die auf .pdb im Verzeichnis alkanes endet
  3. Die erste und die letzte Zeile jeder Datei im Verzeichnis alkanes
  4. Ein Fehler wegen der Anführungszeichen um *.pdb

Die richtige Antwort ist 2.

Die speziellen Variablen $1, $2 und $3 stehen für die Kommandozeilenargumente, die dem Skript übergeben werden, so dass die Befehle ausgeführt werden:

BASH

$ head -n 1 cubane.pdb ethane.pdb octane.pdb pentane.pdb propane.pdb
$ tail -n 1 cubane.pdb ethane.pdb octane.pdb pentane.pdb propane.pdb

Die Shell expandiert '*.pdb' nicht, weil es von Anführungszeichen eingeschlossen ist. Das erste Argument des Skripts ist also '*.pdb', das innerhalb des Skripts durch head und tail erweitert wird.

Aufgabe

Finde die längste Datei mit einer gegebenen Erweiterung

Schreiben Sie ein Shell-Skript mit dem Namen longest.sh, das den Namen eines Verzeichnisses und eine Dateinamenserweiterung als Argumente annimmt und den Namen der Datei mit den meisten Zeilen in diesem Verzeichnis mit dieser Erweiterung ausgibt. Zum Beispiel:

BASH

$ bash longest.sh shell-lesson-data/exercise-data/alkanes pdb

würde den Namen der Datei .pdb in shell-lesson-data/exercise-data/alkanes ausgeben, die die meisten Zeilen hat.

Sie können Ihr Skript auch in einem anderen Verzeichnis testen, z.B.

BASH

$ bash longest.sh shell-lesson-data/exercise-data/writing txt

BASH

# Shell-Skript, das zwei Argumente akzeptiert:
#    1. einen Verzeichnisnamen
#    2. eine Dateierweiterung
# und den Namen der Datei in diesem Verzeichnis ausgibt,
# die die meisten Zeilen enthält, die mit der Dateierweiterung übereinstimmen.

wc -l $1/*.$2 | sort -n | tail -n 2 | head -n 1

Der erste Teil der Pipeline, wc -l $1/*.$2 | sort -n, zählt die Zeilen in jeder Datei und sortiert sie numerisch (die größte zuletzt). Wenn es mehr als eine Datei gibt, gibt wc auch eine abschließende Übersichtszeile aus, die die Gesamtzahl der Zeilen in allen Dateien angibt. Wir benutzen tail -n 2 | head -n 1, um diese letzte Zeile zu verwerfen.

Mit wc -l $1/*.$2 | sort -n | tail -n 1 sehen wir die abschließende Zusammenfassungszeile: wir können unsere Pipeline stückweise aufbauen, um sicher zu sein, dass wir die Ausgabe verstehen.

Aufgabe

Skript Leseverstehen

Für diese Frage betrachten wir noch einmal das Verzeichnis shell-lesson-data/exercise-data/alkanes. Dieses enthält eine Reihe von .pdb-Dateien zusätzlich zu allen anderen Dateien, die Sie erstellt haben. Erkläre, was jedes der folgenden drei Skripte tun würde, wenn es als bash script1.sh *.pdb, bash script2.sh *.pdb bzw. bash script3.sh *.pdb ausgeführt würde.

BASH

# Script 1
echo *.*

BASH

# Script 2
for filename in $1 $2 $3
do
    cat $filename
done

BASH

# Script 3
echo $@.pdb

In jedem Fall expandiert die Shell den Platzhalter in *.pdb, bevor sie die resultierende Liste von Dateinamen als Argumente an das Skript weitergibt.

Skript 1 würde eine Liste aller Dateien ausgeben, die einen Punkt in ihrem Namen enthalten. Die Argumente, die dem Skript übergeben werden, werden im Skript selbst nicht verwendet.

Skript 2 würde den Inhalt der ersten 3 Dateien mit der Dateierweiterung .pdb ausgeben.$1, $2 und $3 beziehen sich jeweils auf das erste, zweite und dritte Argument.

Skript 3 würde alle Argumente für das Skript ausgeben (d.h. alle .pdb-Dateien), gefolgt von .pdb.$@ bezieht sich auf alle Argumente, die einem Shell-Skript übergeben werden.

AUSGABE

cubane.pdb ethane.pdb methane.pdb octane.pdb pentane.pdb propane.pdb.pdb
Aufgabe

Debugging-Skripte

Angenommen, Sie haben das folgende Skript in einer Datei namens do-errors.sh im Verzeichnis north-pacific-gyre von Nelle gespeichert:

BASH

# Berechnen Sie Statistiken für Datendateien.
for datafile in "$@"
do
    echo $datfile
    bash goostats.sh $datafile stats-$datafile
done

Wenn Sie es aus dem Verzeichnis north-pacific-gyre ausführen:

BASH

$ bash do-errors.sh NENE*A.txt NENE*B.txt

Die Ausgabe ist leer. Um herauszufinden, warum, führen Sie das Skript mit der Option -x erneut aus:

BASH

$ bash -x do-errors.sh NENE*A.txt NENE*B.txt

Was zeigt Ihnen die Ausgabe? Welche Zeile ist für den Fehler verantwortlich?

Die Option -x bewirkt, dass bash im Debug-Modus läuft. Dadurch wird jeder Befehl während seiner Ausführung ausgedruckt, was Ihnen hilft, Fehler zu finden. In diesem Beispiel können wir sehen, dass echo nichts ausgibt. Wir haben einen Tippfehler im Namen der Schleifenvariablen gemacht, und die Variable datfile existiert nicht und gibt daher einen leeren String zurück.

Hauptpunkte
  • Speichern Sie Befehle in Dateien (normalerweise Shell-Skripte genannt) zur Wiederverwendung.
  • bash [filename] führt die in einer Datei gespeicherten Befehle aus.
  • $@ bezieht sich auf alle Kommandozeilenargumente eines Shell-Skripts.
  • $1, $2, etc. beziehen sich auf das erste Kommandozeilenargument, das zweite Kommandozeilenargument, etc.
  • Setzen Sie Variablen in Anführungszeichen, wenn die Werte Leerzeichen enthalten könnten.
  • Dem Benutzer die Entscheidung zu überlassen, welche Dateien verarbeitet werden sollen, ist flexibler und konsistenter mit eingebauten Unix-Befehlen.

Content from Dinge finden


Zuletzt aktualisiert am 2025-10-23 | Diese Seite bearbeiten

Geschätzte Zeit: 45 Minuten

Übersicht

Fragen

  • Wie kann ich Dateien finden?
  • Wie kann ich Dinge in Dateien finden?

Ziele

  • Verwenden Sie grep, um Zeilen aus Textdateien auszuwählen, die einfachen Mustern entsprechen.
  • Verwenden Sie find, um Dateien und Verzeichnisse zu finden, deren Namen einfachen Mustern entsprechen.
  • Verwenden Sie die Ausgabe eines Befehls als Befehlszeilenargument(e) für einen anderen Befehl.
  • Erläutern Sie, was mit “Text”- und “Binär”-Dateien gemeint ist und warum viele gängige Werkzeuge mit letzteren nicht gut umgehen können.

Genauso wie viele von uns heute “Google” als Verb für “finden” verwenden, benutzen Unix-Programmierer oft das Wort “grep”. grep” ist eine Abkürzung für “global/regulärer Ausdruck/Druck”, eine übliche Abfolge von Operationen in frühen Unix-Texteditoren. Es ist auch der Name eines sehr nützlichen Befehlszeilenprogramms.

grep findet und druckt Zeilen in Dateien, die einem Muster entsprechen. Für unsere Beispiele verwenden wir eine Datei, die drei Haiku aus einem [1998er Wettbewerb] (https://web.archive.org/web/19991201042211/http://salon.com/21st/chal/1998/01/26chal.html) in der Zeitschrift Salon enthält (Dank an die Autoren Bill Torcaso, Howard Korder bzw. Margaret Segall. Siehe Haiku-Fehlermeldungen im Archiv Seite 1 und Seite 2 .). Für diese Reihe von Beispielen arbeiten wir im Unterverzeichnis writing:

BASH

$ cd
$ cd Desktop/shell-lesson-data/exercise-data/writing
$ cat haiku.txt

AUSGABE

The Tao that is seen
Is not the true Tao, until
You bring fresh toner.

With searching comes loss
and the presence of absence:
"My Thesis" not found.

Yesterday it worked
Today it is not working
Software is like that.

Suchen wir nach Zeilen, die das Wort “not” enthalten:

BASH

$ grep not haiku.txt

AUSGABE

Is not the true Tao, until
"My Thesis" not found
Today it is not working

Hier ist not das Muster, nach dem wir suchen. Der Befehl grep durchsucht die Datei nach Übereinstimmungen mit dem angegebenen Muster. Geben Sie dazu grep ein, dann das gesuchte Muster und schließlich den Namen der Datei (oder der Dateien), in der Sie suchen.

Ausgegeben werden die drei Zeilen der Datei, die die Buchstaben “not” enthalten.

Standardmäßig sucht grep nach einem Muster unter Berücksichtigung der Groß- und Kleinschreibung. Außerdem muss das von uns gewählte Suchmuster kein vollständiges Wort bilden, wie wir im nächsten Beispiel sehen werden.

Suchen wir nach dem Muster: ‘The’.

BASH

$ grep The haiku.txt

AUSGABE

The Tao that is seen
"My Thesis" not found.

Diesmal werden zwei Zeilen ausgegeben, die die Buchstaben “The” enthalten, von denen eine unser Suchmuster innerhalb eines größeren Wortes, “Thesis”, enthält.

Um Übereinstimmungen auf Zeilen zu beschränken, die das Wort “The” allein enthalten, können wir grep die Option -w geben. Dadurch werden die Treffer auf Wortgrenzen beschränkt.

Später in dieser Lektion werden wir auch sehen, wie wir das Suchverhalten von grep in Bezug auf die Groß- und Kleinschreibung ändern können.

BASH

$ grep -w The haiku.txt

AUSGABE

The Tao that is seen

Beachten Sie, dass eine “Wortgrenze” den Anfang und das Ende einer Zeile umfasst, also nicht nur von Leerzeichen umgebene Buchstaben. Manchmal wollen wir nicht nach einem einzelnen Wort suchen, sondern nach einer Phrase. Wir können dies auch mit grep tun, indem wir die Phrase in Anführungszeichen setzen.

BASH

$ grep -w "is not" haiku.txt

AUSGABE

Today it is not working

Wir haben jetzt gesehen, dass Sie einzelne Wörter nicht in Anführungszeichen setzen müssen, aber es ist nützlich, Anführungszeichen zu verwenden, wenn Sie nach mehreren Wörtern suchen. Dies erleichtert auch die Unterscheidung zwischen dem Suchbegriff oder der Phrase und der gesuchten Datei. In den folgenden Beispielen werden wir Anführungszeichen verwenden.

Eine weitere nützliche Option ist -n, die die übereinstimmenden Zeilen nummeriert:

BASH

$ grep -n "it" haiku.txt

AUSGABE

5:With searching comes loss
9:Yesterday it worked
10:Today it is not working

Hier ist zu erkennen, dass die Zeilen 5, 9 und 10 die Buchstaben “it” enthalten.

Wir können Optionen (d.h. Flags) wie bei anderen Unix-Befehlen kombinieren. Wir wollen zum Beispiel die Zeilen finden, die das Wort “the” enthalten. Wir können die Option -w kombinieren, um die Zeilen zu finden, die das Wort ‘the’ enthalten, und -n, um die entsprechenden Zeilen zu nummerieren:

BASH

$ grep -n -w "the" haiku.txt

AUSGABE

2:Is not the true Tao, until
6:and the presence of absence:

Jetzt wollen wir die Option -i verwenden, um die Groß- und Kleinschreibung zu ignorieren:

BASH

$ grep -n -w -i "the" haiku.txt

AUSGABE

1:The Tao that is seen
2:Is not the true Tao, until
6:and the presence of absence:

Jetzt wollen wir die Option -v verwenden, um unsere Suche zu invertieren, d.h. wir wollen die Zeilen ausgeben, die das Wort ‘the’ nicht enthalten.

BASH

$ grep -n -w -v "the" haiku.txt

AUSGABE

1:The Tao that is seen
3:You bring fresh toner.
4:
5:With searching comes loss
7:"My Thesis" not found.
8:
9:Yesterday it worked
10:Today it is not working
11:Software is like that.

Wenn wir die Option -r (rekursiv) verwenden, kann grep rekursiv in einer Menge von Dateien in Unterverzeichnissen nach einem Muster suchen.

Lassen Sie uns rekursiv nach Yesterday im Verzeichnis shell-lesson-data/exercise-data/writing suchen:

BASH

$ grep -r Yesterday .

AUSGABE

./LittleWomen.txt:"Yesterday, when Aunt was asleep and I was trying to be as still as a
./LittleWomen.txt:Yesterday at dinner, when an Austrian officer stared at us and then
./LittleWomen.txt:Yesterday was a quiet day spent in teaching, sewing, and writing in my
./haiku.txt:Yesterday it worked

grep hat viele andere Optionen. Um herauszufinden, welche das sind, können wir sie eingeben:

BASH

$ grep --help

AUSGABE

Usage: grep [OPTION]... PATTERN [FILE]...
Search for PATTERN in each FILE or standard input.
PATTERN is, by default, a basic regular expression (BRE).
Example: grep -i 'hello world' menu.h main.c

Regexp selection and interpretation:
  -E, --extended-regexp     PATTERN is an extended regular expression (ERE)
  -F, --fixed-strings       PATTERN is a set of newline-separated fixed strings
  -G, --basic-regexp        PATTERN is a basic regular expression (BRE)
  -P, --perl-regexp         PATTERN is a Perl regular expression
  -e, --regexp=PATTERN      use PATTERN for matching
  -f, --file=FILE           obtain PATTERN from FILE
  -i, --ignore-case         ignore case distinctions
  -w, --word-regexp         force PATTERN to match only whole words
  -x, --line-regexp         force PATTERN to match only whole lines
  -z, --null-data           a data line ends in 0 byte, not newline

Miscellaneous:
...        ...        ...
Aufgabe

Verwendung von grep

Welcher Befehl würde zu der folgenden Ausgabe führen:

AUSGABE

and the presence of absence:
  1. grep "of" haiku.txt
  2. grep -E "of" haiku.txt
  3. grep -w "of" haiku.txt
  4. grep -i "of" haiku.txt

Die richtige Antwort ist 3, denn die Option -w sucht nur nach Übereinstimmungen mit ganzen Wörtern. Die anderen Optionen passen auch auf “of”, wenn es Teil eines anderen Wortes ist.

Wichtig

Wildcards

Die eigentliche Stärke von grep liegt jedoch nicht in den Optionen, sondern in der Tatsache, dass Muster Platzhalter enthalten können. (Der technische Name dafür ist reguläre Ausdrücke, wofür das “re” in “grep” steht.) Reguläre Ausdrücke sind sowohl komplex als auch mächtig; wenn Sie komplexe Suchvorgänge durchführen wollen, sehen Sie sich bitte die Lektion auf unserer Website an. Als Kostprobe können wir Zeilen finden, die ein ‘o’ an der zweiten Stelle haben, etwa so:

BASH

$ grep -E "^.o" haiku.txt

AUSGABE

You bring fresh toner.
Today it is not working
Software is like that.

Wir benutzen die Option -E und setzen das Muster in Anführungszeichen, um zu verhindern, dass die Shell versucht, es zu interpretieren. (Wenn das Muster zum Beispiel ein * enthielte, würde die Shell versuchen, es zu expandieren, bevor sie grep ausführt.) Das ^ im Muster verankert die Übereinstimmung am Anfang der Zeile. Das . passt auf ein einzelnes Zeichen (genau wie ? in der Shell), während das o auf ein tatsächliches ‘o’ passt.

Aufgabe

Nachverfolgung einer Spezies

Leah hat mehrere hundert Datendateien in einem Verzeichnis gespeichert, von denen jede wie folgt formatiert ist:

2012-11-05,deer,5
2012-11-05,rabbit,22
2012-11-05,raccoon,7
2012-11-06,rabbit,19
2012-11-06,deer,2
2012-11-06,fox,4
2012-11-07,rabbit,16
2012-11-07,bear,1

Sie möchte ein Shell-Skript schreiben, das eine Spezies als erstes Befehlszeilenargument und ein Verzeichnis als zweites Argument annimmt. Das Skript soll eine Datei mit dem Namen <species>.txt zurückgeben, die eine Liste von Daten und die Anzahl der an jedem Datum beobachteten Arten enthält. Bei Verwendung der oben gezeigten Daten würde rabbit.txt zum Beispiel enthalten:

2012-11-05,22
2012-11-06,19
2012-11-07,16

Nachfolgend enthält jede Zeile einen einzelnen Befehl, eine Pipe. Ordnen Sie deren Reihenfolge in einem Befehl an, um das Ziel von Leah zu erreichen:

BASH

cut -d : -f 2
>
|
grep -w $1 -r $2
|
$1.txt
cut -d , -f 1,3

Hinweis: Verwenden Sie man grep, um zu suchen, wie man Text in einem Verzeichnis rekursiv einfängt und man cut, um mehr als ein Feld in einer Zeile auszuwählen.

Ein Beispiel für eine solche Datei ist in shell-lesson-data/exercise-data/animal-counts/animals.csv enthalten

grep -w $1 -r $2 | cut -d : -f 2 | cut -d , -f 1,3 > $1.txt

Sie können die Reihenfolge der beiden Cut-Befehle vertauschen und es funktioniert trotzdem. Versuchen Sie in der Befehlszeile, die Reihenfolge der Schnittbefehle zu ändern, und sehen Sie sich die Ausgabe der einzelnen Schritte an, um zu sehen, warum dies der Fall ist.

Sie würden das obige Skript wie folgt aufrufen:

BASH

$ bash count-species.sh bear .
Aufgabe

Little Women

Sie und Ihr Freund, der gerade Little Women von Louisa May Alcott gelesen hat, streiten sich. Von den vier Schwestern im Buch, Jo, Meg, Beth und Amy, meint Ihr Freund, dass Jo am meisten erwähnt wurde. Sie hingegen sind sich sicher, dass es Amy war. Glücklicherweise haben Sie eine Datei LittleWomen.txt, die den vollständigen Text des Romans enthält (shell-lesson-data/exercise-data/writing/LittleWomen.txt). Wie würden Sie mit Hilfe einer for-Schleife die Anzahl der Erwähnungen jeder der vier Schwestern tabellarisch darstellen?

Hinweis: Eine Lösung könnte die Befehle grep und wc und ein | verwenden, während eine andere die Optionen grep nutzt. Es gibt oft mehr als einen Weg, eine Programmieraufgabe zu lösen, so dass eine bestimmte Lösung in der Regel auf der Grundlage einer Kombination von korrektem Ergebnis, Eleganz, Lesbarkeit und Geschwindigkeit gewählt wird.

for sis in Jo Meg Beth Amy
do
    echo $sis:
    grep -ow $sis LittleWomen.txt | wc -l
done

Alternative, etwas schlechtere Lösung:

for sis in Jo Meg Beth Amy
do
    echo $sis:
    grep -ocw $sis LittleWomen.txt
done

Diese Lösung ist minderwertig, weil grep -c nur die Anzahl der übereinstimmenden Zeilen meldet. Die Gesamtzahl der Übereinstimmungen, die von dieser Methode gemeldet wird, ist geringer, wenn es mehr als eine Übereinstimmung pro Zeile gibt.

Aufmerksamen Beobachtern ist vielleicht aufgefallen, dass die Namen der Figuren in den Kapiteltiteln manchmal in Großbuchstaben erscheinen (z.B. ‘MEG GOES TO VANITY FAIR’). Wenn Sie auch diese mitzählen wollten, könnten Sie die Option -i zur Unterscheidung der Groß- und Kleinschreibung hinzufügen (obwohl dies in diesem Fall keinen Einfluss auf die Antwort auf die Frage hat, welche Schwester am häufigsten erwähnt wird).

Während grep Zeilen in Dateien findet, findet der Befehl find die Dateien selbst. Auch hier gibt es eine Menge Optionen; um zu zeigen, wie die einfachsten funktionieren, verwenden wir den unten gezeigten shell-lesson-data/exercise-data-Verzeichnisbaum.

AUSGABE

.
├── animal-counts/
│   └── animals.csv
├── creatures/
│   ├── basilisk.dat
│   ├── minotaur.dat
│   └── unicorn.dat
├── numbers.txt
├── alkanes/
│   ├── cubane.pdb
│   ├── ethane.pdb
│   ├── methane.pdb
│   ├── octane.pdb
│   ├── pentane.pdb
│   └── propane.pdb
└── writing/
    ├── haiku.txt
    └── LittleWomen.txt

Das Verzeichnis exercise-data enthält eine Datei, numbers.txt und vier Verzeichnisse: animal-counts, creatures, alkanes und writing mit verschiedenen Dateien.

Für unseren ersten Befehl führen wir find . aus (denken Sie daran, diesen Befehl aus dem Ordner shell-lesson-data/exercise-data auszuführen).

BASH

$ find .

AUSGABE

.
./writing
./writing/LittleWomen.txt
./writing/haiku.txt
./creatures
./creatures/basilisk.dat
./creatures/unicorn.dat
./creatures/minotaur.dat
./animal-counts
./animal-counts/animals.csv
./numbers.txt
./alkanes
./alkanes/ethane.pdb
./alkanes/propane.pdb
./alkanes/octane.pdb
./alkanes/pentane.pdb
./alkanes/methane.pdb
./alkanes/cubane.pdb

Wie immer steht . für das aktuelle Arbeitsverzeichnis, in dem wir unsere Suche beginnen wollen. die Ausgabe von find sind die Namen aller Dateien und Verzeichnisse unterhalb des aktuellen Arbeitsverzeichnisses. Das mag zunächst nutzlos erscheinen, aber find hat viele Möglichkeiten, die Ausgabe zu filtern, und in dieser Lektion werden wir einige davon kennenlernen.

Die erste Option in unserer Liste ist -type d, was “Dinge, die Verzeichnisse sind” bedeutet. Sicherlich ist die Ausgabe von find die Namen der fünf Verzeichnisse (einschließlich .):

BASH

$ find . -type d

AUSGABE

.
./writing
./creatures
./animal-counts
./alkanes

Beachten Sie, dass die Objekte, die find findet, nicht in einer bestimmten Reihenfolge aufgelistet sind. Wenn wir -type d in -type f ändern, erhalten wir stattdessen eine Auflistung aller Dateien:

BASH

$ find . -type f

AUSGABE

./writing/LittleWomen.txt
./writing/haiku.txt
./creatures/basilisk.dat
./creatures/unicorn.dat
./creatures/minotaur.dat
./animal-counts/animals.csv
./numbers.txt
./alkanes/ethane.pdb
./alkanes/propane.pdb
./alkanes/octane.pdb
./alkanes/pentane.pdb
./alkanes/methane.pdb
./alkanes/cubane.pdb

Versuchen wir nun, nach Namen zu suchen:

BASH

$ find . -name *.txt

AUSGABE

./numbers.txt

Wir haben erwartet, dass es alle Textdateien findet, aber es gibt nur ./numbers.txt aus. Das Problem ist, dass die Shell Platzhalterzeichen wie * vor der Ausführung von Befehlen expandiert. Da *.txt im aktuellen Verzeichnis zu ./numbers.txt expandiert, war der Befehl, den wir tatsächlich ausgeführt haben:

BASH

$ find . -name numbers.txt

find hat getan, worum wir gebeten haben; wir haben nur nach der falschen Sache gefragt.

Um das zu bekommen, was wir wollen, machen wir es wie bei grep: Wir setzen *.txt in Anführungszeichen, um zu verhindern, dass die Shell den Platzhalter * erweitert. Auf diese Weise erhält find tatsächlich das Muster *.txt, nicht den erweiterten Dateinamen numbers.txt:

BASH

$ find . -name "*.txt"

AUSGABE

./writing/LittleWomen.txt
./writing/haiku.txt
./numbers.txt
Wichtig

Auflistung vs. Auffinden

ls und find können mit den richtigen Optionen ähnliche Dinge tun, aber unter normalen Umständen listet ls alles auf, was es kann, während find nach Dingen mit bestimmten Eigenschaften sucht und sie anzeigt.

Wie wir bereits gesagt haben, liegt die Stärke der Kommandozeile in der Kombination von Werkzeugen. Wir haben gesehen, wie man das mit Pipes macht; sehen wir uns eine andere Technik an. Wie wir gerade gesehen haben, gibt uns find . -name "*.txt" eine Liste aller Textdateien im oder unterhalb des aktuellen Verzeichnisses. Wie können wir das mit wc -l kombinieren, um die Zeilen in all diesen Dateien zu zählen?

Am einfachsten ist es, den Befehl find in $() einzufügen:

BASH

$ wc -l $(find . -name "*.txt")

AUSGABE

  21022 ./writing/LittleWomen.txt
     11 ./writing/haiku.txt
      5 ./numbers.txt
  21038 total

Wenn die Shell diesen Befehl ausführt, führt sie als erstes das aus, was in $() steht. Dann ersetzt sie den Ausdruck $() durch die Ausgabe dieses Befehls. Da die Ausgabe von find aus den drei Dateinamen ./writing/LittleWomen.txt, ./writing/haiku.txt und ./numbers.txt besteht, konstruiert die Shell den Befehl:

BASH

$ wc -l ./writing/LittleWomen.txt ./writing/haiku.txt ./numbers.txt

das ist das, was wir wollten. Diese Expansion ist genau das, was die Shell macht, wenn sie Platzhalter wie * und ? expandiert, aber wir können jeden beliebigen Befehl als unseren eigenen “Platzhalter” verwenden.

Es ist sehr üblich, find und grep zusammen zu verwenden. Die erste findet Dateien, die einem Muster entsprechen; die zweite sucht nach Zeilen innerhalb dieser Dateien, die einem anderen Muster entsprechen. Hier können wir zum Beispiel txt-Dateien finden, die das Wort “searching” enthalten, indem wir nach der Zeichenfolge “searching” in allen .txt-Dateien im aktuellen Verzeichnis suchen:

BASH

$ grep "searching" $(find . -name "*.txt")

AUSGABE

./writing/LittleWomen.txt:sitting on the top step, affected to be searching for her book, but was
./writing/haiku.txt:With searching comes loss
Aufgabe

Abgleichen und Subtrahieren

Die Option -v zu grep kehrt den Mustervergleich um, so dass nur Zeilen gedruckt werden, die nicht dem Muster entsprechen. Welcher der folgenden Befehle findet dann alle .dat-Dateien in creatures außer unicorn.dat? Sobald Sie sich Ihre Antwort überlegt haben, können Sie die Befehle im Verzeichnis shell-lesson-data/exercise-data testen.

  1. find creatures -name "*.dat" | grep -v unicorn
  2. find creatures -name *.dat | grep -v unicorn
  3. grep -v "unicorn" $(find creatures -name "*.dat")
  4. Keines der oben genannten.

Option 1 ist richtig. Das Einschließen des Vergleichsausdrucks in Anführungszeichen verhindert, dass die Shell ihn expandiert, so dass er an den Befehl find übergeben wird.

Option 2 funktioniert auch in diesem Fall, weil die Shell versucht, *.dat zu expandieren, aber es gibt keine *.dat Dateien im aktuellen Verzeichnis, also wird der Platzhalterausdruck an find übergeben. Wir haben dies zum ersten Mal in Episode 3 gesehen.

Option 3 ist falsch, weil sie den Inhalt der Dateien nach Zeilen durchsucht, die nicht mit “unicorn” übereinstimmen, anstatt die Dateinamen zu durchsuchen.

Wichtig

Binäre Dateien

Wir haben uns ausschließlich auf die Suche nach Mustern in Textdateien konzentriert. Was ist, wenn Ihre Daten als Bilder, in Datenbanken oder in einem anderen Format gespeichert sind?

Eine Handvoll Werkzeuge erweitern grep, um einige Nicht-Text-Formate zu verarbeiten. Ein verallgemeinerbarerer Ansatz besteht jedoch darin, die Daten in Text zu konvertieren oder die textähnlichen Elemente aus den Daten zu extrahieren. Einerseits sind damit einfache Dinge leicht zu erledigen. Auf der anderen Seite sind komplexe Dinge in der Regel unmöglich. Es ist zum Beispiel einfach genug, ein Programm zu schreiben, das X- und Y-Maße aus Bilddateien extrahiert, um damit zu spielen, aber wie würden Sie etwas schreiben, um Werte in einem Arbeitsblatt zu finden, dessen Zellen Formeln enthalten?

Eine letzte Möglichkeit ist, zu erkennen, dass die Shell und die Textverarbeitung ihre Grenzen haben, und eine andere Programmiersprache zu verwenden. Wenn es an der Zeit ist, dies zu tun, seien Sie nicht zu streng mit der Shell. Viele moderne Programmiersprachen haben viele Ideen von ihr übernommen, und Nachahmung ist auch die schönste Form des Lobes.

Die Unix-Shell ist älter als die meisten Menschen, die sie benutzen. Sie hat so lange überlebt, weil sie eine der produktivsten Programmierumgebungen ist, die je geschaffen wurden — vielleicht sogar die produktivste. Ihre Syntax mag kryptisch sein, aber wer sie beherrscht, kann interaktiv mit verschiedenen Befehlen experimentieren und dann das Gelernte zur Automatisierung seiner Arbeit nutzen. Grafische Benutzeroberflächen mögen anfangs einfacher zu bedienen sein, aber einmal gelernt, ist die Produktivität der Shell unschlagbar. Und wie Alfred North Whitehead 1911 schrieb: “Die Zivilisation schreitet voran, indem sie die Zahl der wichtigen Operationen erweitert, die wir ausführen können, ohne darüber nachzudenken

Aufgabe

find Pipeline Reading Comprehension

Schreiben Sie einen kurzen erklärenden Kommentar für das folgende Shell-Skript:

BASH

wc -l $(find . -name "*.dat") | sort -n
  1. Sucht alle Dateien mit der Erweiterung .dat rekursiv im aktuellen Verzeichnis
  2. Zählen Sie die Anzahl der Zeilen, die jede dieser Dateien enthält
  3. Sortieren Sie die Ausgabe aus Schritt 2. numerisch
Hauptpunkte
  • find findet Dateien mit bestimmten Eigenschaften, die den Mustern entsprechen.
  • grep wählt Zeilen in Dateien aus, die dem Muster entsprechen.
  • --help ist eine Option, die von vielen Bash-Befehlen und Programmen unterstützt wird, die aus der Bash heraus ausgeführt werden können, um weitere Informationen über die Verwendung dieser Befehle oder Programme anzuzeigen.
  • man [command] zeigt die Handbuchseite für einen bestimmten Befehl an.
  • $([command]) fügt die Ausgabe eines Befehls an dieser Stelle ein.