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

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

Eu sei sobrepréexec()ganchos para zsh e a maneira como isso pode ser feito no bash. (link)

Mas posso pegar oentrada atualenquanto ainda digita?

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

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

É possível verificar o comando atual que está sendo digitado? Se não funcionar a cada pressionamento de tecla, um loop de temporizador também poderá funcionar.

Responder1

Só posso responder zshonde isso pode ser feito, sim.

Primeiro, já existem alguns widgets paraconclusão incremental. O primeiro é aparentemente o de Y. Fujii. Emboraseu siteestá em japonês, você pode descobrir facilmente, sem falar esse idioma, como funciona e como usá-lo. Fu automáticoé uma extensão do script original.

Até agora as referências. Nozsheditor de linha zsh( zle) é responsável pelo uso interativo da linha de comando. Além de muitas outras variáveis ​​fornecidas aos widgets (consulte Recursos man zshzle), elas são de seu interesse, pois você deseja capturar olinha de comando atual:

$BUFFER: todo o conteúdo do buffer de edição.

$LBUFFER: A parte do buffer que fica à esquerda da posição do cursor.

$RBUFFER: A parte do buffer que fica à direita da posição do cursor.

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-insertque é executado (por padrão) para cada pressionamento de tecla, exceto LFou CR. Aqui está um exemplo, que não faz nada de muito útil, mas acrescenta um ponto a cada pressionamento de tecla $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 integrado, então não entramos em um loop infinito.

Portanto, você pode começar do zero ou partir do script do Fujii e modificá-lo. Um benefício deste último é que ele também lida com a exclusão de pressionamentos de tecla que negligenciei aqui.

Responder2

Para Bash você pode criar o seguinte test.shscript:

#!/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 recebe alguns códigos do teclado e os imprime na tela. Agora passe os códigos do teclado para ele:

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

Agora, se você digitar em outro terminal, ele deverá receber valores-chave. 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ê também pode melhorar esse código para reagir a outras chaves. Observe, entretanto, que o script receberá todas as entradas do teclado, não apenas passadas para um determinado terminal.

Quanto à tarefa em si (verificando o comando atual que está sendo digitado), você pode usar compgen -cpara gerar uma lista de possíveis conclusões com base no argumento passado:

 $ compgen -c 'ls' | head -1
 ls
 $ compgen -c 'lsp' | head -1
 lspci

informação relacionada