Ich führe Shell-Skripte von Jenkins aus, das Shell-Skripte mit den Shebang-Optionen startet #!/bin/sh -ex
.
EntsprechendBash Shebang für Dummies?, -x
, „bewirkt, dass die Shell einen Ausführungsverlauf druckt“, was für die meisten Zwecke großartig ist – außer für Echos:
echo "Message"
erzeugt die Ausgabe
+ echo "Message"
Message
was ein bisschen redundant ist und ein bisschen seltsam aussieht. Gibt es eine Möglichkeit, -x
aktiviert zu lassen, aber nur die Ausgabe
Message
anstelle der beiden Zeilen oben, z. B. indem Sie dem Echo-Befehl ein spezielles Befehlszeichen voranstellen oder die Ausgabe umleiten?
Antwort1
Wenn man bis zum Hals in Alligatoren steckt, vergisst man leicht, dass das Ziel darin bestand, den Sumpf trockenzulegen. — beliebtes Sprichwort
Die Frage istecho
, und dennoch konzentrierte sich die Mehrheit der bisherigen Antworten darauf, wie man einen set +x
Befehl einschmuggelt. Es gibt eine viel einfachere, direktere Lösung:
{ echo "Message"; } 2> /dev/null
(Ich gebe zu, dass ich möglicherweise nicht daran gedacht hätte, { …; } 2> /dev/null
wenn ich es nicht in den früheren Antworten 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 Befehl 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 Tippaufwand verringern, indem Siekenorbs Idee/dev/null
dauerhaft mit einem nicht standardmäßigen Dateideskriptor (z. B. 3) zu öffnen und dann ständig „ 2>&3
stattdessen“ zu sagen.2> /dev/null
Die ersten vier Antworten zum Zeitpunkt des Schreibens dieses Artikels erfordern etwas Besonderes (und in den meisten Fällen Umständliches)
jedenecho
Wenn du wirklich willst ,alle echo
Befehle zum Unterdrücken der Ausführungsverfolgung (und warum sollten Sie das nicht tun?), können Sie dies global tun, ohne viel Code zu verändern. Zuerst fiel mir auf, 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 folgenden Skriptausschnitte funktionieren, wenn der Shebang lautet #!/bin/sh
, auch wenn es /bin/sh
sich um einen Link zu Bash handelt. Wenn der Shebang jedoch lautet #!/bin/bash
, müssen Sie einen shopt -s expand_aliases
Befehl hinzufügen, damit Aliase in einem Skript funktionieren.)
Also, mein erster 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-Meldung des set
Befehls (mit der Technik, die zuerst inAntwort von user5071535) und führt dann den eigentlichen echo
Befehl aus. Dadurch können wir einen ähnlichen Effekt wie in der Antwort von user5071535 erzielen, ohne den Code bearbeiten zu müssen.jeden echo
Befehl. Allerdings bleibt der Trace-Modus dabei ausgeschaltet. Wir können kein set -x
in den Alias einfügen (oder zumindest nicht einfach), da ein Alias nur das Ersetzen eines Wortes durch eine Zeichenfolge erlaubt; kein Teil der Alias-Zeichenfolge kann in den Befehl eingefügt werden.
nachdie Argumente (z. B. "Message"
). Wenn das Skript beispielsweise 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
Sie müssen die Trace-Option also immer noch nach der Anzeige der Nachricht(en) wieder einschalten — aber nur einmal nach jedemBlockaufeinanderfolgender echo
Befehle:
date
echo "The quick brown fox"
echo "jumps over the lazy dog."
set -x
date
Es wäre nettset -x
wenn wir die automatische nach einem machen könnten echo
– und das können wir, mit ein bisschen mehr Trickserei. Aber bevor ich das vorstelle, bedenken Sie Folgendes. Der OP beginnt mit Skripten, die ein #!/bin/sh -ex
Shebang verwenden. Implizit könnte der Benutzer das x
aus dem Shebang entfernen und ein Skript haben, das normal funktioniert, ohne Ausführungsverfolgung. Es wäre schön, wenn wir eine Lösung entwickeln könnten, die diese Eigenschaft beibehält. Die ersten paar Antworten hier erfüllen diese Eigenschaft nicht, weil sie die Verfolgung nach Anweisungen bedingungslos „wieder“ einschalten echo
, ohne Rücksicht darauf, ob sie bereits eingeschaltet war.
Diese Antworterkennt dieses Problem offensichtlich nicht an, da esersetzt echo
Ausgabe mit Trace-Ausgabe; daher verschwinden alle Nachrichten, wenn das Tracing ausgeschaltet wird. Ich werde jetzt eine Lösung vorstellen, die das Tracing nach einer echo
Anweisung wieder einschaltetbedingt— nur wenn es bereits eingeschaltet war. Dies auf eine Lösung herunterzustufen, die das Tracing bedingungslos „wieder“ einschaltet, ist trivial und bleibt eine Übung.
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 Optionen e
und x
festgelegt sind, $-
wird ein Buchstabensalat mit e
und angezeigt x
. Mein neuer Alias (oben) speichert den Wert von , $-
bevor die Ablaufverfolgung deaktiviert wird. Wenn die Ablaufverfolgung deaktiviert ist, übergibt er die Kontrolle an eine Shell-Funktion. Diese Funktion führt die eigentliche Operation aus echo
und prüft dann, ob die x
Option aktiviert war, als der Alias aufgerufen wurde. Wenn die Option aktiviert war, aktiviert die Funktion sie wieder; wenn sie deaktiviert war, lässt die Funktion sie deaktiviert.
Sie können die obigen sieben Zeilen (acht, wenn Sie ein einfügen shopt
) am Anfang des Skripts einfügen und den Rest so lassen, wie er ist.
Dies würde Ihnen ermöglichen
- um eine der folgenden Shebang-Zeilen zu verwenden:
#!/bin/sh -ex #!/bin/sh -e #!/bin/sh –x
oder einfach nur#!/bin/sh
und es sollte wie erwartet funktionieren. - Code haben wie
(Kram) 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 davon ist ein
echo
. In diesem Fall wird er ausgeführt, aber nicht verfolgt. (Aber auch wenn Befehl 5 ein istecho
, wird Befehl 6 trotzdem verfolgt.) - Die Befehle 7, 8 und 9 werden nicht verfolgt. Auch wenn Befehl 8 ein ist
echo
, wird Befehl 9 trotzdem nicht verfolgt. - Die Befehle 1, 2 und 3 werden verfolgt (wie 4, 5 und 6) oder nicht (wie 7, 8 und 9), je nachdem, ob der Shebang enthält
x
.
- Die Befehle 4, 5 und 6 werden verfolgt – es sei denn, einer davon ist ein
builtin
PS: Ich habe festgestellt, dass ich auf meinem System das Schlüsselwort in meiner mittleren Antwort (das nur ein Alias für ist ) weglassen kann echo
. Das ist nicht überraschend; bash(1) sagt, dass während der Aliaserweiterung …
… ein Wort, das mit einem zu erweiternden Alias identisch ist, wird nicht ein zweites Mal erweitert. Das bedeutet, dass man einen Alias verwenden kann
ls
Zuls -F
, und Bash versucht nicht, den Ersetzungstext rekursiv zu erweitern.
Wenig überraschend schlägt die letzte Antwort (die mit echo_and_restore
) fehl, wenn das builtin
Schlüsselwort 1 weggelassen wird . Aber seltsamerweise funktioniert es, wenn ich das 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 aufgrund unbegrenzter Rekursion),
- eine
/dev/null: Bad address
Fehlermeldung und - ein Core Dump.
Antwort2
Ich habe eine Teillösung gefunden beiInformierenIT:
#!/bin/bash -ex
set +x;
echo "shell tracing is disabled here"; set -x;
echo "but is enabled here"
Ausgänge
set +x;
shell tracing is disabled here
+ echo "but is enabled here"
but is enabled here
Leider hallt es immer noch set +x
, aber danach ist immerhin Ruhe. Es ist also zumindest eine Teillösung des Problems.
Aber gibt es vielleicht einen besseren Weg, das zu tun? :)
Antwort3
set +x
Auf diese Weise verbessern Sie Ihre eigene Lösung, indem Sie die Ausgabe entfernen :
#!/bin/bash -ex
{ set +x; } 2>/dev/null
echo "shell tracing is disabled here"; set -x;
echo "but is enabled here"
Antwort4
Setzen Sie es set +x
in Klammern, sodass es nur für den lokalen Bereich gilt.
Zum Beispiel:
#!/bin/bash -x
exec 3<> /dev/null
(echo foo1 $(set +x)) 2>&3
($(set +x) echo foo2) 2>&3
( set +x; echo foo3 ) 2>&3
true
würde ausgeben:
$ ./foo.sh
+ exec
foo1
foo2
foo3
+ true