dizer se o último comando estava vazio em PROMPT_COMMAND


12

No bash, de dentro do PROMPT_COMMAND, existe uma maneira de saber se o usuário pressionou 'return' e não inseriu um comando?

Respostas:


7

Verifique se o número do histórico foi incrementado. Um prompt cancelado ou um prompt em que o usuário acabou de pressionar Enternão aumentará o número do histórico.

O número do histórico está disponível na variável HISTCMD, mas não está disponível em PROMPT_COMMAND(porque o que você deseja é, de fato, o número do histórico do comando anterior; o comando que se executa por PROMPT_COMMANDsi mesmo não tem número do histórico). Você pode obter o número da saída de fc.

prompt_command () {
  HISTCMD_previous=$(fc -l -1); HISTCMD_previous=${HISTCMD_previous%%$'[\t ]'*}
  if [[ -z $HISTCMD_before_last ]]; then
    # initial prompt
  elif [[ $HISTCMD_before_last = "$HISTCMD_previous" ]]; then
    # cancelled prompt
  else
    # a command was run
  fi
  HISTCMD_before_last=$HISTCMD_previous
}
PROMPT_COMMAND='prompt_command'

Observe que, se você ativou o esmagamento de duplicatas no histórico ( HISTCONTROL=ignoredupsou HISTCONTROL=erasedups), isso reportará por engano um comando vazio após executar dois comandos idênticos sucessivamente.


Obrigado, Gilles. Estou faltando alguma coisa aqui. Isso nunca parece funcionar, pois colocar 'echo hello' na primeira linha da função literal não funciona, embora PROMPT_COMMAND = 'echo hello' funcione. Eu pensei que poderia ser o HISTCMD_previous vs HISTCMD_PREVIOUS questão, mas nenhum dado. Vou continuar cutucando, mas estou comentando que seu bash fu está claramente ligando além do meu.
usuário

@user Corrigi mais erros de digitação, em particular, o ${HISTCMD_previous%%$'[\t ]'*}bit estava ausente $'…'e acabou truncando após `, t` ou espaço em vez de após tab ou espaço, mas o bash imprime uma tab.
Gilles 'SO- stop be evil'

1
Esta solução é baseada na suposição de que duplicatas são salvas no histórico (que está desativado para mim). Portanto, esta solução não funciona como esperado para comandos repetidos, enquanto as duplicatas não são salvas no histórico.
21417 schlimmchen

4

Existe uma solução alternativa, mas ela tem alguns requisitos:

Você precisa definir $HISTCONTROLpara salvar TODOS os comandos, também duplicatas e espaços. Então defina:

HISTCONTROL=

Agora defina uma função para chamar como $PROMPT_COMMAND:

isnewline () {
  # read the last history number
  prompt_command__isnewline__last="$prompt_command__isnewline__curr"
  # get the current history number
  prompt_command__isnewline__curr="$(history 1 | grep -oP '^\ +\K[0-9]+')"
  [ "$prompt_command__isnewline__curr" = "$prompt_command__isnewline__last" ] && \
    echo "User hit return"
}

Agora, defina a $PROMPT_COMMANDvariável:

PROMPT_COMMAND="isnewline"

Veja a saída:

user@host:~$ true
user@host:~$ <return>
User hit return
user@host:~$ <space><return>
user@host:~$ 

Não entendo por que você está usando um arquivo temporário aqui. A variável lasté preservada de uma chamada isnewlinepara a próxima (escolha apenas um nome menos genérico prompt_command__isnewline__lastpara evitar conflitos).
Gilles 'SO- stop be evil'

@Gilles você está certo, eu mudei, obrigado pela sua sugestão
caos

Obrigado, caos. Usei a mesma idéia para o seguinte, que é um pouco mais fácil de analisar. HISTCONTROL="" function last_was_blank { local last_command="$(history 1)" if [[ "$last_was_blank_PREVIOUS_LINE" = "$last_command" ]] ; then echo "true" else echo "false" fi export last_was_blank_PREVIOUS_LINE="$last_command" } PROMPT_COMMAND=last_was_blank
usuário

1

Não sei como, por si só . Mas você pode obter o mesmo efeito usando

interceptação some_command_or_function debug

Isso fará com some_command_or_functionque seja chamado sempre que você executar um comando. O mais complicado é que não será chamado se você apenas pressionar Enter- a menos que você tenha um PROMPT_COMMAND definido; nesse caso, pressionar Enterinvoca o PROMPT_COMMAND, que, por sua vez, aciona a armadilha.

Talvez a maneira mais simples de obter o resultado desejado seja definir uma função de interceptação de depuração em vez de usar um PROMPT_COMMAND. Mas não sei dizer, porque não sei qual resultado você deseja. Se você deseja que algo aconteça quando você apenas pressiona Enter, e algo diferente / adicional aconteça ao digitar um comando, (AFAIK), você precisa usar uma interceptação de depuração e um PROMPT_COMMAND. Veja esta respostaesta como uma maneira de fazer com que os dois mecanismos funcionem bem juntos.


0

(Isso teria sido um comentário para a resposta aceita se eu tivesse permissão para adicionar comentários ...) @schlimmen, você pode definir HISTTIMEFORMATalgo como isso HISTTIMEFORMAT='%F %T 'e depois salvar e comparar history 1. Isso ocorre porque, com as cópias apagadas, pelo menos o registro de data e hora do último comando (possivelmente repetido) muda sempre - e, com HISSTIMEFORMATo ajuste apropriado, history 1exibirá o registro de data e hora (diferente de fc) e, portanto, difere mesmo entre os comandos repetidos.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.