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 +xBefehl 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 echoBefehle 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>&3statt 2> /dev/nullaller 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/shein Link zu bash ist. Aber, wenn der shebang ist #!/bin/bash, müssen Sie einen hinzufügen shopt -s expand_aliasesBefehl 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 setBefehl (mithilfe der Technik, die zuerst in der Antwort von user5071535 vorgestellt wurde ). Anschließend wird der eigentliche echoBefehl 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 -xin 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 echoBefehle:
date
echo "The quick brown fox"
echo "jumps over the lazy dog."
set -x
date
Es wäre schön, wenn wir die set -xAutomatik 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 -exShebang verwenden. Implizit könnte der Benutzer das xaus 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 echoAnweisungen bedingungslos aktivieren, ohne Rücksicht darauf, ob sie bereits aktiviert waren.
Diese Antwort erkennt das Problem auffällig nicht, da es es ersetzt echoAusgabe 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 echoAnweisung 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 eund x-Optionen festgelegt sind, handelt $-es sich um ein Durcheinander von Buchstaben, das eund 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 xOption 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 builtinSchlü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 lszu 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 builtinSchlüsselwort weggelassen wird 1 . Aber seltsamerweise funktioniert es, wenn ich die lösche builtinund 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 addressFehlermeldung und
- ein Core-Dump.
echo +x; echo "$*"; echo -xeinem Alias zu machen, würde ich es gerne sehen.