Como eu posso digitar um comando para executar quando o comando atual é concluído?

3

Eu tenho uma função ( not ) que exibe uma notificação. Por isso, posso usá-lo para mostrar quando um comando está completo.

sleep 5; not

No entanto, às vezes esqueço-me de adicionar ;not . No terminal do OS X (alguns anos atrás), eu poderia inserir um segundo comando, enquanto o comando atual estava em execução. Este segundo comando seria executado após o primeiro ter terminado.

Assim, digite sleep 5 Enter e, em seguida, digite not Enter . Após sleep ter terminado, not seria executado.

No entanto, minha experiência no Linux é que isso não ocorre. Depois que sleep terminar, a linha de comando mostrará not , mas o Enter nunca será registrado. Eu testei Terminator, Konsole e um tty.

Esse comportamento depende do emulador de terminal e, em caso afirmativo, há algum que funcione como eu quero? Alternativamente, existe uma maneira de fazer esta função funcionar no meu terminal de escolha (Terminator)?

Testando em diferentes shells

Não funciona, ou seja, o segundo comando não se registra:

  • bash
  • bash --norc
  • bash --norc --noprofile
  • sh

Funciona, ou seja, o segundo comando é registrado:

  • bash --norc --noprofile --noediting
  • zsh

Eu removi seletivamente as linhas de ~/.inputrc e testei novamente com meu shell bash padrão. Eu segui o problema até a linha seguinte. Quando removido, o segundo comando é registrado conforme o esperado.

Control-j: menu-complete

Curiosamente, se eu tentar ligar (digamos) Ctrl + i , não há problema. Por que essa entrada impede que o segundo comando se registre, e existe uma maneira de continuar usando Ctrl + j para menu-complete , tendo o comportamento que desejo para esse segundo comando?

    
por Sparhawk 16.01.2016 / 08:49

2 respostas

1

Bem, de acordo com algumas de suas edições, você tem CTRL+J ligado a um comando bindkey macro. Isso explica seu problema de bash considerando o comportamento padrão de readline .

Geralmente, readline lê a entrada em algo muito parecido com o modo stty raw . Os caracteres de entrada são lidos assim que são digitados e o editor de linha do shell manipula seu próprio buffer. readline define o terminal como raw quando recebe o primeiro plano e o restaura para qualquer estado anterior ao chamar outro grupo de processos em primeiro plano.

CTRL+J é uma nova linha ASCII. ABCDEFGHIJ é 10 bytes do NUL. Como você configurou readline para comer esse caractere e, subsequentemente, expandir o que resta de qualquer linha de comando em que ele faz com a conclusão do menu, a digitação antecipada não funcionará. O terminal está em um estado diferente quando a digitação antecipada é armazenada em buffer pela disciplina de linha do kernel do que quando readline está em primeiro plano.

Quando readline está no primeiro plano, ele faz sua própria tradução para os retornos de transporte de entrada - > novas linhas e o driver do terminal não o converte em nada. Quando você insere sua entrada de digitação antecipada, no entanto, o driver do terminal geralmente traduz retornos para novas linhas conforme pode ser configurado com stty [-]icrnl . E assim, sua chave de retorno é suficiente para os comandos inseridos ao vivo, mas as novas linhas enviadas pela linha de disciplina do terminal estão sendo interpretadas como comandos de menu completo.

Você pode dizer ao driver do terminal para parar essa tradução com stty -icrnl . É provável que isso leve pelo menos um pouco de tempo para se acostumar. Outros comandos que aceitam entrada de terminal geralmente esperam novas linhas ao invés de retornos, e assim você terá que usar explicitamente CTRL+J quando eles controlarem o primeiro plano, ou então ensiná-los a manipular os retornos como bash .

Você já mencionou que read não funciona como esperado ao ler o terminal. Novamente, é provável que você use explicitamente CTRL+J para finalizar uma linha de entrada. Ou ... você pode ensinar:

read()
    if    [ -t 0 ]
    then  command read -d $'\r' "$@"
    else  command read "$@"
    fi

Provavelmente será muito menos trabalhoso a longo prazo se você encontrar uma chave diferente para o menu completo, no entanto. As novas linhas são muito importantes para a maioria dos aplicativos de terminal.

    
por 16.01.2016 / 13:23
3

Supondo que você esteja usando o bash: tente pressionar ^ Z (ou seja, Ctrl-Z) para parar o processo, mova-o para o segundo plano e obtenha outro prompt bash. Tipo fg; not , o primeiro continua o processo parado e retorna quando termina.

Como alternativa, descubra o ID do processo do programa que você deseja aguarde, suponha que é 2342. Em um novo, digite

until kill -0 2342; do sleep 1; done; not

isso irá verificar a cada segundo.

    
por 16.01.2016 / 14:23