Según el manual de Bash , la variable de entorno BASH_COMMAND
contiene
El comando que se está ejecutando actualmente o que se va a ejecutar, a menos que el shell esté ejecutando un comando como resultado de una captura, en cuyo caso es el comando que se ejecuta en el momento de la captura.
Si entiendo el caso de la esquina de la trampa, si entiendo correctamente, esto significa que cuando ejecuto un comando, la variable BASH_COMMAND
contiene ese comando. No está absolutamente claro si esa variable se desarma después de la ejecución del comando (es decir, solo está disponible mientras el comando se está ejecutando, pero no después), aunque se podría argumentar que dado que es "el comando que se está ejecutando actualmente o está por ejecutarse" , no es el comando que era solo ejecutar.
Pero revisemos:
$ set | grep BASH_COMMAND=
$
Vacío. Hubiera esperado ver BASH_COMMAND='set | grep BASH_COMMAND='
o tal vez soloBASH_COMMAND='set'
, pero vacío me sorprendió.
Probemos algo más:
$ echo $BASH_COMMAND
echo $BASH_COMMAND
$
Bueno, eso tiene sentido. Ejecuto el comando echo $BASH_COMMAND
y la variable BASH_COMMAND
contiene la cadena echo $BASH_COMMAND
. ¿Por qué funcionó esta vez, pero no antes?
Hagamos la set
cosa otra vez:
$ set | grep BASH_COMMAND=
BASH_COMMAND='echo $BASH_COMMAND'
$
Entonces espera. Que se establece cuando ejecuté que echo
comando, y no fue desactivada después. Pero cuando ejecuté set
nuevamente, BASH_COMMAND
no estaba configurado para el set
comando. No importa con qué frecuencia ejecute el set
comando aquí, el resultado sigue siendo el mismo. Entonces, ¿se establece la variable al ejecutar echo
, pero no al ejecutar set
? Veamos.
$ echo Hello AskUbuntu
Hello AskUbuntu
$ set | grep BASH_COMMAND=
BASH_COMMAND='echo $BASH_COMMAND'
$
¿Qué? Entonces, ¿la variable se configuró cuando ejecuté echo $BASH_COMMAND
, pero no cuando ejecuté echo Hello AskUbuntu
? ¿Dónde está la diferencia ahora? ¿La variable solo se establece cuando el comando actual en sí mismo obliga al shell a evaluar la variable? Probemos algo diferente. Tal vez algún comando externo esta vez, no un bash incorporado, para variar.
$ /bin/echo $BASH_COMMAND
/bin/echo $BASH_COMMAND
$ set | grep BASH_COMMAND=
BASH_COMMAND='/bin/echo $BASH_COMMAND'
$
Hmm, ok ... otra vez, la variable fue establecida. Entonces, ¿es correcta mi suposición actual? ¿La variable solo se establece cuando debe evaluarse? ¿Por qué? ¿Por qué? Por razones de rendimiento? Hagamos un intento más. Intentaremos grep $BASH_COMMAND
en un archivo, y como $BASH_COMMAND
debería contener un grep
comando, grep
debería grep para ese grep
comando (es decir, para sí mismo). así que hagamos un archivo apropiado:
$ 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, interesante El comando grep $BASH_COMMAND tmp
se expandió a grep grep $BASH_COMMAND tmp tmp
(la variable se expande solo una vez, por supuesto), por lo que busqué grep
, una vez en un archivo $BASH_COMMAND
que no existe, y dos veces en el archivo tmp
.
P1: ¿Es correcto mi supuesto actual de que:
BASH_COMMAND
solo se establece cuando un comando intenta evaluarlo realmente; y- se no desactívala después de la ejecución de un comando, a pesar de que la descripción que nos puede llevar a creer eso?
P2: En caso afirmativo, ¿por qué? ¿Actuación? Si no, ¿de qué otra manera se puede explicar el comportamiento en la secuencia de comandos anterior?
P3: Por último, ¿hay algún escenario en el que esta variable realmente pueda usarse de manera significativa? En realidad estaba tratando de usarlo $PROMPT_COMMAND
para analizar el comando que se estaba ejecutando (y hacer algunas cosas dependiendo de eso), pero no puedo, porque tan pronto como, dentro de mi $PROMPT_COMMAND
, ejecuto un comando para mirar la variable $BASH_COMMAND
, la variable obtiene conjuntos para ese comando. Incluso cuando lo hago MYVARIABLE=$BASH_COMMAND
al comienzo de mi $PROMPT_COMMAND
, luego MYVARIABLE
contiene la cadena MYVARIABLE=$BASH_COMMAND
, porque una asignación también es un comando. (Esta pregunta no se trata de cómo podría obtener el comando actual dentro de una $PROMPT_COMMAND
ejecución. Hay otras formas, lo sé).
Es un poco como con el principio de incertidumbre de Heisenberg. Simplemente observando la variable, la cambio.
fuente
bash
über-gurus allí.Respuestas:
Respondiendo a la tercera pregunta: por supuesto, se puede usar de manera significativa en la forma en que el manual de Bash sugiere claramente, en una trampa, por ejemplo:
fuente
$BASH_COMMAND
hecho se puede usar de manera significativa incluso en contextos distintos de una trampa. Sin embargo, el uso que describe es probablemente el más típico y directo. Entonces, su respuesta, y la de DocSalvager, responde mi Q3 mejor, y esta fue la más importante para mí. En cuanto a Q1 y Q2, como lo indica @zwets, esas cosas no están definidas. Es posible que$BASH_COMMAND
solo se le dé un valor si se accede a él, para el rendimiento, o bien algunas condiciones extrañas del programa interno pueden conducir a ese comportamiento. ¿Quién sabe?$BASH_COMMAND
que se configure siempre, forzando la evaluación$BASH_COMMAND
antes de cada comando. Para hacer esto, podemos usar la trampa DEBUG, que se ejecuta antes de cada comando (todos ellos). Si emitimos, por ejemplo,trap 'echo "$BASH_COMMAND" > /dev/null' DEBUG
y luego$BASH_COMMAND
siempre será evaluado antes de cada comando (y asignado el valor de esa$COMMAND
). Entonces, si ejecutoset | grep BASH_COMMAND=
mientras esa trampa está activa ... ¿qué sabes? Ahora la salida esBASH_COMMAND=set
, como se esperaba :)Ahora que Q3 ha sido respondido (correctamente, en mi opinión:
BASH_COMMAND
es útil en trampas y casi en ningún otro lado), demos una oportunidad a Q1 y Q2.La respuesta a Q1 es: la exactitud de su suposición es indecidible. No se puede establecer la verdad de ninguno de los puntos, ya que preguntan sobre el comportamiento no especificado. Por su especificación, el valor de
BASH_COMMAND
se establece en el texto de un comando durante la ejecución de ese comando. La especificación no indica cuál debe ser su valor en ninguna otra situación, es decir, cuando no se ejecuta ningún comando. Podría tener cualquier valor o ninguno en absoluto.La respuesta a la P2 "Si no, ¿de qué otra manera se puede explicar el comportamiento en la secuencia de comandos anterior?" luego sigue lógicamente (si es algo pedante): se explica por el hecho de que el valor de
BASH_COMMAND
no está definido. Como su valor no está definido, puede tener cualquier valor, que es exactamente lo que muestra la secuencia.Posdata
Hay un punto en el que creo que realmente estás llegando a un punto débil en la especificación. Es donde dices:
La forma en que leo la página de manual de bash, el bit en cursiva no es cierto. La sección
SIMPLE COMMAND EXPANSION
explica cómo primero se dejan de lado las asignaciones de variables en la línea de comando, y luegoEsto me sugiere que las asignaciones de variables no son comandos (y, por lo tanto, están exentos de aparecer en
BASH_COMMAND
), como en otros lenguajes de programación. Esto también explicaría por qué no hay una líneaBASH_COMMAND=set
en la salida deset
,set
siendo esencialmente un 'marcador' sintáctico para la asignación de variables.OTOH, en el párrafo final de esa sección dice
... lo que sugiere lo contrario, y las asignaciones variables también son comandos.
fuente
set
, debería verBASH_COMMAND='set'
en algún lugar de esa salida, queset
comando . Por lo tanto, de acuerdo con las especificaciones, debería funcionar. Entonces, ¿es que la implementación no obedece fielmente las especificaciones, o no entiendo las especificaciones? Encontrar la respuesta a esa pregunta es una especie de propósito de Q1. +1 para tu postdata :)set
.set
no sea un "comando". Así como=
no es un "comando". El procesamiento del texto que sigue / rodea esos tokens podría tener una lógica completamente diferente que el procesamiento de un "comando".set
no cuente como un "comando". No hubiera pensado que$BASH_COMMAND
resultaría tan poco especificado en muchas circunstancias. Supongo que al menos hemos establecido que la página del manual definitivamente podría ser más clara al respecto;)Un uso inventivo para $ BASH_COMMAND
Recientemente encontré este uso impresionante de $ BASH_COMMAND en la implementación de una funcionalidad tipo macro.
El artículo anterior del autor también proporciona algunos buenos antecedentes al implementar una técnica utilizando un DEBUG
trap
. Eltrap
se elimina en la versión mejorada.fuente
$BASH_COMMAND
se puede usar de manera significativa en un contexto que no sea atrap
. ¡Y qué uso es eso! Utilizándolo para implementar comandos de macro en bash: ¿quién lo hubiera pensado posible? Gracias por el puntero.Un uso aparentemente común para la trampa ... depuración es mejorar los títulos que aparecen en la lista de ventanas (^ A ") cuando está usando" pantalla ".
Estaba tratando de hacer que la "pantalla", "lista de ventanas" fuera más utilizable, así que comencé a encontrar artículos que hacen referencia a "trampa ... depuración".
Descubrí que el método que usa PROMPT_COMMAND para enviar la "secuencia de título nulo" no funcionaba tan bien, así que volví al método trap ... debug.
Así es como lo haces:
1 Indique a "pantalla" que busque la secuencia de escape (habilítela) colocando "shelltitle '$ | bash:'" en "$ HOME / .screenrc".
2 Desactive la propagación de la trampa de depuración en subcapas. Esto es importante, porque si está habilitado, todo se arruina, use: "set + o functrace".
3 Envíe la secuencia de escape del título para "pantalla" para interpretar: trap 'printf "\ ek $ (fecha +% Y% m% d% H% M% S) $ (whoami) @ $ (nombre de host): $ (pwd) $ {BASH_COMMAND} \ e \ "'" DEBUG "
No es perfecto, pero ayuda, y puedes usar este método para poner literalmente todo lo que quieras en el título
Consulte la siguiente "lista de ventanas" (5 pantallas):
Num Nombre Banderas
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 $
fuente