Wenn Sie mit Alligatoren bis zum Hals sind, können Sie leicht vergessen, dass das Ziel darin bestand, den Sumpf zu entwässern.
- beliebtes Sprichwort
Es geht um die Frage echo
, und doch haben sich die meisten Antworten bisher darauf konzentriert, wie ein set +x
Befehl eingegeben werden kann . Es gibt eine viel einfachere und direktere Lösung:
{ echo "Message"; } 2> /dev/null
(Ich gebe zu, dass ich vielleicht nicht daran gedacht hätte, { …; } 2> /dev/null
wenn ich es in den früheren Antworten nicht gesehen hätte.)
Dies ist etwas umständlich, aber wenn Sie einen Block aufeinanderfolgender echo
Befehle haben, müssen Sie dies nicht für jeden einzeln tun:
{
echo "The quick brown fox"
echo "jumps over the lazy dog."
} 2> /dev/null
Beachten Sie, dass Sie bei Zeilenumbrüchen keine Semikolons benötigen.
Sie können den Aufwand für die Eingabe verringern, indem Sie Kenorbs Idee verwenden,/dev/null
dauerhaft in einem nicht standardmäßigen Dateideskriptor (z. B. 3) zu
öffnen und dann 2>&3
statt 2> /dev/null
aller Zeiten zu sagen .
Die ersten vier Antworten zum Zeitpunkt des Schreibens erfordern, dass Sie jedes Mal etwas Besonderes tun (und in den meisten Fällen umständlich),
wenn Sie eine echo
. Wenn Sie wirklich möchten, dass alle echo
Befehle die Ausführungsablaufverfolgung unterdrücken (und warum nicht?), Können Sie dies global tun, ohne viel Code zu mischen. Erstens habe ich festgestellt, dass Aliase nicht verfolgt werden:
$ myfunc()
> {
> date
> }
$ alias myalias="date"
$ set -x
$ date
+ date
Mon, Oct 31, 2016 0:00:00 AM # Happy Halloween!
$ myfunc
+ myfunc # Note that function call is traced.
+ date
Mon, Oct 31, 2016 0:00:01 AM
$ myalias
+ date # Note that it doesn’t say + myalias
Mon, Oct 31, 2016 0:00:02 AM
(Beachten Sie, dass die Arbeit Schnipsel folgenden Skript , wenn der shebang ist #!/bin/sh
, auch wenn /bin/sh
ein Link zu bash ist. Aber, wenn der shebang ist #!/bin/bash
, müssen Sie einen hinzufügen shopt -s expand_aliases
Befehl Aliase Arbeit in einem Skript zu erhalten.)
Also für meinen ersten Trick:
alias echo='{ set +x; } 2> /dev/null; builtin echo'
Wenn wir jetzt sagen echo "Message"
, rufen wir den Alias auf, der nicht verfolgt wird. Der Alias deaktiviert die Trace-Option und unterdrückt gleichzeitig die Trace-Nachricht aus dem set
Befehl (mithilfe der Technik, die zuerst in der Antwort von user5071535 vorgestellt wurde ). Anschließend wird der eigentliche echo
Befehl ausgeführt. Auf diese Weise erhalten wir einen ähnlichen Effekt wie bei der Antwort von user5071535, ohne den Code bei jedem echo
Befehl bearbeiten zu müssen . Der Trace-Modus bleibt jedoch deaktiviert. Wir können kein set -x
in den Alias setzen (oder zumindest nicht leicht), weil ein Alias nur erlaubt, dass ein Wort durch einen String ersetzt wird; Nach den Argumenten (z "Message"
. B. ) kann kein Teil der Alias-Zeichenfolge in den Befehl
eingefügt werden . So zum Beispiel, wenn das Skript enthält
date
echo "The quick brown fox"
echo "jumps over the lazy dog."
date
die Ausgabe wäre
+ date
Mon, Oct 31, 2016 0:00:03 AM
The quick brown fox
jumps over the lazy dog.
Mon, Oct 31, 2016 0:00:04 AM # Note that it doesn’t say + date
Daher müssen Sie die Trace-Option nach dem Anzeigen von Nachrichten immer noch wieder aktivieren - jedoch nur einmal nach jedem Block aufeinanderfolgender echo
Befehle:
date
echo "The quick brown fox"
echo "jumps over the lazy dog."
set -x
date
Es wäre schön, wenn wir die set -x
Automatik nach einem echo
- und wir können, mit etwas mehr Trick. Aber bevor ich das präsentiere, denke ich darüber nach. Das OP beginnt mit Skripten, die einen #!/bin/sh -ex
Shebang verwenden. Implizit könnte der Benutzer das x
aus dem shebang entfernen und ein Skript haben, das ohne Ausführungsverfolgung normal funktioniert. Es wäre schön, wenn wir eine Lösung entwickeln könnten, die diese Eigenschaft beibehält. Die ersten Antworten hier scheitern an dieser Eigenschaft, weil sie das Zurückverfolgen nach echo
Anweisungen bedingungslos aktivieren, ohne Rücksicht darauf, ob sie bereits aktiviert waren.
Diese Antwort erkennt das Problem auffällig nicht, da es es ersetzt echo
Ausgabe mit Trace-Ausgabe; Daher verschwinden alle Nachrichten, wenn die Ablaufverfolgung deaktiviert wird. Ich werde jetzt eine Lösung vorstellen, die die Rückverfolgung nach einer echo
Anweisung unter bestimmten Bedingungen aktiviert - nur wenn sie bereits aktiviert war. Die Herabstufung auf eine Lösung, die das bedingungslose Zurückverfolgen aktiviert, ist trivial und wird als Übung behandelt.
alias echo='{ save_flags="$-"; set +x;} 2> /dev/null; echo_and_restore'
echo_and_restore() {
builtin echo "$*"
case "$save_flags" in
(*x*) set -x
esac
}
$-
ist die Optionsliste; eine Verkettung der Buchstaben, die allen festgelegten Optionen entsprechen. Wenn beispielsweise die e
und x
-Optionen festgelegt sind, handelt $-
es sich um ein Durcheinander von Buchstaben, das e
und enthält x
. Mein neuer Alias (oben) speichert den Wert von, $-
bevor die Ablaufverfolgung deaktiviert wird. Wenn die Ablaufverfolgung deaktiviert ist, wird die Steuerung in eine Shell-Funktion umgewandelt. Diese Funktion führt die eigentliche Aktion aus echo
und prüft dann, ob die x
Option beim Aufrufen des Alias aktiviert war. Wenn die Option aktiviert war, wird sie durch die Funktion wieder aktiviert. Wenn es ausgeschaltet war, lässt die Funktion es ausgeschaltet.
Sie können die obigen sieben Zeilen (acht, wenn Sie einschließen shopt
) am Anfang des Skripts einfügen und den Rest in Ruhe lassen.
Dies würde es Ihnen erlauben
- eine der folgenden Shebang-Linien verwenden:
#! / bin / sh -ex
#! / bin / sh -e
#! / bin / sh –x
oder einfach nur#! / bin / sh
und es sollte wie erwartet funktionieren.
- Code haben wie
(shebang)
befehl 1
befehl 2
befehl 3
setze -x
befehl 4
befehl 5
befehl 6
setze + x
befehl 7
befehl 8
befehl 9
und
- Die Befehle 4, 5 und 6 werden verfolgt - es sei denn, einer von ihnen ist ein
echo
. In diesem Fall wird er ausgeführt, aber nicht verfolgt. (Aber auch wenn Befehl 5 ein ist echo
, wird Befehl 6 trotzdem verfolgt.)
- Befehle 7, 8 und 9 werden nicht verfolgt. Auch wenn Befehl 8 ein ist
echo
, wird Befehl 9 immer noch nicht verfolgt.
- Die Befehle 1, 2 und 3 werden nachverfolgt (wie 4, 5 und 6) oder nicht (wie 7, 8 und 9), je nachdem, ob der Shebang beinhaltet
x
.
PS Ich habe festgestellt, dass ich auf meinem System das builtin
Schlüsselwort in meiner mittleren Antwort weglassen kann (die, die nur ein Alias für ist echo
). Das ist nicht überraschend. Bash (1) sagt, dass während der Alias-Erweiterung ...
… Ein Wort, das mit einem erweiterten Alias identisch ist, wird kein zweites Mal erweitert. Dies bedeutet , dass man kann alias ls
zu ls -F
, zum Beispiel, und bash versucht nicht rekursiv den Ersatztext zu erweitern.
Es überrascht nicht, dass die letzte Antwort (die mit echo_and_restore
) fehlschlägt, wenn das builtin
Schlüsselwort weggelassen wird 1 . Aber seltsamerweise funktioniert es, wenn ich die lösche builtin
und die Reihenfolge ändere:
echo_and_restore() {
echo "$*"
case "$save_flags" in
(*x*) set -x
esac
}
alias echo='{ save_flags="$-"; set +x;} 2> /dev/null; echo_and_restore'
__________
1 Es scheint zu undefiniertem Verhalten zu führen. Ich habe gesehen
- eine Endlosschleife (wahrscheinlich wegen unbegrenzter Rekursion),
- eine
/dev/null: Bad address
Fehlermeldung und
- ein Core-Dump.
echo +x; echo "$*"; echo -x
einem Alias zu machen, würde ich es gerne sehen.