Según el manual de Bash , la variable de entorno BASH_COMMANDcontiene
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_COMMANDcontiene 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_COMMANDy la variable BASH_COMMANDcontiene la cadena echo $BASH_COMMAND. ¿Por qué funcionó esta vez, pero no antes?
Hagamos la setcosa otra vez:
$ set | grep BASH_COMMAND=
BASH_COMMAND='echo $BASH_COMMAND'
$
Entonces espera. Que se establece cuando ejecuté que echocomando, y no fue desactivada después. Pero cuando ejecuté setnuevamente, BASH_COMMAND no estaba configurado para el setcomando. No importa con qué frecuencia ejecute el setcomando 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_COMMANDen un archivo, y como $BASH_COMMANDdebería contener un grepcomando, grepdebería grep para ese grepcomando (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 tmpse 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_COMMANDque no existe, y dos veces en el archivo tmp.
P1: ¿Es correcto mi supuesto actual de que:
BASH_COMMANDsolo 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_COMMANDpara 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_COMMANDal comienzo de mi $PROMPT_COMMAND, luego MYVARIABLEcontiene 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_COMMANDejecució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_COMMANDhecho 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_COMMANDsolo 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_COMMANDque se configure siempre, forzando la evaluación$BASH_COMMANDantes 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' DEBUGy luego$BASH_COMMANDsiempre 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_COMMANDes ú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_COMMANDse 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_COMMANDno 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 EXPANSIONexplica 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=seten la salida deset,setsiendo 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, quesetcomando . 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.setno 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".setno cuente como un "comando". No hubiera pensado que$BASH_COMMANDresultarí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. Eltrapse elimina en la versión mejorada.fuente
$BASH_COMMANDse 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