Linux-Programmierung I / O-Umleitung. So speichern Sie die Ausgabe eines Terminalbefehls (Bash) in einer Textdatei. ▍Umleitung von Fehler- und Ausgabeströmen

Die Umleitung erfolgt normalerweise durch Einfügen des Sonderzeichens ">" zwischen den Befehlen. Normalerweise sieht die Syntax so aus:

Befehl1> Datei1

führt Befehl1 aus und gibt die Standardausgabe in Datei1 ein.

Team1< файл1

führt Befehl1 mit Datei1 als Eingabequelle (anstelle der Tastatur) aus.

Team1< файл1 >Datei2

kombiniert die beiden vorherigen Optionen. Führt die Eingabe von Befehl1 von Datei1 und Ausgabe in Datei2 aus

Förderer

Pipelines sind die Fähigkeit mehrerer Programme, zusammenzuarbeiten, wenn die Ausgabe eines Programms direkt zur Eingabe eines anderen geht, ohne zwischenzeitliche temporäre Dateien zu verwenden. Syntax:

team1 | team2

Führt Befehl1 mit seinem Ausgabestream als Eingabe aus, wenn Befehl2 ausgeführt wird, was der Verwendung von zwei Umleitungen und einer temporären Datei entspricht:

Befehl1> Temporäre Datei Befehl2< ВременныйФайл rm ВременныйФайл

Ein gutes Beispiel für Befehlspipelines ist die Kombination von echo mit einem anderen Befehl, um Interaktivität in nicht interaktiven Umgebungen zu erhalten, zum Beispiel:

echo -e "Benutzername \ nPasswort" | ftp localhost

Dies startet den Client, der sich als Benutzername mit localhost verbindet, drückt die Eingabetaste und gibt dann das Kennwort Password ein.

Umleitung zu / von Standarddateideskriptoren

In einer von der Bourne-Shell abgeleiteten UNIX-Shell können die vorherigen beiden Aktionen verbessert werden, indem eine Zahl (Dateideskriptor) unmittelbar vor dem Umleitungszeichen angegeben wird. Diese Zahl gibt an, welcher Stream für die Umleitung verwendet wird. Die folgenden Standard-I/O-Streams existieren unter UNIX:

Z.B:

Befehl1 2> Datei1

Fügen Sie in von der C-Shell abgeleiteten Befehlsshells gemäß den Syntaxregeln das Zeichen & nach dem Umleitungszeichen hinzu, um den Stream anzugeben, zu dem die Umleitung ausgeführt wird.

Häufig werden Standardfehler mit Standardausgaben verkettet, damit Fehler und normale Programmausgaben zusammen behandelt werden können. Z.B:

Suchen / -name .profile> results.txt 2> & 1

versucht, alle Dateien mit dem Namen .profile zu finden. Wenn Sie diesen Befehl ohne Umleitungen ausführen, werden Suchergebnisse und Fehlermeldungen (z. B. unzureichende Zugriffsrechte beim Versuch, in geschützten Verzeichnissen zu suchen) dorthin geleitet. Standardmäßig werden diese Rollen von der Konsole ausgeführt. Wenn die Standardausgabe an die Ergebnisdatei geleitet wird, werden dennoch Fehler an die Konsole gesendet. Damit sowohl Fehler als auch Suchergebnisse an die Datei results.txt weitergeleitet werden, werden die Standardfehler- und Ausgabestreams mit verkettet 2>&1 .

Schreiben 2>&1 Vorderseite > geht nicht, seit wann der Dolmetscher liest 2>&1 , weiß es noch nicht, wohin die Standardausgabe umgeleitet wird, sodass die Fehler- und Ausgabestreams nicht zusammengeführt werden.

Wenn das kombinierte Ergebnis über eine Pipeline an die Eingabe eines anderen Programms gesendet werden muss, dann wird die Sequenz 2>&1 muss vor dem Förderband stehen. Z.B:

Suche / -name .profile 2> & 1 | weniger

Vereinfachte Befehlsnotation:

Befehl> Datei 2> & 1

sieht so aus:

Befehl &> Datei

Befehl> & Datei

Förderungskette

Umleitungs- und Pipelining-Befehle können verkettet werden, um komplexere Befehle zu erzeugen, zum Beispiel:

Ls | grep ".sh" | sortieren > shlist

Ruft eine Liste des Inhalts des aktuellen Verzeichnisses ab, die gefiltert wird, sodass nur Zeilen übrig bleiben, die . enthalten ".NS", dann wird diese gefilterte Liste lexikalisch sortiert und das Endergebnis in eine Datei abgelegt shlist... Diese Art von Konstrukten findet man häufig in UNIX-Shell-Skripten.

Umleitung auf mehrere Pins

Ein Standardbefehl kann die Ausgabe eines Befehls gleichzeitig an mehrere Speicherorte umleiten. Beispiel:

Ls -lrt | T-Datei1

leitet die Standardausgabe des Befehls ls -lrt(Liste der Dateien) sowohl in der Konsole als auch in Datei1.

Weiterleiten mit anhängen

In der Befehlsshell können Sie zu einer Datei mit angehängtem umleiten. In diesem Fall werden die in der Datei gespeicherten Informationen nicht gelöscht, sondern alle neuen Informationen werden am Ende dieser Datei hinzugefügt. Syntax:

Befehl1 >> Datei1

Eingebettetes Dokument

Einige Shells und sogar die Anwendung Java (PHP], Perl) erlauben die Syntax eingebetteter Dokumente (siehe Heredoc-Syntax), wodurch Sie einen Eingabestrom aus der Programmdatei selbst senden können, zum Beispiel: cat „EOF Jeder Text wird hier platziert , einschließlich Sonderzeichen EOF

Die Endsignatur des Endes eines eingebetteten EOF-Dokuments (Sie können einen beliebigen Wert verwenden, aber oft wird EOF verwendet - je nach Bedeutung) muss am Anfang der Zeile beginnen.

Systemadministration von Linux-Systemen, und zwar die Administration jedes UNIX-ähnlichen Systems. Es ist untrennbar mit der Arbeit in Befehlsshells verbunden. Für erfahrene Systemadministratoren Diese Art der Interaktion mit dem System ist viel bequemer und schneller als die Verwendung von grafischen Shells und Oberflächen. Natürlich wird dies vielen sofort als übertrieben erscheinen, aber das ist eine unbestreitbare Tatsache. In der Praxis ständig bestätigt. Und diese Situation ist dank einiger Tricks und Tools möglich, die bei der Arbeit mit der Befehlskonsole verwendet werden. Und eines dieser Werkzeuge ist die Nutzung von Informationskanälen und die Umleitung von Datenströmen für Prozesse.

Ein bisschen Theorie

Es sollte damit beginnen, dass das System für jeden Prozess mindestens drei Informationskanäle zur "Nutzung" bereitstellt:

  • STDIN - Standardeingabe;
  • STDOUT - Standardausgabe;
  • STDERR ist ein Standardfehler.

Es gibt keine strikte Mitgliedschaft in diesen Kanälen für jeden Prozess. Die Prozesse selbst, die zunächst im System auftauchen, wissen nicht, wer und wie die Kanäle gehören. Sie (Kanäle) sind eine systemweite Ressource. Obwohl sie vom Kernel im Auftrag des Prozesses installiert werden. Pipes können Dateien, Pipes, die andere Prozesse verknüpfen, Netzwerkverbindungen usw. verknüpfen.

V UNIX-ähnliche Systeme, nach dem I/O-Modell. Jedem der Verkehrskanäle wird ein ganzzahliger Wert als Zahl zugewiesen. Allerdings für einen sicheren Zugriff. zu den oben genannten Kanälen. Dahinter sind reservierte permanente Nummern - 0, 1 und 2 für STDIN, STDOUT bzw. STDERR. Bei der Ausführung von Prozessen werden die Eingangsdaten mit STDIN gelesen. Über die Tastatur, aus der Ausgabe eines anderen Prozesses, einer Datei usw. Und Ausgabedaten (über STDOUT), sowie Fehlerdaten (über STDERR). Sie werden am Bildschirm, in einer Datei, am Eingang (bereits durch die STDIN eines anderen Prozesses) in einem anderen Programm angezeigt.

Es gibt spezielle Anweisungen in Form von Symbolen, um die Richtung von Informationskanälen zu ändern und mit Dateien zu verknüpfen<, >und >>. Also zum Beispiel die Anleitung< можно заставить направить процессу по STDIN содержимое файла. А с помощью инструкции >der Prozess auf STDOUT überträgt die Ausgabedaten in die Datei, während der gesamte Inhalt der vorhandenen Datei vollständig ersetzt wird. Wenn nicht vorhanden, wird es erstellt. Die >>-Anweisung macht dasselbe wie>, überschreibt jedoch nicht die Datei, sondern hängt die Ausgabe an deren Ende an. Um Streams zu kombinieren (dh sie an dasselbe Ziel zu leiten), müssen STDOUT und STDERR die Konstruktion > & verwenden. Um einen der Streams, zum Beispiel STDERR, an einen separaten Ort zu leiten, gibt es eine 2>-Anweisung.

Zum Verbinden zweier Kanäle miteinander. Zum Beispiel, wenn Sie die Ausgabe eines Befehls an die Eingabe eines anderen senden müssen. Verwenden Sie dazu die Anweisung (Symbol) "|". Was bedeutet die logische Operation "oder". Im Zusammenhang mit der Fadenbindung ist diese Interpretation jedoch irrelevant, was für Anfänger oft verwirrend ist. Dank dieser Fähigkeiten ist es möglich, ganze Befehlspipelines zusammenzustellen. Das macht das Arbeiten in Schalen sehr effizient.

Ausgabe in Datei

Leiten Sie die Befehlsausgabe und schreiben Sie diese Ausgabe in die Datei / tmp / somemessage:

$ echo "Dies ist eine Testnachricht"> /tmp / somemessage

In diesem Fall als Befehl, von dessen Ausgabe (über STDOUT) Daten in Form des Textes „ DiesisteinPrüfungMassage"Ist das Echo-Dienstprogramm. Als Ergebnis wird die Datei /tmp/somemessage erstellt, in der sich der Eintrag "Dies ist eine Testnachricht" befindet. Wenn die Datei nicht erstellt wurde, wird sie erstellt, wenn sie erstellt wurde, werden alle darin enthaltenen Daten überschrieben. Wenn Sie die Ausgabe an das Ende der Datei anhängen müssen, müssen Sie den Operator ">>" verwenden.

$ echo “Dies ist eine Testnachricht” >> / tmp / somemessage $ cat / tmp / somemessage Dies ist eine Testnachricht Dies ist eine Testnachricht

Wie Sie dem Beispiel entnehmen können, fügte der zweite Befehl eine Zeile am Ende der Datei hinzu.

Abrufen von Daten aus einer Datei

Das folgende Beispiel zeigt die Login-Umleitung:

$ mail -s "Mail-Test" john< /tmp/somemessage

Auf der rechten Seite des Befehls (nach dem<) находится файл-источник /tmp/somemesage, содержимое которого перенаправляется в утилиту mail (через STDIN), которая в свою очередь, имеет в качестве собственных параметров заголовок письма и адресата (john).

Mehr Beispiele

Das folgende Beispiel zeigt, warum es manchmal sehr nützlich ist, Streams von STDIN- und STDERR-Kanälen zu trennen:

$ find / -name core 2> / dev / null

Tatsache ist, dass der Befehl find / -name core Fehlermeldungen "streut" und sie standardmäßig an dieselbe Stelle wie die Suchergebnisse weiterleitet. Das heißt, im Terminal der Befehlskonsole, was die Wahrnehmung von Informationen durch den Benutzer erheblich erschwert. Denn die gesuchten Ergebnisse gehen unter den zahlreichen Fehlermeldungen im Zusammenhang mit dem Zugriffsmodus verloren. Das 2> / dev / null-Konstrukt bewirkt, dass find Fehlermeldungen (nach der STDERR-Pipe mit der reservierten Nummer 2) an das Dummy-Gerät / dev / null sendet, wobei nur die Suchergebnisse in der Ausgabe übrig bleiben.

$ find / -name core> / tmp / corefiles 2> / dev / null

Hier leitet die Konstruktion> /tmp/corefiles die Ausgabe des Find-Dienstprogramms (über die STDOUT-Pipe) in die Datei /tmp/corefiles um. Fehlermeldungen werden nach /dev/null aussortiert und erscheinen nicht in der Terminalausgabe der Shell.

So verknüpfen Sie verschiedene Kanäle für verschiedene Teams miteinander:

$fsck --help | drep M

M Eingehängte Dateisysteme nicht prüfen

Dieser Befehl druckt die Zeile (oder Zeilen), die das Zeichen "M" von der Schnellhilfeseite für das Dienstprogramm enthalten. Dies ist sehr praktisch, wenn Sie nur Informationen von Interesse anzeigen möchten. In diesem Fall empfängt das Dienstprogramm grep die Ausgabe (mit der Anweisung |) vom Befehl fsck —help. Und dann, nach dem "M"-Muster, verwirft es alles Unnötige.

Wenn Sie möchten, dass der nächste Befehl in der Pipeline erst nach vollständigem und erfolgreichem Abschluss des vorherigen Befehls ausgeführt wird, dann verwenden Sie hierfür beispielsweise die &&-Anweisung:

$ lpr / tmp / t2 && rm / tmp / page1

Dieser Befehl löscht die Datei / tmp / page1 nur, wenn der Inhalt aus der Druckwarteschlange gesendet wird. Um den gegenteiligen Effekt zu erzielen, d. h. wenn Sie den nächsten Befehl in der Pipeline erst ausführen müssen, nachdem der vorherige nicht ausgeführt wurde (wird mit einem Fehler mit einem Code ungleich Null abgeschlossen), sollten Sie || . verwenden Konstruktion.

Wenn eine Codezeile, die eine zu lange Pipeline enthält, schwer zu verstehen ist, können Sie sie mit dem umgekehrten Schrägstrich "\" zeilenweise in logische Komponenten zerlegen:

$ cp --preserve --recursive / etc / * / spare / backup \ || echo "Fehler beim Backup erstellen"

Einzelne Befehle, die nacheinander ausgeführt werden müssen, können zu einer Zeile zusammengefasst und durch den Doppelpunkt ";" getrennt werden:

Wenn Sie einen Fehler finden, wählen Sie bitte einen Text aus und drücken Sie Strg + Eingabetaste.

Ich habe eine im Internet gefunden hilfreicher Befehl um alles, was im Terminal passiert, in eine Datei zu schreiben. Sie erstellen ein vollständiges Protokoll über alle Befehle, die Sie im Terminal eingeben und was auf dem Bildschirm angezeigt wird.


Um die Aufnahme zu starten, müssen Sie den Befehl ausführen Skript... Wenn du den Befehl rufst Skript ohne Parameter, dann erfolgt die Aufnahme in eine Datei namens Typoskript.


$ Skript
Das Skript läuft, die Datei - Typoskript

Die Datei wird genau in dem Verzeichnis erstellt, in dem Sie sich befinden. Sie können den Namen des aktuellen Verzeichnisses mit dem Befehl pwd anzeigen. Wenn die Datei bereits existiert, wird sie gelöscht.


Als Parameter für den Skriptbefehl können Sie den Namen der Datei angeben, in der Sie alle Aktivitäten im Terminal aufzeichnen möchten. Anrufbeispiel:


Skript terminal.log

Nach der Eingabe des Befehls wird eine Datei erstellt, in die jedoch erst Daten geschrieben werden, wenn Sie den Exit-Befehl eingeben oder die Tastenkombination Strg + D drücken. Beispiel:


$ Skript
Das Skript wird ausgeführt, die Datei ist Typskript
$ pwd
/ Heimanwender
$ beenden
Ausfahrt
Das Skript wird ausgeführt, die Datei ist Typskript
$

Wir haben den Befehl ausgeführt Skript. Es wurde automatisch eine Datei erstellt Typoskript(wenn es bereits vorhanden war, wird es gelöscht). Von diesem Punkt an beginnt das System, alle Ein- und Ausgaben im Terminal zu speichern. Am Ende geben wir den Befehl exit ein und in eine Datei namens Typoskript alles, was ab dem Moment der Befehlseingabe im Terminal passiert ist, wird aufgezeichnet Skript.


Wenn Sie in eine vorhandene Datei schreiben möchten, müssen Sie die Option -a hinzufügen. In diesem Fall wird die Datei nicht gelöscht, sondern es werden neue Daten an den aktuellen Inhalt angehängt. Beispiel:


$ script my.log <--- Первый вызов: создается пустой файл my.log

$ ifconfig
eth0 Link encap: Ethernet HWaddr bb: aa: cc: dd: aa: bb
..
$ beenden <--- Данные записываются в файл my.log
Ausfahrt

$ script my.log -a <--- Второй вызов с опцией -a. Файл не очищается.
Das Skript läuft, die Datei ist my.log
$ pwd
/ Heimanwender
$ beenden
Ausfahrt

Das Skript wird ausgeführt, die Datei ist mein.log <--- Данные добавляются к содержимому mein.log

Es lohnt sich auch, über eine nützliche Option zu sprechen -C oder -Befehl... Mit dieser Option können Sie den auszuführenden Befehl angeben und die Ausgabe dieses Befehls in eine Datei schreiben. Beispiel:


$ script my.log -c ls
Das Skript läuft, die Datei ist my.log
my.logtemp Ubuntu OneImages
DownloadsDesktop
Das Skript wird ausgeführt, die Datei ist my.log

In diesem Beispiel nennen wir den Befehl Skript mit Option -C und geben Sie den Befehl als Optionsparameter an ls ausgeführt werden, und die Ausgabe des Befehls muss in eine Datei geschrieben werden mein.log. Befehl ls listet die Dateien im aktuellen Verzeichnis auf. Also zur Datei mein.log wird eine Liste der Dateien erhalten.


Befehlshilfe abrufen Skript(für alle seine Optionen) kann durch Ausführen im Terminal erfolgen:

Wenn Sie im Terminal arbeiten, sehen Sie natürlich die gesamte Ausgabe der Befehle in Echtzeit direkt im Terminalfenster. Es gibt jedoch Zeiten, in denen die Ausgabe gespeichert werden muss, um später damit zu arbeiten (analysieren, vergleichen usw.). Wenn Sie in Bash arbeiten, haben Sie also die Möglichkeit, die angezeigten Informationen aus dem Terminalfenster in eine Textdatei umzuleiten. Mal sehen, wie das geht.

Option 1: Nur die Terminalausgabe in eine Datei umleiten

In diesem Fall wird das gesamte Ergebnis eines Befehls in eine Textdatei geschrieben, ohne es auf dem Bildschirm anzuzeigen. Das heißt, wir leiten Informationen vom Bildschirm buchstäblich in eine Datei um. Dazu müssen Sie die Operatoren verwenden > und >> und den Pfad zu der Datei, in die geschrieben werden soll, am Ende des ausgeführten Befehls.

Operator > speichert das Ergebnis des Befehls in angegebene Datei und wenn es bereits Informationen enthält, werden diese überschrieben.

Operator >> leitet die Befehlsausgabe in eine Datei um, und wenn sie auch Informationen enthält, werden die neuen Daten am Ende der Datei angehängt.

Schauen wir uns das Beispiel des Befehls an ls die eine Liste von Dateien und Ordnern im angegebenen Verzeichnis anzeigt. Schreiben wir das Ergebnis ihrer Arbeit in eine Textdatei. Wir müssen einen Befehl schreiben, einen Operator eingeben und den Pfad zur Datei angeben:

Ls> / home / ruslan / beispiel

Mal sehen, ob alles funktioniert hat. Dazu können Sie beliebige Texteditor welche du hast. Sie können dies auch direkt im Terminal mit dem Befehl cat tun:

Katze / Zuhause / Ruslan / Beispiel

Alles arbeitet.

Erinnere dich daran " > "Überschreibt alle Daten, die sich zuvor in der Datei befanden. Wenn Sie der Datei also etwas hinzufügen müssen, verwenden Sie den Operator" >> «

Nehmen wir an, nachdem wir die Ausgabe des Befehls umgeleitet haben ls zur Datei" Beispiel »Wir haben uns entschieden, die Version des Systemkernels herauszufinden und auch die Ausgabe in derselben Datei zu speichern. Um die Kernel-Version herauszufinden, verwenden Sie den Befehl dein Name und Parameter -ein , dann teilen wir Bash mit, wie und wo das Ergebnis der Ausführung gespeichert werden soll:

Uname -a >> / home / ruslan / example

Überprüfen wir das Ergebnis noch einmal:

Katze / Zuhause / Ruslan / Beispiel

Wie Sie sehen, haben wir die Ergebnisse unserer Arbeit konserviert und ls , und dein Name .

Option 2: Leiten Sie die Ausgabe in eine Datei um und zeigen Sie sie auf dem Bildschirm an

Nicht jeder und nicht immer bequem zu bedienende Operatoren > und >> , da es noch besser ist, wenn die Aufregung von Befehlen in Echtzeit im Terminalfenster beobachtet werden kann. In diesem Fall können wir den Befehl verwenden tee , die die Ausführung von Befehlen auf dem Bildschirm anzeigt und in einer Datei speichert. Seine Syntax lautet wie folgt:

Team | T-Stück / Pfad / zu / Datei

Diese Option ähnelt dem Operator > vom vorherigen Punkt, d. h. beim Schreiben in eine Datei, werden alle alten Daten gelöscht. Wenn Sie der Datei etwas hinzufügen müssen, müssen Sie der Konstruktion den Parameter hinzufügen -ein :

Team | tee -a / Pfad / zu / Datei

Sie kennen bereits zwei Methoden, um mit der Ausgabe von Skripten zu arbeiten. Befehlszeile:

  • Zeigen Sie die Ausgabedaten auf dem Bildschirm an.
  • Umleiten der Ausgabe in eine Datei.
Manchmal muss etwas auf dem Bildschirm angezeigt und etwas in eine Datei geschrieben werden, daher müssen Sie verstehen, wie Ein- und Ausgabe in Linux gehandhabt wird müssen. Beginnen wir damit, über Standarddateideskriptoren zu sprechen.

Standarddateideskriptoren

Alles in Linux sind Dateien, einschließlich Eingabe und Ausgabe. Operationssystem identifiziert Dateien mithilfe von Deskriptoren.

Jeder Prozess darf bis zu neun offene Dateideskriptoren haben. Die Bash-Shell reserviert die ersten drei Deskriptoren, IDs 0, 1 und 2. Sie haben folgende Bedeutung.

  • 0, STDIN - Standard-Eingabedatenstrom.
  • 1, STDOUT - Standardausgabestrom.
  • 2, STDERR - Standardfehlerstrom.
Diese drei speziellen Deskriptoren verarbeiten die Skripteingabe und -ausgabe.
Sie müssen die Standard-Streams gut verstehen. Sie können mit dem Fundament verglichen werden, auf dem die Interaktion von Skripten mit der Außenwelt aufbaut. Betrachten wir die Details über sie.

STDIN

STDIN ist die Standardeingabe für die Shell. Bei einem Terminal ist die Standardeingabe die Tastatur. Wenn Skripte das Eingabeumleitungszeichen verwenden -< , Linux заменяет дескриптор файла стандартного ввода на тот, который указан в команде. Система читает файл и обрабатывает данные так, будто они введены с клавиатуры.

Viele Bash-Befehle akzeptiert Eingaben von STDIN, wenn die Befehlszeile keine Datei angibt, aus der Daten entnommen werden sollen. Dies gilt beispielsweise für den Befehl cat.

Wenn Sie cat in der Befehlszeile eingeben, ohne Parameter anzugeben, akzeptiert es Eingaben von STDIN. Nachdem Sie eine weitere Zeile eingegeben haben, druckt cat diese einfach auf den Bildschirm.

STDOUT

STDOUT ist die Standardausgabe der Shell. Standardmäßig ist dies der Bildschirm. Die meisten Bash-Befehle geben Daten an STDOUT aus, wodurch sie in der Konsole angezeigt werden. Daten können in eine Datei umgeleitet werden, indem sie mit dem Befehl >> an ihren Inhalt angehängt werden.

Wir haben also eine bestimmte Datendatei, zu der wir mit diesem Befehl andere Daten hinzufügen können:

Pwd >> myfile
Was pwd druckt, wird an myfile angehängt, während die bereits darin enthaltenen Daten nirgendwo hingehen.

Umleiten der Befehlsausgabe in eine Datei

So weit, so gut, aber was ist, wenn Sie versuchen, etwas wie das folgende zu tun, indem Sie auf eine nicht vorhandene xfile zugreifen und all dies beabsichtigen, eine Fehlermeldung in myfile zu erhalten.

Ls –l xfile> myfile
Nach der Ausführung dieses Befehls werden Fehlermeldungen auf dem Bildschirm angezeigt.


Versuch, auf eine nicht vorhandene Datei zuzugreifen

Der Versuch, auf eine nicht vorhandene Datei zuzugreifen, erzeugt einen Fehler, aber die Shell hat die Fehlermeldungen nicht an die Datei umgeleitet und sie auf dem Bildschirm angezeigt. Aber wir wollten, dass die Fehlermeldungen in die Datei gehen. Was zu tun ist? Die Antwort ist einfach – verwenden Sie den dritten Standarddeskriptor.

STDERR

STDERR ist der Standardfehlerstrom der Shell. Standardmäßig zeigt dieser Deskriptor auf dasselbe, worauf STDOUT zeigt, weshalb wir im Fehlerfall eine Meldung auf dem Bildschirm sehen.

Angenommen, Sie möchten Fehlermeldungen beispielsweise in eine Protokolldatei oder anderswo umleiten, anstatt sie auf dem Bildschirm anzuzeigen.

▍Fehlerstrom umleiten

Wie Sie bereits wissen, lautet der Dateideskriptor STDERR - 2. Wir können Fehler umleiten, indem wir diesen Deskriptor vor dem Umleitungsbefehl platzieren:

Ls -l xfile 2> myfile cat ./myfile
Die Fehlermeldung wird nun zu myfile gehen.


Umleiten einer Fehlermeldung in eine Datei

▍Umleitung von Fehler- und Ausgabeströmen

Beim Schreiben von Befehlszeilenskripts kann eine Situation auftreten, in der Sie sowohl eine Umleitung von Fehlermeldungen als auch eine Standardausgabeumleitung einrichten müssen. Um dies zu erreichen, müssen Sie die Umleitungsbefehle für die entsprechenden Deskriptoren verwenden, die die Dateien angeben, in die Fehler und Standardausgaben gehen sollen:

Ls –l myfile xfile otherfile 2> Fehlerinhalt 1> korrekter Inhalt

Umleitungsfehler und stdout

Die Shell leitet das, was der ls-Befehl normalerweise an STDOUT senden würde, dank des 1>-Konstrukts in die korrekte Inhaltsdatei um. Fehlermeldungen, die in STDERR gelandet wären, landen aufgrund des 2>-Umleitungsbefehls in der errorcontent-Datei.

Bei Bedarf können sowohl STDERR als auch STDOUT mit dem Befehl &> in dieselbe Datei umgeleitet werden:


Umleiten von STDERR und STDOUT in dieselbe Datei

Nach Ausführung des Befehls erscheint im Dateiinhalt, was für STDERR und STDOUT vorgesehen ist.

Ausgabe in Skripten umleiten

Es gibt zwei Methoden zum Umleiten der Ausgabe in Befehlszeilenskripten:
  • Temporäre Umleitung oder Umleitung der Ausgabe einer Zeile.
  • Permanentes Umleiten oder Umleiten der gesamten oder eines Teils der Ausgabe im Skript.

▍Ausgabe vorübergehend umleiten

In einem Skript können Sie die Ausgabe einer einzelnen Zeile an STDERR umleiten. Dazu genügt der Umleitungsbefehl unter Angabe des STDERR-Deskriptors und das kaufmännische Und-Zeichen (&) muss vor der Deskriptornummer stehen:

#! / bin / bash echo "Dies ist ein Fehler"> & 2 echo "Dies ist eine normale Ausgabe"
Wenn Sie das Skript ausführen, werden beide Zeilen auf dem Bildschirm angezeigt, da, wie Sie bereits wissen, standardmäßig Fehler an der gleichen Stelle wie normale Daten angezeigt werden.


Temporäre Weiterleitung

Lassen Sie uns das Skript ausführen, damit die STDERR-Ausgabe in die Datei geht.

./myscript 2> myfile
Wie Sie sehen, erfolgt nun die übliche Ausgabe an die Konsole und es werden Fehlermeldungen an die Datei gesendet.


Fehlermeldungen werden in eine Datei geschrieben

▍Permanente Ausgabeumleitung

Wenn ein Skript viel Ausgabe auf den Bildschirm umleiten muss, ist es unpraktisch, den entsprechenden Befehl zu jedem Echo-Aufruf hinzuzufügen. Stattdessen können Sie mit dem Befehl exec festlegen, dass die Ausgabe für die Dauer des Skripts an einen bestimmten Deskriptor umgeleitet wird:

#! / bin / bash exec 1> outfile echo "Dies ist ein Test zum Umleiten der gesamten Ausgabe" echo "von einem Shell-Skript in eine andere Datei." echo "ohne jede Zeile umleiten zu müssen"
Lassen Sie uns das Skript ausführen.


Alle Ausgaben in eine Datei umleiten

Wenn Sie sich die im Ausgabeumleitungsbefehl angegebene Datei ansehen, stellt sich heraus, dass alles, was von den Echo-Befehlen ausgegeben wurde, in dieser Datei gelandet ist.

Der Befehl exec kann nicht nur am Anfang des Skripts verwendet werden, sondern auch an anderen Stellen:

#! / bin / bash exec 2> myerror echo "Dies ist der Anfang des Skripts" echo "umleiten jetzt alle Ausgaben an einen anderen Ort" exec 1> myfile echo "Dies sollte in die myfile-Datei gehen" echo "und das sollte gehen zur myerror-Datei "> & 2
Dies geschieht, nachdem das Skript ausgeführt und die Dateien angezeigt wurden, an die wir die Ausgabe umgeleitet haben.


Ausgabe in verschiedene Dateien umleiten

Der Befehl exec leitet die Ausgabe von STDERR zunächst in die Datei myerror. Dann wird die Ausgabe mehrerer Echobefehle an STDOUT gesendet und auf dem Bildschirm ausgegeben. Der exec-Befehl richtet dann das Senden von allem ein, was an STDOUT an myfile geht, und schließlich verwenden wir den Befehl redirect to STDERR im echo-Befehl, der die entsprechende Zeile in myerror schreibt.

Sobald Sie dies beherrschen, sollten Sie in der Lage sein, die Ausgabe dorthin umzuleiten, wo sie hin soll. Lassen Sie uns nun über die Eingabeumleitung sprechen.

Umleiten von Eingaben in Skripten

Um Eingaben umzuleiten, können Sie dieselbe Technik verwenden, die wir zum Umleiten der Ausgabe verwendet haben. Mit dem Befehl exec können Sie beispielsweise eine Dateiquelle für STDIN erstellen:

Ausführung 0< myfile
Dieser Befehl weist die Shell an, die Eingabe von myfile zu beziehen, nicht von der normalen STDIN. Sehen wir uns die Eingabeumleitung in Aktion an:

#! / bin / bash exec 0< testfile count=1 while read line do echo "Line #$count: $line" count=$(($count + 1)) done
Dies wird auf dem Bildschirm angezeigt, nachdem das Skript ausgeführt wurde.


Umleitung von Eingaben

In einem der vorherigen Artikel haben Sie gelernt, wie Sie mit dem Lesebefehl Benutzereingaben über die Tastatur lesen. Wenn Sie die Eingabe umleiten und die Datenquelle zu einer Datei machen, liest der Lesebefehl beim Versuch, Daten aus STDIN zu lesen, diese aus der Datei und nicht aus der Tastatur.

Einige Linux-Administratoren verwenden diesen Ansatz, um Protokolldateien zu lesen und dann zu verarbeiten.

Erstellen Sie Ihre eigene Ausgabeumleitung

Beim Umleiten von Eingabe und Ausgabe in Skripten sind Sie nicht auf die drei Standarddateideskriptoren beschränkt. Wie bereits erwähnt, können Sie bis zu neun offene Deskriptoren haben. Die anderen sechs, nummeriert von 3 bis 8, können verwendet werden, um die Eingabe oder Ausgabe umzuleiten. Jeder von ihnen kann einer Datei zugewiesen und im Skriptcode verwendet werden.

Mit dem Befehl exec können Sie einen Deskriptor für die Ausgabe von Daten zuweisen:

#! /bin/bash exec 3> myfile echo "Dies sollte auf dem Bildschirm angezeigt werden" echo "und dies sollte in der Datei gespeichert werden"> & 3 echo "Und das sollte wieder auf dem Bildschirm sein"
Nach dem Ausführen des Skripts wird ein Teil der Ausgabe auf dem Bildschirm angezeigt und ein Teil der Datei mit dem Deskriptor 3.


Umleiten der Ausgabe mit einem benutzerdefinierten Deskriptor

Erstellen von Dateideskriptoren für die Dateneingabe

Sie können die Eingabe in einem Skript auf die gleiche Weise wie die Ausgabe umleiten. Speichern Sie STDIN in einem anderen Deskriptor, bevor Sie die Eingabe umleiten.

Nachdem Sie die Datei gelesen haben, können Sie STDIN wiederherstellen und wie gewohnt verwenden:

#! / bin / bash exec 6<&0 exec 0< myfile count=1 while read line do echo "Line #$count: $line" count=$(($count + 1)) done exec 0<&6 read -p "Are you done now? " answer case $answer in y) echo "Goodbye";; n) echo "Sorry, this is the end.";; esac
Lassen Sie uns das Skript testen.


Umleitung von Eingaben

In diesem Beispiel wurde der Dateideskriptor 6 verwendet, um einen Verweis auf STDIN zu speichern. Dann wurde die Eingabeumleitung durchgeführt, die Datei wurde zur Datenquelle für STDIN. Danach kam die Eingabe für den Lesebefehl aus der umgeleiteten STDIN, also aus der Datei.

Nachdem wir die Datei gelesen haben, setzen wir STDIN in den ursprünglichen Zustand zurück, indem wir es an Deskriptor 6 umleiten. Um nun zu überprüfen, ob alles richtig funktioniert, stellt das Skript dem Benutzer eine Frage, wartet auf Tastatureingaben und verarbeitet die Eingaben.

Dateideskriptoren schließen

Die Shell schließt die Dateideskriptoren automatisch, nachdem das Skript beendet wurde. In einigen Fällen ist es jedoch erforderlich, die Deskriptoren manuell zu schließen, bevor das Skript seine Arbeit beendet. Um das Handle zu schließen, muss es auf & - umgeleitet werden. Es sieht aus wie das:

#! / bin / bash exec 3> myfile echo "Dies ist eine Testzeile mit Daten"> & 3 exec 3> & - echo "Das funktioniert nicht"> & 3
Nach der Ausführung des Skripts erhalten wir eine Fehlermeldung.


Versuch, auf einen privaten Dateideskriptor zuzugreifen

Der Punkt ist, dass wir versucht haben, auf einen nicht existierenden Deskriptor zuzugreifen.

Seien Sie vorsichtig, wenn Sie Dateideskriptoren in Skripten schließen. Wenn Sie Daten an eine Datei gesendet, dann das Handle geschlossen und dann wieder geöffnet haben, überschreibt die Shell die vorhandene Datei mit der neuen. Das heißt, alles, was zuvor in diese Datei geschrieben wurde, geht verloren.

Informationen zu offenen Deskriptoren abrufen

Sie können den Befehl lsof verwenden, um eine Liste aller in Linux geöffneten Handles abzurufen. Auf vielen Distributionen wie Fedora befindet sich das Dienstprogramm lsof in /usr/sbin. Dieser Befehl ist sehr nützlich, da er Informationen zu jedem auf dem System geöffneten Handle anzeigt. Dazu gehört, was von im Hintergrund laufenden Prozessen geöffnet wird und was von angemeldeten Benutzern geöffnet wird.

Dieser Befehl hat viele Tasten, schauen wir uns die wichtigsten an.

  • -p Ermöglicht die Angabe der Prozess-ID.
  • -d Ermöglicht Ihnen, die Nummer des Deskriptors anzugeben, über den Sie Informationen abrufen möchten.
Um die PID des aktuellen Prozesses herauszufinden, können Sie ein spezielles Umgebungsvariable$$ in das die Shell die aktuelle PID schreibt.

Der Schalter -a wird verwendet, um eine logische UND-Operation an den zurückgegebenen Ergebnissen durchzuführen, indem Sie die anderen beiden Schalter verwenden:

Lsof -a -p $$ -d 0,1,2

Informationen zu offenen Deskriptoren anzeigen

Der mit STDIN, STDOUT und STDERR verknüpfte Dateityp ist CHR (Zeichenmodus). Da sie alle auf ein Terminal verweisen, stimmt der Dateiname mit dem dem Terminal zugewiesenen Gerätenamen überein. Alle drei Standarddateien stehen zum Lesen und Schreiben zur Verfügung.

Schauen wir uns den Aufruf des lsof-Befehls aus dem Skript an, in dem neben dem Standard noch andere Deskriptoren geöffnet sind:

#! / bin / bash exec 3> myfile1 exec 6> myfile2 exec 7< myfile3 lsof -a -p $$ -d 0,1,2,3,6,7
Dies geschieht, wenn Sie dieses Skript ausführen.


Vom Skript geöffnete Dateideskriptoren anzeigen

Das Skript öffnete zwei Deskriptoren für die Ausgabe (3 und 6) und einen für die Eingabe (7). Hier werden auch die Pfade zu den Dateien angezeigt, die zum Konfigurieren der Deskriptoren verwendet werden.

Ausgangsunterdrückung

Manchmal muss man dafür sorgen, dass die Befehle im Skript, die beispielsweise als Hintergrundprozess ausgeführt werden können, nichts auf dem Bildschirm anzeigen. Dazu können Sie die Ausgabe nach /dev/null umleiten. Das ist so etwas wie ein "schwarzes Loch".

So unterdrücken Sie beispielsweise Fehlermeldungen:

Ls -al badfile otherfile 2> / dev / null
Der gleiche Ansatz wird verwendet, wenn Sie beispielsweise eine Datei bereinigen müssen, ohne sie zu löschen:

Cat / dev / null> myfile

Ergebnisse

Heute haben Sie erfahren, wie Eingabe und Ausgabe bei der Befehlszeilenskripterstellung funktionieren. Jetzt wissen Sie, wie Sie mit Dateideskriptoren umgehen, sie erstellen, anzeigen und schließen, und wissen, wie Sie Eingabe-, Ausgabe- und Fehlerströme umleiten. Diese sind alle sehr wichtig bei der Entwicklung von Bash-Skripten.

Beim nächsten Mal werden wir über Linux-Signale sprechen, wie man sie in Skripten verarbeitet, wie geplante Jobs ausgeführt werden und Hintergrundaufgaben.

Liebe Leser! Dieser Artikel behandelt die Grundlagen der Arbeit mit Eingabe-, Ausgabe- und Fehlerströmen. Wir sind uns sicher, dass es unter Ihnen Profis gibt, die über all das berichten können, was nur mit Erfahrung kommt. Dann erteilen wir Ihnen das Wort.