Laut Bash-HandbuchBASH_COMMAND
enthält die Umgebungsvariable
Der Befehl, der gerade ausgeführt wird oder gerade ausgeführt wird, es sei denn, die Shell führt einen Befehl als Ergebnis eines Traps aus. In diesem Fall handelt es sich um den Befehl, der zum Zeitpunkt des Traps ausgeführt wird.
Wenn ich den Fall der Trap-Ecke beiseite lasse, bedeutet dies, dass die Variable BASH_COMMAND
diesen Befehl enthält, wenn ich einen Befehl ausführe . Es ist nicht absolut klar, ob diese Variable nach der Befehlsausführung nicht gesetzt ist (dh nur verfügbar ist, während der Befehl ausgeführt wird, aber nicht danach), obwohl man argumentieren könnte, dass es sich um "den Befehl handelt, der gerade ausgeführt wird oder gerade ausgeführt wird". , es ist nicht der Befehl , der gerade ausgeführt wurde.
Aber lasst uns prüfen:
$ set | grep BASH_COMMAND=
$
Leeren. Ich hätte erwartet, zu sehen BASH_COMMAND='set | grep BASH_COMMAND='
oder vielleicht nur BASH_COMMAND='set'
, aber leer hat mich überrascht.
Versuchen wir etwas anderes:
$ echo $BASH_COMMAND
echo $BASH_COMMAND
$
Na das macht Sinn. Ich führe den Befehl aus echo $BASH_COMMAND
und so BASH_COMMAND
enthält die Variable die Zeichenfolge echo $BASH_COMMAND
. Warum hat es diesmal funktioniert, aber nicht vorher?
Lass uns das set
Ding nochmal machen:
$ set | grep BASH_COMMAND=
BASH_COMMAND='echo $BASH_COMMAND'
$
Also warte. Es wurde gesetzt, als ich diesen echo
Befehl ausführte , und es wurde danach nicht aufgehoben. Aber als ich set
nochmal ausführte , BASH_COMMAND
wurde nicht auf den set
Befehl gesetzt. Egal wie oft ich den set
Befehl hier ausführe , das Ergebnis bleibt gleich. Ist die Variable also beim Ausführen gesetzt echo
, aber nicht beim Ausführen set
? Wir werden sehen.
$ echo Hello AskUbuntu
Hello AskUbuntu
$ set | grep BASH_COMMAND=
BASH_COMMAND='echo $BASH_COMMAND'
$
Was? Also wurde die Variable gesetzt, als ich ausgeführt habe echo $BASH_COMMAND
, aber nicht, als ich ausgeführt habe echo Hello AskUbuntu
? Wo ist jetzt der Unterschied? Wird die Variable nur gesetzt, wenn der aktuelle Befehl selbst die Shell zwingt, die Variable auszuwerten? Versuchen wir etwas anderes. Vielleicht ein externes Kommando, diesmal kein eingebauter Bash.
$ /bin/echo $BASH_COMMAND
/bin/echo $BASH_COMMAND
$ set | grep BASH_COMMAND=
BASH_COMMAND='/bin/echo $BASH_COMMAND'
$
Hmm, ok ... wieder wurde die Variable gesetzt. Ist meine derzeitige Vermutung also richtig? Wird die Variable nur gesetzt, wenn sie ausgewertet werden muss? Warum? Warum? Aus Performancegründen? Versuchen wir es noch einmal. Wir werden versuchen, nach $BASH_COMMAND
in einer Datei zu suchen , und da $BASH_COMMAND
sollte dann ein grep
Befehl enthalten sein , grep
sollte nach diesem grep
Befehl gesucht werden (dh nach sich selbst). Machen wir also eine entsprechende Datei:
$ echo -e "1 foo\n2 grep\n3 bar\n4 grep \$BASH_COMMAND tmp" > tmp
$ grep $BASH_COMMAND tmp
grep: $BASH_COMMAND: No such file or directory
tmp:2 grep <-- here, the word "grep" is RED
tmp:4 grep $BASH_COMMAND tmp <-- here, the word "grep" is RED
tmp:2 grep <-- here, the word "grep" is RED
tmp:4 grep $BASH_COMMAND tmp <-- here, the word "grep" is RED
$ set | grep BASH_COMMAND=
BASH_COMMAND='grep --color=auto $BASH_COMMAND tmp'
$
Ok, interessant. Der Befehl grep $BASH_COMMAND tmp
wurde erweitert auf grep grep $BASH_COMMAND tmp tmp
(die Variable wird natürlich nur einmal erweitert), und so habe ich grep
einmal in einer Datei, $BASH_COMMAND
die nicht existiert, und zweimal in der Datei nachgegriffen tmp
.
F1: Ist meine derzeitige Annahme richtig, dass:
BASH_COMMAND
wird nur gesetzt, wenn ein Befehl versucht, ihn tatsächlich auszuwerten; und- Sie wird nach der Ausführung eines Befehls nicht deaktiviert, auch wenn die Beschreibung uns zu der Annahme verleitet.
Frage 2: Wenn ja, warum? Performance? Wenn nein, wie kann sonst das Verhalten in der obigen Befehlssequenz erklärt werden?
F3: Gibt es ein Szenario, in dem diese Variable tatsächlich sinnvoll verwendet werden könnte? Eigentlich habe ich versucht, $PROMPT_COMMAND
den ausgeführten Befehl damit zu analysieren (und davon abhängig einige Dinge zu tun), aber ich kann nicht, weil ich, sobald $PROMPT_COMMAND
ich einen Befehl ausführe $BASH_COMMAND
, der die Variable , die Variable, ansieht Ruft Sätze auf diesen Befehl ab. Auch wenn ich das MYVARIABLE=$BASH_COMMAND
gleich am Anfang mache $PROMPT_COMMAND
, dann MYVARIABLE
enthält der String MYVARIABLE=$BASH_COMMAND
, weil eine Zuweisung auch ein Befehl ist. (Bei dieser Frage geht es nicht darum, wie ich den aktuellen Befehl innerhalb einer $PROMPT_COMMAND
Ausführung erhalten kann. Ich weiß, dass es auch andere Möglichkeiten gibt.)
Es ist ein bisschen wie mit Heisenbergs Unschärferelation. Nur indem ich die Variable beobachte, ändere ich sie.
quelle
bash
Über-Gurus.Antworten:
Beantwortung der dritten Frage: Natürlich kann es sinnvoll eingesetzt werden, um im Bash-Handbuch eindeutige Hinweise zu geben - in einer Falle, zB:
quelle
$BASH_COMMAND
sie auch in anderen Kontexten als einer Falle sinnvoll verwendet werden können. Die von Ihnen beschriebene Verwendung ist jedoch wahrscheinlich die typischste und direkteste. Ihre und die von DocSalvager gestellte Antwort beantwortet mein Q3 am besten, und dies war für mich die wichtigste. Für Q1 und Q2 sind, wie durch @zwets angegeben, diese Dinge undefiniert. Es kann sein, dass$BASH_COMMAND
für die Leistung nur ein Wert angegeben wird, auf den zugegriffen wird, oder dass einige seltsame interne Programmbedingungen zu diesem Verhalten führen. Wer weiß?$BASH_COMMAND
immer so eingestellt werden, durch Erzwingen Auswertung der$BASH_COMMAND
vor jedem Befehl. Dazu können wir den DEBUG-Trap verwenden, der vor jedem einzelnen Befehl (all of em) ausgeführt wird. Wenn wir ausgeben, zum Beispieltrap 'echo "$BASH_COMMAND" > /dev/null' DEBUG
, dann$BASH_COMMAND
wird immer vor jedem Befehl ausgewertet werden (und den Wert dieser zugewiesen$COMMAND
). Also, wenn ich ausführe,set | grep BASH_COMMAND=
während diese Falle aktiv ist ... was weißt du? Jetzt ist die AusgabeBASH_COMMAND=set
wie erwartet :)Nachdem Q3 beantwortet wurde (meiner Meinung nach richtig:
BASH_COMMAND
nützlich in Fallen und kaum anderswo), versuchen wir es mit Q1 und Q2.Die Antwort auf Q1 lautet: Die Richtigkeit Ihrer Annahme ist nicht zu entscheiden. Die Wahrheit von keinem der Aufzählungspunkte kann festgestellt werden, da sie nach nicht spezifiziertem Verhalten fragen. Gemäß seiner Spezifikation wird der Wert von
BASH_COMMAND
für die Dauer der Ausführung dieses Befehls auf den Text eines Befehls festgelegt. Die Spezifikation gibt nicht an, wie hoch ihr Wert in einer anderen Situation sein muss, dh wenn kein Befehl ausgeführt wird. Es könnte irgendeinen Wert haben oder gar keinen.Die Antwort auf Q2 "Wenn nein, wie sonst kann das Verhalten in der obigen Befehlssequenz erklärt werden?" dann folgt logisch (wenn auch etwas pedantisch): es wird dadurch erklärt, dass der Wert von
BASH_COMMAND
undefiniert ist. Da sein Wert undefiniert ist, kann er einen beliebigen Wert haben, und genau das zeigt die Sequenz.Nachsatz
Es gibt einen Punkt, an dem Sie meiner Meinung nach tatsächlich eine Schwäche in der Spezifikation haben. Hier sagst du:
Die Art und Weise, wie ich die Bash-Manpage lese, ist nicht wahr. In diesem Abschnitt wird
SIMPLE COMMAND EXPANSION
erläutert, wie zuerst die Variablenzuweisungen in der Befehlszeile aufgehoben werden und dannDies legt für mich nahe, dass Variablenzuweisungen keine Befehle sind (und daher nicht angezeigt werden dürfen
BASH_COMMAND
), wie dies auch in anderen Programmiersprachen der Fall ist. Dies würde dann auch erklären, warum es keine ZeileBASH_COMMAND=set
in der Ausgabe von gibtset
, die imset
Wesentlichen ein syntaktischer 'Marker' für die Variablenzuweisung ist.OTOH, im letzten Absatz dieses Abschnitts heißt es
... was etwas anderes vorschlägt, und Variablenzuweisungen sind ebenfalls Befehle.
quelle
set
sollte ichBASH_COMMAND='set'
irgendwo in dieser Ausgabe sehen, welcheset
Befehls geschieht . Daher sollte es laut Spezifikation funktionieren. Befolgen die Implementierungen die Spezifikationen nicht genau oder verstehe ich sie falsch? Die Antwort auf diese Frage zu finden, ist eine Art Zweck von Q1. +1 für Ihren Nachtrag :)set
.set
nicht um einen "Befehl" handelt. So wie=
es kein "Befehl" ist. Die Verarbeitung des Texts, der diesen Tokens folgt / diese umgibt, kann eine völlig andere Logik haben als die Verarbeitung eines "Befehls".set
das nicht als "Befehl" zählt. Ich hätte nicht gedacht, dass sich$BASH_COMMAND
das unter vielen Umständen als so unterbestimmt herausstellen würde. Ich denke , zumindest wir festgestellt haben , dass der Mann Seite auf jeden Fall könnte klarer darüber sein;)Eine erfinderische Verwendung für $ BASH_COMMAND
Kürzlich wurde diese eindrucksvolle Verwendung von $ BASH_COMMAND bei der Implementierung einer makrofähigen Funktionalität festgestellt .
Der vorherige Artikel des Autors bietet auch einige gute Hintergrundinformationen beim Implementieren einer Technik unter Verwendung eines DEBUG
trap
. Dastrap
ist in der verbesserten Version beseitigt.quelle
$BASH_COMMAND
in einem anderen Kontext als a sinnvoll verwendet werden kanntrap
. Und was für ein Nutzen das ist! Verwenden Sie es, um Makrobefehle in bash zu implementieren - wer hätte das für möglich gehalten? Danke für den Hinweis.Eine anscheinend übliche Verwendung für das Debuggen von trap ... besteht darin, die Titel in der Fensterliste (^ A ") zu verbessern, wenn Sie" screen "verwenden.
Ich habe versucht, den "Bildschirm" und die "Fensterliste" benutzerfreundlicher zu machen, also habe ich angefangen, Artikel zu finden, die auf "trap ... debug" verweisen.
Ich fand heraus, dass die Methode, die PROMPT_COMMAND zum Senden der "Null-Titelsequenz" verwendet, nicht so gut funktionierte, weshalb ich auf die Debug-Methode trap ... zurückgegriffen habe.
So machen Sie es:
1 Weisen Sie "screen" an, nach der Escape-Sequenz zu suchen (aktivieren), indem Sie "shelltitle '$ | bash:'" in "$ HOME / .screenrc" einfügen.
2 Deaktivieren Sie die Weitergabe der Debug-Trap in Sub-Shells. Dies ist wichtig, denn wenn es aktiviert ist, wird alles durcheinander gebracht. Verwenden Sie dazu: "set + o functrace".
3 Senden Sie die Titel-Escape-Sequenz für "screen", um Folgendes zu interpretieren: trap 'printf "\ ek $ (Datum +% Y% m% d% H% M% S) $ (whoami) @ $ (Hostname): $ (pwd) $ {BASH_COMMAND} \ e \ "'" DEBUG "
Es ist nicht perfekt, aber es hilft, und Sie können diese Methode verwenden, um buchstäblich alles, was Sie möchten, in den Titel einzufügen
Siehe folgende "Fensterliste" (5 Bildschirme):
Num Name Flags
1 Bash: 20161115232035 mcb @ ken007: / home / mcb / ken007 RSYNCCMD = "sudo rsync" myrsync.sh -R -r "$ {1}" "$ {BACKUPDIR} $ {2: +" / $ {2} " } "$ 2 bash: 20161115230434 mcb @ ken007: / home / mcb / ken007 ls --color = auto -la $ 3 bash: 20161115230504 mcb @ ken007: / home / mcb / ken007 cat bin / psg.sh $ 4 bash: 20161115222415 mcb @ ken007: / home / mcb / ken007 ssh ken009 $ 5 bash: 20161115222450 mcb @ ken007: / home / mcb / ken007 mycommoncleanup $
quelle