No bash: processando cada linha de comando sem usar a armadilha de depuração?

2

Eu tenho um mecanismo complicado incorporado no meu ambiente bash que requer a execução de alguns scripts quando o prompt é gerado, mas também quando o usuário pressiona enter para iniciar o processamento de um comando. Vou dar uma descrição simplificada:

A armadilha de depuração faz isso de uma maneira bastante limitada: é acionada toda vez que uma instrução é executada.

trap 'echo $BASH_COMMAND' DEBUG  # example only

Infelizmente, isso significa que quando eu digito isso:

sleep 1; sleep 2; sleep 3

em vez de processar um $ BASH_COMMAND que contém toda a linha, recebo os três dormes em três armadilhas diferentes. Pior ainda:

sleep 1 | sleep 2 | sleep 3

aciona os três enquanto o tubo é configurado - antes que o sono 1 comece a ser executado, a saída pode levar você a acreditar que o sono 3 está em execução.

Preciso de uma maneira de executar um script logo no início, processando o comando inteiro, e prefiro que não seja acionado quando o comando prompt for executado, mas posso lidar com isso se for necessário.

Sniggerfardimungus
fonte
Boa pergunta. Porém, mais orientado à programação, portanto, ele deve ir para o StackOverflow.
perfil completo de JakeGould

Respostas:

3

Não é muito bonito, mas se você realmente precisar disso, poderá usar PROMPT_COMMANDalém da armadilha de depuração para se livrar das chamadas extras:

trap 'debug_hook' DEBUG

debug_hook()
{ 
  [ -n "$debug_hook_on" ] || return 
  debug_hook_on="" 
  echo hook             # cmds to run ...
}

PROMPT_COMMAND='debug_hook_on=1'

Agora:

$ echo 1 ; echo 2 | cat
hook
1
2

No entanto, ainda não temos acesso a toda a linha de entrada: $BASH_COMMANDé justo echo 1.


Outra idéia inspirada neste artigo é usar as ligações readline para obter acesso a toda a linha:

$ bind -x '"\C-o":hook'
$ hook(){ echo "hook: $READLINE_LINE";  }
$ bind 'RETURN: "\C-o\n"'

Agora funciona:

hook: echo 1; echo 2
$ echo 1; echo 2
1
2

Porém, um aspecto a ter em mente: para entrada em várias linhas, será invocado uma vez para cada linha que pode não ser o que você deseja (poderia usar uma combinação de ambas as abordagens).

limões
fonte
Acabei chamando a história do manipulador de armadilhas e pegando a linha de comando mais recente. Ao longo do caminho, aprendi NUNCA em segundo plano um processo em um manipulador de armadilhas. Mesmo se você negar o processo, a interceptação não retornará até que o subprocesso seja encerrado.
Sniggerfardimungus