Does bash have a hook that is run before executing a command?

Solution 1:

Not natively, but it can be hacked up using the DEBUG trap. This code sets up preexec and precmd functions similar to zsh. The command line is passed as a single argument to preexec.

Here is a simplified version of the code to set up a precmd function that is executed before running each command.

preexec () { :; }
preexec_invoke_exec () {
    [ -n "$COMP_LINE" ] && return  # do nothing if completing
    [ "$BASH_COMMAND" = "$PROMPT_COMMAND" ] && return # don't cause a preexec for $PROMPT_COMMAND
    local this_command=`HISTTIMEFORMAT= history 1 | sed -e "s/^[ ]*[0-9]*[ ]*//"`;
    preexec "$this_command"
}
trap 'preexec_invoke_exec' DEBUG

This trick is due to Glyph Lefkowitz; thanks to bcat for locating the original author.

Edit. An updated version of Glyph's hack can be found here: https://github.com/rcaloras/bash-preexec

Solution 2:

You can use the trap command (from help trap):

If a SIGNAL_SPEC is DEBUG, ARG is executed before every simple command.

For example, to change the terminal title dynamically you may use:

trap 'echo -ne "\e]0;$BASH_COMMAND\007"' DEBUG

From this source.

Solution 3:

It's not a shell function that gets executed, but I contributed a $PS0 prompt string that is displayed before each command is run. Details here: http://stromberg.dnsalias.org/~strombrg/PS0-prompt/

$PS0 is included in bash 4.4, though it'll take a while for most Linuxes to include 4.4 - you can build 4.4 yourself if you want though; in that case, you probably should put it under /usr/local, add it to /etc/shells and chsh to it. Then log out and back in, perhaps sshing to yourself@localhost or suing to yourself first as a test.

Solution 4:

I recently had to solve this exact problem for a side project of mine. I made a fairly robust and resilient solution that emulates zsh's preexec and precmd functionality for bash.

https://github.com/rcaloras/bash-preexec

It was originally based off Glyph Lefkowitz's solution, but I've improved on it and brought it up to date. Happy to help or add a feature if needed.