¿Para qué sirve la variable $BASH_COMMAND?

¿Para qué sirve la variable $BASH_COMMAND?

De acuerdo con lamanual de bash, la variable de entorno BASH_COMMANDcontiene

El comando que se está ejecutando actualmente o a punto de ejecutarse, a menos que el shell esté ejecutando un comando como resultado de una trampa, en cuyo caso es el comando que se ejecuta en el momento de la trampa.

Dejando a un lado ese caso de esquina trampa, si entiendo correctamente, esto significa que cuando ejecuto un comando, la variable BASH_COMMANDcontiene ese comando. No está del todo claro si esa variable no está configurada después de la ejecución del comando (es decir, solo está disponiblemientrasel comando se está ejecutando, pero no después), aunque se podría argumentar que dado que es "el comandoactualmentesiendo ejecutado oa punto de serejecutado", no es el comandoeso fue soloejecutado.

Pero comprobemos:

$ set | grep BASH_COMMAND=
$ 

Vacío. Esperaba verlo BASH_COMMAND='set | grep BASH_COMMAND='o tal vez simplemente BASH_COMMAND='set', pero el vacío me sorprendió.

Probemos algo más:

$ echo $BASH_COMMAND
echo $BASH_COMMAND
$ 

Bueno, eso tiene sentido. Ejecuto el comando echo $BASH_COMMANDy entonces la variable BASH_COMMANDcontiene la cadena echo $BASH_COMMAND. ¿Por qué funcionó esta vez, pero no antes?

Hagamos la setcosa de nuevo:

$ set | grep BASH_COMMAND=
BASH_COMMAND='echo $BASH_COMMAND'
$

Entonces espera. Éleraestablecido cuando ejecuté ese echocomando, yno estabadesarmar después. Pero cuando ejecuté setde nuevo,BASH_COMMAND no estabaestablecido en el setcomando. No importa con qué frecuencia ejecute el setcomando aquí, el resultado sigue siendo el mismo. Entonces, ¿la variable se establece al ejecutar echo, pero no al ejecutar set? Vamos a ver.

$ 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, peronocuando ejecuté echo Hello AskUbuntu? ¿Dónde está la diferencia ahora? ¿La variable solo se establece cuando el comando actual realmente obliga al shell a evaluar la variable? Probemos algo diferente. Quizás esta vez algún comando externo, no un bash integrado, para variar.

$ /bin/echo $BASH_COMMAND
/bin/echo $BASH_COMMAND
$ set | grep BASH_COMMAND=
BASH_COMMAND='/bin/echo $BASH_COMMAND'
$

Hmm, ok... nuevamente, la variable fue configurada. Entonces, ¿es correcta mi suposición actual? ¿La variable sólo se establece cuando debe evaluarse? ¿Por qué?¿Por qué?¿Por motivos de rendimiento? Hagamos un intento más. Intentaremos buscar $BASH_COMMANDen un archivo y, dado que $BASH_COMMANDdebería contener un grepcomando, grepdeberíamos buscar ese grepcomando (es decir, por 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'
$

Vale, interesante. El comando grep $BASH_COMMAND tmpse expandió a grep grep $BASH_COMMAND tmp tmp(la variable se expande solo esa 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 correcta mi suposición actual de que:

  • BASH_COMMANDsólo se establece cuando un comando intenta evaluarlo; y
  • esno¿desarmado después de la ejecución de un comando, aunque la descripción pueda hacernos creer que sí?

P2:¿Si es así por qué? ¿Actuación? En caso negativo, ¿de qué otra manera se puede explicar el comportamiento en la secuencia de comandos anterior?

P3:Por último, ¿existe algún escenario en el que esta variable pueda usarse de manera significativa? En realidad, estaba tratando de usarlo $PROMPT_COMMANDpara analizar el comando que se está 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_COMMANDjusto al principio de my $PROMPT_COMMAND, luego MYVARIABLEcontiene la cadena MYVARIABLE=$BASH_COMMAND, porque una asignación también es un comando. (Esta pregunta no trata sobre cómo podría obtener el comando actual dentro de una $PROMPT_COMMANDejecución. Hay otras formas, lo sé).

Es un poco como el principio de incertidumbre de Heisenberg. Con solo observar la variable, la cambio.

Respuesta1

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:

$ trap 'echo ‘$BASH_COMMAND’ failed with error code $?' ERR
$ fgfdjsa
fgfdjsa: command not found
‘fgfdjsa’ failed with error code 127
$ cat /etc/fgfdjsa
cat: /etc/fgfdjsa: No such file or directory
‘cat /etc/fgfdjsa’ failed with error code 1

Respuesta2

Ahora que se ha respondido la pregunta 3 (correctamente, en mi opinión: BASH_COMMANDes útil en trampas y casi en ningún otro lugar), demos una oportunidad a la pregunta 1 y la pregunta 2.

La respuesta a la pregunta 1 es: la exactitud de su suposición es indecidible. No se puede establecer la verdad de ninguno de los puntos, ya que preguntan sobre un comportamiento no especificado. Según 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 cualquier otra situación, es decir, cuando no se ejecuta ningún comando. Podría tener cualquier valor o ninguno.

La respuesta a la pregunta 2 "Si no, ¿de qué otra manera se puede explicar el comportamiento en la secuencia de comandos anterior?" luego sigue lógicamente (aunque un poco 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 estás tocando un punto débil en la especificación. Es donde dices:

Incluso cuando hago MYVARIABLE=$BASH_COMMAND justo al comienzo de mi $PROMPT_COMMAND, entonces MYVARIABLE contiene la cadena MYVARIABLE=$BASH_COMMAND,porque una tarea también es una orden.

Según leo la página de manual de bash, la parte en cursiva no es cierta. La sección SIMPLE COMMAND EXPANSIONexplica cómo primero se reservan las asignaciones de variables en la línea de comando y luego

Si no se obtiene ningún nombre de comando [en otras palabras, solo hubo asignaciones de variables], las asignaciones de variables afectan el entorno de shell actual.

Esto me sugiere que las asignaciones de variables no son comandos (y por lo tanto están exentas de aparecer en BASH_COMMAND), como en otros lenguajes de programación. Esto también explicaría por qué no hay una línea BASH_COMMAND=seten la salida de set, setsiendo esencialmente un 'marcador' sintáctico para la asignación de variables.

OTOH, en el párrafo final de esa sección dice

Si queda un nombre de comando después de la expansión, la ejecución continúa como se describe a continuación. De lo contrario, eldominiosalidas.

... lo que sugiere lo contrario, y las asignaciones de variables también son comandos.

Respuesta3

Un uso inventivo para $BASH_COMMAND

Recientemente encontré estouso impresionante de $BASH_COMMANDen la implementación de una funcionalidad similar a una macro.

Este es el truco principal del alias y reemplaza el uso de la trampa DEBUG. Si lees la parte de la publicación anterior sobre la trampa DEBUG, reconocerás la variable $BASH_COMMAND. En esa publicación dije que estaba configurado con el texto del comando antes de cada llamada a la trampa DEBUG. Bueno, resulta que se configura antes de la ejecución de cada comando, con trampa DEBUG o no (por ejemplo, ejecute 'echo “this command = $BASH_COMMAND”' para ver de qué estoy hablando). Al asignarle una variable (solo para esa línea), capturamos BASH_COMMAND en el alcance más externo del comando, que contendrá el comando completo.

Los autoresArtículo anteriorTambién proporciona buenos conocimientos sobre la implementación de una técnica utilizando DEBUG trap. Se trapelimina en la versión mejorada.

Respuesta4

Un uso aparentemente común para la trampa...depuración es mejorar los títulos que aparecen en la lista de ventanas (^A") cuando se usa "pantalla".

Estaba intentando hacer que la "pantalla", la "lista de ventanas" fuera más utilizable, así que comencé a encontrar artículos que hacían referencia a "trampa...depuración".

Descubrí que el método que utiliza PROMPT_COMMAND para enviar la "secuencia de títulos nulos" no funcionaba tan bien, así que volví al método trap...debug.

Así es como se hace:

1 Dile a "pantalla" que busque la secuencia de escape (habilítala) poniendo "shelltitle '$|bash:'" en "$HOME/.screenrc".

2 Desactive la propagación de la captura de depuración a 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 que "pantalla" la interprete: trap 'printf "\ek$(date +%Y%m%d%H%M%S) $(whoami)@$(hostname):$(pwd) ${BASH_COMMAND}\e\"' "DEPURACIÓN"

No es perfecto, pero ayuda y puedes usar este método para poner literalmente lo que quieras en el título.

Consulte la siguiente "lista de ventanas" (5 pantallas):

Núm. 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 $

información relacionada