Para que serve a variável $BASH_COMMAND?

Para que serve a variável $BASH_COMMAND?

De acordo comManual do Bash, a variável de ambiente BASH_COMMANDcontém

O comando atualmente sendo executado ou prestes a ser executado, a menos que o shell esteja executando um comando como resultado de uma armadilha, caso em que é o comando em execução no momento da armadilha.

Deixando de lado esse caso de armadilha, se bem entendi, isso significa que quando executo um comando, a variável BASH_COMMANDcontém esse comando. Não está absolutamente claro se essa variável não está definida após a execução do comando (ou seja, só está disponívelenquantoo comando está em execução, mas não depois), embora se possa argumentar que, uma vez que é "o comandoatualmentesendo executado ousobre serexecutado", não é o comandoisso foi apenasexecutado.

Mas vamos verificar:

$ set | grep BASH_COMMAND=
$ 

Vazio. Eu esperava ver BASH_COMMAND='set | grep BASH_COMMAND='ou talvez apenas BASH_COMMAND='set', mas o vazio me surpreendeu.

Vamos tentar outra coisa:

$ echo $BASH_COMMAND
echo $BASH_COMMAND
$ 

Bem, isso faz sentido. Eu executo o comando echo $BASH_COMMANDe assim a variável BASH_COMMANDcontém a string echo $BASH_COMMAND. Por que funcionou desta vez, mas não antes?

Vamos fazer a setcoisa novamente:

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

Então espere. Istoeradefinido quando executei esse echocomando, e elenão foidesativada depois. Mas quando executei setnovamente,BASH_COMMAND não foidefinido para o setcomando. Não importa quantas vezes eu execute o setcomando aqui, o resultado permanece o mesmo. Então, a variável está definida durante a execução echo, mas não durante a execução set? Vamos ver.

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

O que?Então a variável foi definida quando eu executei echo $BASH_COMMAND, masnãoquando eu executei echo Hello AskUbuntu? Onde está a diferença agora? A variável só é definida quando o próprio comando atual realmente força o shell a avaliar a variável? Vamos tentar algo diferente. Talvez algum comando externo desta vez, não um bash embutido, para variar.

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

Hmm, ok... novamente, a variável foi definida. Então, meu palpite atual está correto? A variável só é definida quando precisa ser avaliada? Por que?Por que?Por motivos de desempenho? Vamos fazer mais uma tentativa. Tentaremos usar o grep $BASH_COMMANDem um arquivo e, como $BASH_COMMANDdeverá conter um grepcomando, grepdeverá usar o grep para esse grepcomando (ou seja, para si mesmo). então vamos criar um arquivo apropriado:

$ 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, interessante. O comando grep $BASH_COMMAND tmpfoi expandido para grep grep $BASH_COMMAND tmp tmp(a variável é expandida apenas uma vez, é claro), e então eu usei o grepped para grep, uma vez em um arquivo $BASH_COMMANDque não existe e duas vezes no arquivo tmp.

P1:Minha suposição atual está correta de que:

  • BASH_COMMANDsó é definido quando um comando tenta realmente avaliá-lo; e
  • isso énãodesativado após a execução de um comando, mesmo que a descrição possa nos levar a acreditar que sim?

Q2:Se sim, por quê? Desempenho? Se não, de que outra forma o comportamento na sequência de comandos acima pode ser explicado?

P3:Por último, existe algum cenário em que esta variável possa realmente ser usada de forma significativa? Na verdade eu estava tentando usar ele dentro $PROMPT_COMMANDpara analisar o comando que está sendo executado (e fazer algumas coisas dependendo disso), mas não consigo, pois assim que, dentro do meu $PROMPT_COMMAND, eu executo um comando para olhar a variável $BASH_COMMAND, a variável obtém conjuntos para esse comando. Mesmo quando faço MYVARIABLE=$BASH_COMMANDlogo no início do meu $PROMPT_COMMAND, então MYVARIABLEcontém a string MYVARIABLE=$BASH_COMMAND, pois uma atribuição também é um comando. (Esta questão não é sobre como eu poderia obter o comando atual dentro de uma $PROMPT_COMMANDexecução. Existem outras maneiras, eu sei.)

É um pouco como o princípio da incerteza de Heisenberg. Apenas observando a variável, eu a mudo.

Responder1

Respondendo à terceira pergunta: é claro que pode ser usado de forma significativa da maneira que o manual do Bash sugere claramente - em uma armadilha, por exemplo:

$ 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

Responder2

Agora que a Q3 foi respondida (corretamente, na minha opinião: BASH_COMMANDé útil em armadilhas e dificilmente em qualquer outro lugar), vamos dar uma chance à Q1 e à Q2.

A resposta à Q1 é: a exatidão da sua suposição é indecidível. A verdade de nenhum dos pontos pode ser estabelecida, pois eles perguntam sobre comportamento não especificado. Pela sua especificação, o valor de BASH_COMMANDé definido como o texto de um comando durante a execução desse comando. A especificação não indica qual deve ser seu valor em qualquer outra situação, ou seja, quando nenhum comando está sendo executado. Poderia ter qualquer valor ou nenhum.

A resposta à pergunta 2 "Se não, de que outra forma o comportamento na sequência de comandos acima pode ser explicado?" então segue logicamente (embora um tanto pedantemente): é explicado pelo fato de que o valor de BASH_COMMANDé indefinido. Como seu valor é indefinido, pode ter qualquer valor, que é exatamente o que a sequência mostra.

Pós-escrito

Há um ponto em que acho que você está realmente atingindo um ponto fraco nas especificações. É onde você diz:

Mesmo quando eu faço MYVARIABLE=$BASH_COMMAND logo no início do meu $PROMPT_COMMAND, então MYVARIABLE contém a string MYVARIABLE=$BASH_COMMAND,porque uma tarefa também é um comando.

Do jeito que li a página de manual do bash, o trecho em itálico não é verdade. A seção SIMPLE COMMAND EXPANSIONexplica como primeiro as atribuições de variáveis ​​na linha de comando são deixadas de lado e depois

Se nenhum nome de comando resultar [em outras palavras, houve apenas atribuições de variáveis], as atribuições de variáveis ​​afetarão o ambiente shell atual.

Isso me sugere que atribuições de variáveis ​​não são comandos (e, portanto, isentas de aparecer em BASH_COMMAND), como em outras linguagens de programação. Isso também explicaria por que não há uma linha BASH_COMMAND=setna saída de set, setsendo essencialmente um 'marcador' sintático para atribuição de variáveis.

OTOH, no parágrafo final dessa seção diz

Se sobrar um nome de comando após a expansão, a execução continuará conforme descrito abaixo. Caso contrário, ocomandosaídas.

... o que sugere o contrário, e atribuições de variáveis ​​também são comandos.

Responder3

Um uso inventivo para $BASH_COMMAND

Encontrei isso recentementeuso impressionante de $BASH_COMMANDna implementação de uma funcionalidade semelhante a macro.

Este é o truque principal do alias e substitui o uso da armadilha DEBUG. Se você leu a parte do post anterior sobre a armadilha DEBUG, você reconhecerá a variável $BASH_COMMAND. Naquele post eu disse que era definido o texto do comando antes de cada chamada para a armadilha DEBUG. Bem, acontece que ele é definido antes da execução de cada comando, com DEBUG trap ou não (por exemplo, execute 'echo “this command = $BASH_COMMAND”' para ver do que estou falando). Ao atribuir-lhe uma variável (apenas para essa linha), capturamos BASH_COMMAND no escopo mais externo do comando, que conterá o comando inteiro.

Os autoresartigo anteriortambém fornece algumas boas informações ao implementar uma técnica usando DEBUG trap. O trapé eliminado na versão melhorada.

Responder4

Um uso aparentemente comum para trap...debug é melhorar os títulos que aparecem na lista de janelas (^A") quando você está usando "screen".

Eu estava tentando tornar a "tela", "lista de janelas" mais utilizável, então comecei a encontrar artigos referenciando "trap...debug".

Descobri que o método usando PROMPT_COMMAND para enviar a "sequência de título nulo" não funcionou tão bem, então voltei para o método trap...debug.

Aqui está como você faz isso:

1 Diga à "tela" para procurar a sequência de escape (habilite-a) colocando "shelltitle '$|bash:'" em "$HOME/.screenrc".

2 Desative a propagação da interceptação de depuração em subshells. Isso é importante, pois se estiver habilitado fica tudo bagunçado, use: "set +o functrace".

3 Envie a sequência de escape do título para "tela" para interpretar: trap 'printf "\ek$(date +%Y%m%d%H%M%S) $(whoami)@$(hostname):$(pwd) ${BASH_COMMAND}\e\"' "DEBUGAR"

Não é perfeito, mas ajuda, e você pode usar esse método para colocar literalmente o que quiser no título

Veja a seguinte "lista de janelas" (5 telas):

Sinalizadores de nomes numéricos

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 $

informação relacionada