In bash, from inside PROMPT_COMMAND, is there a way to tell if the user just hit 'return' and didn't enter a command?
4 Answers
Check whether the history number was incremented. A cancelled prompt or a prompt where the user just pressed Enter won't increment the history number.
The history number is available in the variable HISTCMD
, but this is not available in PROMPT_COMMAND
(because what you want there is in fact the history number of the previous command; the command that executes PROMPT_COMMAND
itself has no history number). You can get the number from the output of 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'
Note that if you've turned on squashing of duplicates in the history (HISTCONTROL=ignoredups
or HISTCONTROL=erasedups
), this will mistakenly report an empty command after running two identical commands successively.

- 829,060
There is a workaround, but it has some requirements:
You need to set $HISTCONTROL
to save ALL commands, also duplicates and spaces. So set:
HISTCONTROL=
Now define a function to call as $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"
}
Now, set the $PROMPT_COMMAND
variable:
PROMPT_COMMAND="isnewline"
See the output:
user@host:~$ true
user@host:~$ <return>
User hit return
user@host:~$ <space><return>
user@host:~$

- 48,171
-
I don't understand why you're using a temporary file here. The variable
last
is preserved from one invocation ofisnewline
to the next (only pick a less generic name likeprompt_command__isnewline__last
to avoid clashes). – Gilles 'SO- stop being evil' Sep 02 '15 at 20:53 -
-
Thanks, chaos. I used the same idea for the following, which is a bit easier to parse.
– user Sep 03 '15 at 21:26HISTCONTROL="" 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
I don’t know of a way to do that, per se. But you can get the same effect by using
trap some_command_or_function debug
This will causes the some_command_or_function
to be called
any time you run a command.
The tricky thing is, it will not be called if you just hit Enter —
unless you have a PROMPT_COMMAND defined,
in which case hitting Enter invokes the PROMPT_COMMAND,
which, in turn, triggers the trap.
Perhaps the simplest way to achieve the result that you want is to define a debug trap function instead of using a PROMPT_COMMAND. But I can’t tell, because I don’t know what result you want. If you want something to happen when you just hit Enter, and something different/additional to happen when you type a command, then (AFAIK) you need to use a debug trap and a PROMPT_COMMAND. See this answer and this one for a way to make the two mechanisms play together nicely.

- 10,519
(This would have been a comment to the accepted answer if I had been allowed to add comments...) @schlimmen, you may set HISTTIMEFORMAT
to something like HISTTIMEFORMAT='%F %T '
and then save and compare history 1
. It's because with erasedups at least the timestamp of the (possibly repeated) last command changes every time --- and with HISSTIMEFORMAT
appropriately set, history 1
will display the timestamp (unlike fc
), and thus differ even between the repeated commands.
${HISTCMD_previous%%$'[\t ]'*}
bit was missing the$'…'
and ended up truncating after\
,t
or space instead of after tab or space, but bash prints a tab. – Gilles 'SO- stop being evil' Sep 04 '15 at 07:40