ZSH – Equivalent of BASH’s $PROMPT_COMMAND

bashenvironment-variablesshellzsh

BASH supports a $PROMPT_COMMAND environment variable that defines a command to be executed before any first-level interactive prompt. I'm looking for a ZSH equilvalent of that.

The documentation says that there's a function precmd I can define to achive that; however, I have no idea how to define it from an environment variable.

I've considered passing an environment variable that would make ZSH read a file containing the definition of that function, but ZSH doesn't seem to support such things: it only reads global files and then per-user files. I can replace them but I cannot add to them without modifying the files, which I cannot do.

So how do I define a pre-prompt hook in ZSH via an environment variable, like I'd do using $PROMPT_COMMAND in BASH?

Best Answer

The simplest approach to emulate bash's $PROMPT_COMMAND which comes to my mind is to use the precmd hook, as you already figured out. Define it as

precmd() { eval "$PROMPT_COMMAND" }

and you can do something like that:

$ PROMPT_COMMAND='echo Hello, it is now $(date)'
Hello, it is now Mon, Mar 31, 2014 7:08:00 PM
$ whoami      
user
Hello, it is now Mon, Mar 31, 2014 7:08:21 PM     
$

Please note the single quotes in that example, otherwise $(date) will get expanded too early, i.e. already when defining $PROMPT_COMMAND and not when called before the prompt.


If you want to preserve (and don't want to alter) the existing definition, you can use that approach:

$ prmptcmd() { eval "$PROMPT_COMMAND" }
$ precmd_functions=(prmptcmd)

With that the prmptcmd functions is executed after the existing precmd() function.


Finally, here is a way which is suitable for use in a program package, which neither should modify user or system files nor can enter the commands interactive.

An example to spawn a bash session could be

PROMPT_COMMAND="echo foo" bash

To spawn zsh you can use

ZDOTDIR=/program/dir zsh

which causes /program/dir/.zshrc to be sourced. In this file the precmd() hook can be defined as explained above. If you want the user's settings in addition include source $HOME/.zshrc etc. in the program's .zshrc, too. This setup is maintainable, as no files outside the program directory are modified.


As a last addition, here is a proof of concept how to keep the newuser welcome, too. Use the following code in your /program/dir/.zshenv rc config file:

echo define precmd, traps, etc.

autoload -Uz zsh-newuser-install

if [[ ! -e "$HOME/.zshrc" ]]; then
  zsh-newuser-install -f
  mv $ZDOTDIR/.zshrc $HOME/.zshrc
else
  builtin source $HOME/.zshrc
fi
Related Question