Como executar uma função no bash ou zsh em cada letra sendo digitada no prompt?

3

Eu sei sobre preexec () ganchos para zsh e como isso pode ser alcançado no bash. ( link )

Mas posso obter a entrada atual enquanto digito?

A ideia por trás dessa pergunta é a seguinte:

para permitir um aprendizado mais rápido de comandos, argumentos e atalhos, eu quero pesquisar o comando que está sendo digitado em um "banco de dados" fornecendo dicas de "ajuda / bom para saber / atalho" e mostrá-las em outra sessão com screen / tmux ao digitar o outro.

É possível verificar o comando atual sendo digitado? Se não funcionar em todas as teclas, um loop temporizador pode funcionar também.

    
por nifr 07.06.2013 / 08:10

2 respostas

3

Eu só posso responder por zsh , onde isso pode ser feito, sim.

Primeiro, já existem alguns widgets para conclusão incremental . O primeiro é aparentemente o de Y. Fujii. Embora o seu site esteja em japonês, você pode descobrir facilmente sem falar esse idioma, como funciona e como usar isto. Auto-fu é uma extensão do script original.

Até agora, as referências. Em zsh , o editor de linhas zsh ( zle ) é responsável pelo uso interativo da linha de comando. Além de muitas outras variáveis fornecidas para widgets (veja man zshzle ), estas são de interesse para você como você deseja capturar a linha de comando atual :

$BUFFER: The entire contents of the edit buffer.

$LBUFFER: The part of the buffer that lies to the left of the cursor position.

$RBUFFER: The part of the buffer that lies to the right of the cursor position.

Estas variáveis são graváveis, o que alterará a linha de comando atual!

Para capturar cada pressionamento de tecla, você pode modificar o widget self-insert que é executado (por padrão) para cada pressionamento de tecla, exceto LF ou CR . Aqui está um exemplo, que não faz nada muito útil, mas acrescenta, para cada tecla, um ponto a $RBUFFER - apenas para ilustrar como isso funciona:

function self-insert() {
  RBUFFER+="."
  # execute some other command, but ensure they don't produce any output.
  zle .self-insert
  }
zle -N self-insert

.self-insert é o widget incorporado, por isso não corremos para um ciclo infinito.

Então, você pode começar do zero ou começar do script do Fujii e modificá-lo. Um dos benefícios deste último é que ele também faz algumas manipulações de excluir pressionamentos de teclas que negligenciei aqui.

    
por 07.06.2013 / 10:58
2

Para o Bash, você pode criar o seguinte script test.sh :

#!/usr/bin/env bash

ARRAY=('1' '2' '3' '4' '5' '6' '7' '8' '9' '0' '-' '=' 'BACKSPACE' ''
'q' 'w' 'e' 'r' 't' 'y' 'u' 'i' 'o' 'p' '[' ']' 'NEWLINE' '' 
'a' 's' 'd' 'f' 'g' 'h' 'j' 'k' 'l' ';' "'" '' '' '' 'z' 'x' 'c' 
'v' 'b' 'n' 'm' '0' ',' '.' '/' '' '' 'SPACE')

while read row 
do
    if [[ "$row" == *press* ]]
    then
        index=$((${row/key press   /}-10))
        if [[ "${ARRAY[$index]}" == 'NEWLINE' ]] 
        then
                printf "\n"
        elif [[ "${ARRAY[$index]}" == 'BACKSPACE' ]] 
        then
            echo  -ne "\b \b"
        elif [[ "${ARRAY[$index]}" == 'SPACE' ]] 
        then
            printf " "
        else
            printf "%s" "${ARRAY[$index]}"
        fi
    fi
done

É um script simples que está recebendo alguns códigos de teclado e os imprime na tela. Agora passe os códigos de teclado para ele:

$ stdbuf -o0 xinput test 'AT Translated Set 2 keyboard' | bash test.sh

Agora, se você digitar outro terminal, ele deverá receber valores de chave. Eu não sei se existe alguma maneira inteligente de mapear códigos-chave para seus valores ASCII, então estou apenas fazendo um mapeamento simples. Você pode melhorar este código para reagir a outras teclas também. Note, entretanto, que o script receberá todas as entradas do teclado, não apenas passado para um determinado terminal.

Quanto à tarefa em si (verificando se o comando atual está sendo digitado), é possível usar compgen -c para gerar uma lista de possíveis conclusões com base no argumento transmitido:

 $ compgen -c 'ls' | head -1
 ls
 $ compgen -c 'lsp' | head -1
 lspci
    
por 07.06.2013 / 17:27