Как выполнить функцию в bash или zsh при вводе каждой буквы в командной строке?

Как выполнить функцию в bash или zsh при вводе каждой буквы в командной строке?

Я знаю оpreexec()Хуки для zsh и способ, которым этого можно добиться в bash. (связь)

Но могу ли я получитьтекущий входпродолжая печатать?

Идея этого вопроса следующая:

Чтобы ускорить изучение команд, аргументов и сочетаний клавиш, я хочу найти вводимую команду в «базе данных», предоставляющей подсказки «помощь / полезно знать / сочетания клавиш» и показать их в другом сеансе с screen/tmux во время ввода в другом сеансе.

Можно ли проверить текущую набираемую команду? Если это не работает при каждом нажатии клавиши, то цикл таймера может сработать.

решение1

Я могу ответить только за то zsh, где это можно сделать, да.

Во-первых, уже есть некоторые виджеты дляпостепенное завершение. Первый, по-видимому, принадлежит Y. Fujii. Хотяего сайтна японском языке, вы легко поймете, не зная этого языка, как он работает и как им пользоваться. Авто-фуявляется расширением оригинального сценария.

Пока что ссылки. zshВредактор строк zsh( zle) отвечает за интерактивное использование командной строки. Помимо множества других переменных, предоставляемых виджетам (см. man zshzle), они представляют для вас интерес, поскольку вы хотите захватитьтекущая командная строка:

$БУФЕР: Все содержимое буфера редактирования.

$LBUFFER: Часть буфера, которая находится слева от позиции курсора.

$RBUFFER: Часть буфера, которая находится справа от позиции курсора.

Эти переменные доступны для записи, что изменит текущую командную строку!

Чтобы захватить каждое нажатие клавиши, вы можете изменить виджет self-insert, который выполняется (по умолчанию) для каждого нажатия клавиши, кроме LFили CR. Вот пример, который не делает ничего полезного, но добавляет для каждого нажатия клавиши точку $RBUFFER— просто для иллюстрации того, как это работает:

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— это встроенный виджет, поэтому мы не попадаем в бесконечный цикл.

Итак, вы можете либо начать с нуля, либо начать со скрипта Fujii и модифицировать его. Одним из преимуществ последнего является то, что он также выполняет некоторую обработку удаления нажатий клавиш, которую я здесь проигнорировал.

решение2

Для Bash вы можете создать следующий 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

Это простой скрипт, который получает некоторые коды клавиатуры и выводит их на экран. Теперь передайте ему коды клавиатуры:

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

Теперь, если вы введете в другом терминале, он должен получить значения клавиш. Я не знаю, есть ли какой-нибудь умный способ сопоставить коды клавиш с их значениями ASCII, поэтому я просто делаю простое сопоставление. Вы можете улучшить этот код, чтобы он реагировал и на другие клавиши. Однако обратите внимание, что скрипт будет получать весь ввод с клавиатуры, а не только передаваться на один заданный терминал.

Что касается самой задачи (проверки текущей набираемой команды), то вы можете использовать ее compgen -cдля генерации списка возможных завершений на основе переданного аргумента:

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

Связанный контент