В bash, изнутри PROMPT_COMMAND, есть ли способ узнать, нажал ли пользователь «возврат» и не ввел ли команду?
В bash, изнутри PROMPT_COMMAND, есть ли способ узнать, нажал ли пользователь «возврат» и не ввел ли команду?
Ответы:
Проверьте, был ли увеличен номер истории. Отмененный запрос или запрос, когда пользователь только что нажал Enter, не будет увеличивать номер истории.
Номер истории доступен в переменной HISTCMD
, но он недоступен в PROMPT_COMMAND
(потому что на самом деле вы хотите получить номер истории предыдущей команды; команда, которая выполняется PROMPT_COMMAND
сама по себе, не имеет номера истории). Вы можете получить номер из вывода 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'
Обратите внимание, что если вы включили в дублирование дубликатов в истории ( HISTCONTROL=ignoredups
или HISTCONTROL=erasedups
), это приведет к ошибочному сообщению о пустой команде после последовательного выполнения двух одинаковых команд.
${HISTCMD_previous%%$'[\t ]'*}
бит пропускал $'…'
и заканчивал усечением после `,
t` или пробела, а не после табуляции или пробела, но bash печатает табуляцию.
Существует обходной путь, но у него есть некоторые требования:
Вам необходимо настроить $HISTCONTROL
сохранение ВСЕХ команд, а также дубликатов и пробелов. Итак, установите:
HISTCONTROL=
Теперь определите функцию для вызова как $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"
}
Теперь установите $PROMPT_COMMAND
переменную:
PROMPT_COMMAND="isnewline"
Смотрите вывод:
user@host:~$ true
user@host:~$ <return>
User hit return
user@host:~$ <space><return>
user@host:~$
last
сохраняется от одного вызова isnewline
к другому (выбирайте только менее общее имя, prompt_command__isnewline__last
чтобы избежать конфликтов).
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
Я не знаю способ сделать это, сами по себе . Но вы можете получить тот же эффект, используя
trap some_command_or_function debug
Это заставит some_command_or_function
вызываться каждый раз, когда вы запускаете команду. Хитрость в том, что он не будет вызываться, если вы просто нажмете Enter- если только у вас не определен PROMPT_COMMAND, в этом случае Enterнажатие вызывает PROMPT_COMMAND, что, в свою очередь, вызывает ловушку.
Возможно, самый простой способ достичь желаемого результата - определить функцию отладочной ловушки вместо использования PROMPT_COMMAND. Но я не могу сказать, потому что я не знаю, какой результат вы хотите. Если вы хотите, чтобы что-то происходило, когда вы просто нажимаете Enter, и что-то другое / дополнительное, когда вы набираете команду, тогда (AFAIK) вам нужно использовать отладочную ловушку и PROMPT_COMMAND. Посмотрите этот ответ и этот, чтобы узнать, как эти два механизма хорошо играют вместе.
(Это был бы комментарий к принятому ответу, если бы мне было позволено добавлять комментарии ...) @schlimmen, вы можете установить HISTTIMEFORMAT
что-то подобное, HISTTIMEFORMAT='%F %T '
а затем сохранить и сравнить history 1
. Это связано с тем, что при erasedups, по крайней мере, метка времени (возможно, повторяющейся) последней команды изменяется каждый раз - и при HISSTIMEFORMAT
соответствующей установке history 1
будет отображаться метка времени (в отличие от fc
), и, таким образом, будет отличаться даже между повторяющимися командами.