сказать, была ли последняя команда пустой в PROMPT_COMMAND


12

В bash, изнутри PROMPT_COMMAND, есть ли способ узнать, нажал ли пользователь «возврат» и не ввел ли команду?

Ответы:


7

Проверьте, был ли увеличен номер истории. Отмененный запрос или запрос, когда пользователь только что нажал 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), это приведет к ошибочному сообщению о пустой команде после последовательного выполнения двух одинаковых команд.


Спасибо, Жиль. Я что-то здесь упускаю. Кажется, что это никогда не выполняется, так как помещение 'echo hello' в первую строку литеральной функции не работает, хотя PROMPT_COMMAND = 'echo hello' работает. Я думал, что это может быть проблема HISTCMD_previous против HISTCMD_PREVIOUS, но не игра в кости. Я продолжу тыкать, но я комментирую, так как ваш баш-фу явно выше моей.
Пользователь

@user Я исправил больше опечаток, в частности, ${HISTCMD_previous%%$'[\t ]'*}бит пропускал $'…'и заканчивал усечением после `, t` или пробела, а не после табуляции или пробела, но bash печатает табуляцию.
Жиль "ТАК - перестать быть злым"

1
Это решение основано на предположении, что дубликаты сохраняются в истории (что для меня выключено). Следовательно, это решение не работает должным образом для повторных команд, в то время как дубликаты не сохраняются в истории.
schlimmchen

4

Существует обходной путь, но у него есть некоторые требования:

Вам необходимо настроить $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
Пользователь

1

Я не знаю способ сделать это, сами по себе . Но вы можете получить тот же эффект, используя

trap some_command_or_function debug

Это заставит some_command_or_functionвызываться каждый раз, когда вы запускаете команду. Хитрость в том, что он не будет вызываться, если вы просто нажмете Enter- если только у вас не определен PROMPT_COMMAND, в этом случае Enterнажатие вызывает PROMPT_COMMAND, что, в свою очередь, вызывает ловушку.

Возможно, самый простой способ достичь желаемого результата - определить функцию отладочной ловушки вместо использования PROMPT_COMMAND. Но я не могу сказать, потому что я не знаю, какой результат вы хотите. Если вы хотите, чтобы что-то происходило, когда вы просто нажимаете Enter, и что-то другое / дополнительное, когда вы набираете команду, тогда (AFAIK) вам нужно использовать отладочную ловушку и PROMPT_COMMAND. Посмотрите этот ответ и  этот, чтобы узнать, как эти два механизма хорошо играют вместе.


0

(Это был бы комментарий к принятому ответу, если бы мне было позволено добавлять комментарии ...) @schlimmen, вы можете установить HISTTIMEFORMATчто-то подобное, HISTTIMEFORMAT='%F %T 'а затем сохранить и сравнить history 1. Это связано с тем, что при erasedups, по крайней мере, метка времени (возможно, повторяющейся) последней команды изменяется каждый раз - и при HISSTIMEFORMATсоответствующей установке history 1будет отображаться метка времени (в отличие от fc), и, таким образом, будет отличаться даже между повторяющимися командами.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.