В bash, зсередини PROMPT_COMMAND, чи є спосіб сказати, чи користувач просто натиснув "return" і не ввів команду?
В bash, зсередини PROMPT_COMMAND, чи є спосіб сказати, чи користувач просто натиснув "return" і не ввів команду?
Відповіді:
Перевірте, чи збільшено номер історії. Скасований запит або підказка, коли користувач щойно натиснув 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
Я не знаю спосіб зробити це, самі по собі . Але такий же ефект можна отримати, використовуючи
пастка some_command_or_function налагодження
Це призведе some_command_or_function
до виклику кожного разу, коли ви запускаєте команду. Справа в тому, що він не буде викликаний, якщо ви просто натиснете Enter- якщо у вас не визначено PROMPT_COMMAND, у цьому випадку натискання Enterвикликає PROMPT_COMMAND, що, в свою чергу, запускає пастку.
Мабуть, найпростіший спосіб досягти бажаного результату - це визначити функцію пастки налагодження замість використання PROMPT_COMMAND. Але я не можу сказати, тому що я не знаю, якого результату ви хочете. Якщо ви хочете, щоб щось траплялося, коли ви просто натискаєте Enter, і щось друге / додаткове трапляється, коли ви вводите команду, тоді (AFAIK) вам потрібно використовувати пастку налагодження та PROMPT_COMMAND. Дивіться цю відповідь, і це - спосіб змусити два механізми гарно грати разом.
(Це був би коментар до прийнятої відповіді, якби мені дозволили додати коментарі ...) @schlimmen, ви можете встановити HISTTIMEFORMAT
щось на кшталт, HISTTIMEFORMAT='%F %T '
а потім зберегти та порівняти history 1
. Причиною цього є те, що при видаленні часу принаймні часова мітка (можливо повторювана) остання команда змінюється щоразу --- і при HISSTIMEFORMAT
належному встановленні history 1
буде відображати часову позначку (на відміну від цього fc
) і, таким чином, відрізнятися навіть між повторними командами.