Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a hook in Bash to find out when the cwd changes?

Tags:

bash

zsh

cd

cwd

I am usually using zsh, which provides the chpwd() hook. That is: If the cwd is changed by the cd builtin, zsh automatically calls the method chpwd() if it exists. This allows to set up variables and aliases which depend on the cwd.

Now I want to port this bit of my .zshrc to bash, but found that chpwd() is not recognized by bash. Is a similar functionality already existing in bash? I'm aware that redefining cd works (see below), yet I'm aiming for a more elegant solution.

function cd()
{
    builtin cd $@
    chpwd
}
like image 273
Stefan Majewsky Avatar asked Jul 18 '10 16:07

Stefan Majewsky


2 Answers

You would have to use a DEBUG trap or PROMPT_COMMAND.

Examples:

trap chpwd DEBUG        # calls the function before each command

PROMPT_COMMAND=chpwd    # calls the function after each command

Note that the function defined in PROMPT_COMMAND is run before each prompt, though, even empty ones.

like image 138
Dennis Williamson Avatar answered Oct 15 '22 07:10

Dennis Williamson


A better solution could be defining a custom chpwd hook.

There's not a complete hook system designed in Bash when compared with other modern shells. PROMPT_COMMAND variable is used as a hook function, which is equivalent to precmd hook in ZSH, fish_prompt in Fish. For the time being, ZSH is the only shell I've known that has a chpwd hook builtin.

PROMPT_COMMAND

If set, the value is interpreted as a command to execute before the printing of each primary prompt ($PS1).

https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Bash-Variables

chpwd Hook in Bash

A trick is provided to setup a chpwd equivalent hook in Bash based on PROMPT_COMMAND.

# create a PROPMT_COMMAND equivalent to store chpwd functions
typeset -g CHPWD_COMMAND=""

_chpwd_hook() {
  shopt -s nullglob

  local f

  # run commands in CHPWD_COMMAND variable on dir change
  if [[ "$PREVPWD" != "$PWD" ]]; then
    local IFS=$';'
    for f in $CHPWD_COMMAND; do
      "$f"
    done
    unset IFS
  fi
  # refresh last working dir record
  export PREVPWD="$PWD"
}

# add `;` after _chpwd_hook if PROMPT_COMMAND is not empty
PROMPT_COMMAND="_chpwd_hook${PROMPT_COMMAND:+;$PROMPT_COMMAND}"

Usage

# example 1: `ls` list directory once dir is changed
_ls_on_cwd_change() {
  ls
}

# append the command into CHPWD_COMMAND
CHPWD_COMMAND="${CHPWD_COMMAND:+$CHPWD_COMMAND;}_ls_on_cwd_change"

# or just use `ls` directly
CHPWD_COMMAND="${CHPWD_COMMAND:+$CHPWD_COMMAND;}ls"

Source: Create chpwd Equivalent Hook in Bash from my gist.

like image 39
Simba Avatar answered Oct 15 '22 08:10

Simba