Warum schlägt "exec 2> & 1" in diesem Bourne-Shell-Skript fehl?

7

Ich portiere ein altes ksh-Skript auf die Bourne-Shell. Das alte ksh-Skript enthält den folgenden Code:

#!/bin/sh

tmpLog=/var/tmp/logfile.$$

exec 1> $tmpLog
exec 2>&1

eval $*
another_command_1
another_command_2

Nach dem, was ich gelesen habe, sollen diese beiden exec-Anweisungen $ *, einen anderen_Befehl_1, einen anderen_Befehl_2 und alle folgenden Befehle ausführen. und leiten Sie dann alle STDERR und STDOUT von diesen Befehlen nach um /var/tmp/logfile.$$. Wenn ich dies jedoch in einem Skript ausführe, schlägt das Skript danach fehl exec 2>&1.

stefanl@host:~ $ sh -xv ./output.sh echo "Hello"
#!/bin/sh

tmpLog=/var/tmp/logfile.$$
+ tmpLog=/var/tmp/logfile.39918

exec 1> $tmpLog
+ exec
exec 2>&1
+ exec
stefanl@host:~ $

Und wenn ich dies über die Befehlszeile ausführe, friert meine Shell ein, nachdem ich Folgendes ausgeführt habe exec 2>&1:

stefanl@host:~ $ tmpLog=/var/tmp/logfile.$$
stefanl@host:~ $ exec 1> $tmpLog
stefanl@host:~ $ exec 2>&1
### FREEZE ###

Meine Fragen:

  1. Was exec 2>&1soll tun?
  2. Warum scheitert es für mich?
Stefan Lasiewski
quelle

Antworten:

16

Ihr Skript schlägt nicht fehl - es funktioniert einwandfrei. Ihr Verständnis ist insofern richtig, als es exec >logfile; exec 2>&1sowohl die Standardausgabe als auch den Standardfehler an weiterleitet logfile. Sie sollten also in der Protokolldatei und nicht in Ihrem Terminal nach Ausgabe und Fehler suchen. Wenn Sie diese Umleitungen direkt in Ihrer aktuellen Shell ausführen, scheint Ihre Shell eingefroren zu sein, da Sie die gesamte Ausgabe von Ihrem Terminal weggeschickt haben.

Beachten Sie, dass die Ausgabe der Option xtrace( set -x) auch zum Standardfehler führt, bei dem es sich immer um den Dateideskriptor 2 handelt, den Sie an die Protokolldatei gesendet haben. Sie sollten den Rest nach dem exec 2>&1in dort finden.

jw013
quelle
Ah danke! Und wenn ich ein neues Fenster öffne und ein mache, tail -f /var/tmp/logfile.39918sehe ich alles, was ich in das alte Fenster tippe. Cleverer Trick!
Stefan Lasiewski
1
"... sendet sowohl Standardausgabe als auch Standardeingabe an logfile, ..." sollte "Standardausgabe und Standardfehler " sein . Ich werde bearbeiten, um die Korrektur vorzunehmen.
Kevin Fegan
4

Diese Form von exec (dh ohne Befehl) wird verwendet, um alle nachfolgenden Ausgaben des aktuellen Shell-Interpreters umzuleiten.

von Bashs eingebauter Hilfe:

$ help exec
exec: exec [-cl] [-a Name] [Befehl [Argumente ...]] [Umleitung ...]
    Ersetzen Sie die Shell durch den angegebenen Befehl.

    Führen Sie COMMAND aus und ersetzen Sie diese Shell durch das angegebene Programm.
    ARGUMENTE werden zu Argumenten für COMMAND. Wenn COMMAND nicht angegeben ist,
    Alle Umleitungen werden in der aktuellen Shell wirksam.
    [...]

Ich verwende exec &> logfile , um stdout und stderr gleichzeitig umzuleiten. ZB beginnen die meisten meiner Backup- und Rsync-Wrapper-Skripte (oder jedes Skript, das viele Ausgaben erzeugt, die ich später genauer untersuchen möchte) mit etwa dem folgenden:

BNAME=$(basename "$0" .sh)
LOGFILE="/tmp/$BNAME.log"
savelog "$LOGFILE"
exec &> "$LOGFILE"

Ich führe das Skript dann von cron oder im Hintergrund aus und verwende es tail -F, um die Protokolldatei zu beobachten, während das Skript ausgeführt wird. Mit dem Savelog kann ich die Ausgabe der letzten 7 Läufe beibehalten (standardmäßig 7, savelog -cum dies zu ändern).

cas
quelle
Die Frage richtet sich speziell an die Bourne-Shell. Bourne hat weder den &>Operator noch ist das Zitieren der bashManpage fürchterlich hilfreich. Der Teil über Cron ist irrelevant.
jw013
Seine erste Frage "Was soll exec 2> & 1 tun?" Wurde immer noch klar beantwortet, die noch nicht beantwortet worden war. Die Annahme einer vernünftigen Fähigkeit zum Verstehen, Verallgemeinern und Extrapolieren verdient keine -1. Ich neige dazu, eine allgemeine Frage lieber allgemein zu erklären als nur Frachtkultmagie. Übrigens, es war die Bash-Hilfe, nicht die Bash-Manpage ... es war einfach die bequemste und prägnanteste Dokumentation, und der relevante Punkt zum Inkrafttreten in der aktuellen Shell gilt für alle Versionen von sh.
Cas
Ich sehe keinen Teil in Ihrer Antwort, der speziell erklärt, was exec 2>&1tut? Ich stimme Antworten, die explizit oder implizit zu Missverständnissen führen (in Ihrem Fall impliziert sh= bash), generell ab , weil nicht jede Person, die Ihre Antwort in Zukunft liest, den Unterschied kennt. bash basiert auf sh, aber in der Praxis gibt es viele Unterschiede (wie das &>: Wenn man das in ein Bourne-Shell-Skript einfügt, wird es wahrscheinlich kaputt gehen). Außerdem ist bash execwahrscheinlich keine der akzeptierten Optionen gültig.
jw013
Mein erster Satz erklärt es. Ebenso wie der letzte Satz in der Bash-Hilfeausgabe. Der Rest ist ein Beispiel dafür, warum und wie eine solche Funktion verwendet werden kann - warum und wie normalerweise in Manpages und anderem Referenzmaterial weggelassen wird.
Cas
1
F. "Was soll exec 2> & 1 tun?" A. "Diese Form der Ausführung (dh ohne Befehl) wird verwendet, um [...]". In diesem Satz gibt es keine Verwechslung zwischen bash und sh. Es gilt für alle Varianten von sh. Sie haben seine erste Frage ignoriert und seine zweite beantwortet, ich habe seine zweite ignoriert und seine erste beantwortet. Sie beurteilen meine Antwort nach der Frage, die Sie beantwortet haben, nicht nach der, die ich beantwortet habe.
Cas