![Para que serve a variável $BASH_COMMAND?](https://rvso.com/image/1047576/Para%20que%20serve%20a%20vari%C3%A1vel%20%24BASH_COMMAND%3F.png)
De acordo comManual do Bash, a variável de ambiente BASH_COMMAND
conté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_COMMAND
conté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_COMMAND
e assim a variável BASH_COMMAND
contém a string echo $BASH_COMMAND
. Por que funcionou desta vez, mas não antes?
Vamos fazer a set
coisa novamente:
$ set | grep BASH_COMMAND=
BASH_COMMAND='echo $BASH_COMMAND'
$
Então espere. Istoeradefinido quando executei esse echo
comando, e elenão foidesativada depois. Mas quando executei set
novamente,BASH_COMMAND
não foidefinido para o set
comando. Não importa quantas vezes eu execute o set
comando 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_COMMAND
em um arquivo e, como $BASH_COMMAND
deverá conter um grep
comando, grep
deverá usar o grep para esse grep
comando (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 tmp
foi 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_COMMAND
que não existe e duas vezes no arquivo tmp
.
P1:Minha suposição atual está correta de que:
BASH_COMMAND
só é 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_COMMAND
para 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_COMMAND
logo no início do meu $PROMPT_COMMAND
, então MYVARIABLE
conté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_COMMAND
execuçã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 EXPANSION
explica 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=set
na saída de set
, set
sendo 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 $