Was macht dieser Befehl?
exec 2>&1
Technisch gesehen kopiert oder kopiert er stderr auf stdout.
Normalerweise brauchen Sie den Exec nicht, um dies durchzuführen. Eine typischere Verwendung von exec bei Dateideskriptoren besteht darin, anzugeben, dass Sie eine Datei einem nicht verwendeten Dateideskriptor zuordnen möchten, z.
ls > mydirlist 2>&1
funktioniert, weil es sowohl stdout als auch stderr auf die Datei mydirlist verweist, während der Befehl
ls 2>&1 > mydirlist
weist nur stdout und nicht stderr an, mydirlist zu archivieren, da stderr eine Kopie von stdout gemacht wurde, bevor stdout zu mydirlist umgeleitet wurde.
Edit: So scannt die Shell von links nach rechts. Lesen Sie also die zweite als "copy stderr auf stdout", bevor sie "send stdout an mydirlist" aussagt. Lesen Sie dann den ersten Satz mit der Überschrift "Sende stdout an die Datei mydirlist", bevor er sagt "Duplizieren Sie stderr auf den von mir eingerichteten stdout". Ich kenne. Es ist absolut nicht intuitiv!
Einer der besseren Artikel, die ich auf "2> & 1" gesehen habe, ist Bash One-Liner erklärt, Teil III: Alles über Weiterleitungen .
Was die aktuellen Antworten auf diese Frage jedoch nicht liefern, ist, warum Sie dies nach einem einfachen "exec" tun möchten. Wie die bash-Manpage für den exec-Befehl erläutert: "Wenn der Befehl nicht angegeben ist, werden Umleitungen in der aktuellen Shell wirksam.".
Ich habe ein einfaches Skript namens out-and-err.py
geschrieben, das eine Ausgabezeile in stdout und eine weitere Zeile in stderr schreibt:
#!/usr/bin/python
import sys
sys.stdout.write('this is stdout.\n')
sys.stderr.write('this is stderr.\n')
Und dann habe ich das in ein Shell-Skript namens out-and-err.sh mit "exec 2> & 1" verpackt:
#!/bin/bash
exec 2>&1
./out-and-err.py
Wenn ich nur das Python-Skript ausführe, sind stdout und stderr getrennt:
$ ./out-and-err.py 1> out 2> err
$ cat out
this is stdout.
$ cat err
the is stderr.
Wenn ich jedoch das Shell-Skript starte, können Sie sehen, dass der Exec für alles nach stderr sorgt:
$ ./out-and-err.sh 1> out 2> err
$ cat out
this is stdout.
this is stderr.
$ cat err
$
Wenn Ihr Shell-Wrapping-Skript mehr als nur einen einzigen Python-Befehl ausführt und Sie die gesamte Ausgabe in stdout kombinieren müssen, wird Ihnen das Ausführen von "exec 2> & 1" leicht fallen.
Es verbindet Standardfehler mit Standardausgang
der 2
ist stderr und 1
ist stdout. Wenn Sie ein Programm ausführen, erhalten Sie die normale Ausgabe in stdout, aber Fehler oder Warnungen gehen normalerweise an stderr. Wenn Sie beispielsweise die gesamte Ausgabe an eine Datei übergeben möchten, ist es nützlich, stderr zuerst mit stdout mit 2>&1
zu kombinieren.
Wie @cma sagte, wird stderr auf stdout gesetzt. Möglicherweise möchten Sie dieses Verhalten, indem Sie grep oder ein anderes Dienstprogramm verwenden, um Ausgaben zu erfassen, die nur in stderr angezeigt werden. Oder Sie möchten vielleicht nur die gesamte Ausgabe, einschließlich stderr, für eine spätere Verarbeitung in einer Datei speichern.
An diesem Tag war ich auch an diesem Problem scheiße, aber jetzt springe ich aus ihm heraus ... Bitte erlauben Sie mir zu erklären, was passiert, nachdem Sie exec 1>&2
in CLI eingegeben haben.
Ich möchte das Problem Stück für Stück zerstören. Wenn Sie also das Wissen bereits kennen, überfliegen Sie es einfach, um Zeit zu sparen.
exec
steht für:exec
ist ein in Linux integrierter Befehl. Anders als der traditionelle Befehl, der nur einen Unter-Shell-Prozess umfasst, könnte exec
den aktuellen Shell-Prozess ändern.
Was ist eine E/A-Umleitung: Umleitung ist eine Funktion in Linux. Hiermit können Sie die Standard-Ein-/Ausgabegeräte ändern. In Linux gibt es standardmäßig drei Dateideskriptoren .
Handle Name Description
0 stdin Standard input
1 stdout Standard output
2 stderr Standard error
Lass mich ein Beispiel sehen:
$ pstree -p | grep 'term' | tr -d ' '
$ Sudo ls -l /proc/{pid}/fd
bash
$ pstree -p | grep -i 'terminal' | tr -d ' '
||||-gnome-terminal-(6008)-+-bash(7641)-+-grep(8355)
$ Sudo ls -l /proc/7641/fd
total 0
lrwx------ 1 alopex alopex 64 Oct 27 19:39 0 -> /dev/pts/3
lrwx------ 1 alopex alopex 64 Oct 27 19:39 1 -> /dev/pts/3
lrwx------ 1 alopex alopex 64 Oct 27 19:39 2 -> /dev/pts/3
lrwx------ 1 alopex alopex 64 Oct 27 19:39 255 -> /dev/pts/3
Wie Sie sehen, listet die Variable ls
die PID-Prozessdatei (6860) auf. Zuerst benennen sie alle nach der Nummer (0, 1, 2), zweitens verknüpfen sie alle mit/dev/pts/3, was bedeutet, dass alle Standardeingaben/-ausgänge/-fehler in pts3 angezeigt werden.bash
$ ls /tmp/stdout
ls: cannot access '/tmp/stdout': No such file or directory
$ exec 1>/tmp/stdout
$ ls
$ pwd
$ echo "Are you ok"
$
Die Befehlsausgabe war zu diesem Zeitpunkt verschwunden.bash
$ Sudo ls -l /proc/7641/fd
total 0
lrwx------ 1 alopex alopex 64 Oct 27 19:39 0 -> /dev/pts/3
lrwx------ 1 alopex alopex 64 Oct 27 19:39 1 -> /tmp/stdout
lrwx------ 1 alopex alopex 64 Oct 27 19:39 2 -> /dev/pts/3
lrwx------ 1 alopex alopex 64 Oct 27 19:39 255 -> /dev/pts/3
Offensichtlich können wir feststellen, dass die 1 (Dateideskriptor) bereits den Link zu/tmp/stdout ändert. Bei uns wird die Standardausgabe nach/tmp/stdout übertragenbash
$ exec 1>&2
$ cat /tmp/stdout
a.sh
/home/alopex
Are you ok
$ Sudo ls -l /proc/7641/fd
total 0
lrwx------ 1 alopex alopex 64 Oct 27 19:39 0 -> /dev/pts/3
lrwx------ 1 alopex alopex 64 Oct 27 19:39 1 -> /dev/pts/3
lrwx------ 1 alopex alopex 64 Oct 27 19:39 2 -> /dev/pts/3
lrwx------ 1 alopex alopex 64 Oct 27 19:39 255 -> /dev/pts/3
.__ wieder her. Wiederum die Verknüpfung 1 (Dateideskriptor) zu/dev/pts/3, können Sie die Ausgabe erneut sehen.Zusammenfassung:
exec 1>&2
macht die Standardausgabe ---> StandardfehlerEine recht nützliche Anwendung von exec 2>&1
, die ich gefunden habe, ist, wenn Sie stderr
und stdout
für mehrere durch Semikola getrennte Befehle zusammenführen möchten. Mein spezielles Beispiel geschah, als ich in PHP mehr als einen Befehl an popen
sendete und wollte, dass die Fehler verschachtelt angezeigt wurden, als würden Sie die Befehle an einem Shell-Prompt eingeben:
$ echo hi ; yikes ; echo there
hi
-bash: yikes: command not found
there
$
Folgendes fasst nicht stderr
und stdout
zusammen, außer der letzten echo
(was sinnlos ist, da die yikes
den Fehler verursacht):
echo hi ; yikes ; echo there 2>&1
Ich kann die zusammengeführte Ausgabe auf "harte Weise" wie folgt erhalten:
echo hi 2>&1; yikes 2>&1; echo there 2>&1
Es sieht viel sauberer und weniger fehleranfällig aus, wenn Sie exec
verwenden:
exec 2>&1 ; echo hi; echo yikes; echo there
Sie erhalten die Ausgabe von stdout
und stderr
genau so, wie Sie es auf dem Terminal sehen würden, wenn Sie die drei durch ein Semikolon getrennten Befehle ausführen.