ZSH Gem #8: Hook function chpwd()

Posted by | Comments (2) | Trackbacks (2)

There is a number of magic functions called hook functions in ZSH which are automatically executed under certain circumstances. One of these functions is chpwd() and it is executed each time you change the current working directory.

This doesn't seem to be too exciting, but it can be pretty useful to know this little function. One thing that is often accomplished with this hook function is to change the title of your graphical terminal emulator (e.g. xterm) every time you change the working directory. With just the default configuration, ZSH doesn't show anything in the title bar of your xterm or xterm compatible TE, but we can change that. What we need to do is to write some escape sequences to STDOUT every time the directory is changed. For this we use print because with the -P parameter we can expand prompt escape sequences such as %n for $USERNAME or %~ for the current working directory (with home directories replaced with ~).

print -Pn "\e]2;%~\a"

This little code snippet changes the title of your current xterm (note: for other terminal types, the code looks a little different). Let me explain, what it does exactly. First it uses the print command with the already explained parameter -P. The second parameter -n just suppresses insertion of a newline character at the end. Until here it's easy. The more complex part is the expression itself. But also this isn't as hard to understand as it seems. The first part \e] just introduces an xterm escape command. \e is the ASCII form of the special ESC character (alternate form: \033). The number specifies what type of command it is. 0 sets the window icon name (don't ask me about that) and the window title, 1 sets only the icon name and 2 only the window title. The following semicolon ends the command sequence. Everything up to the next following BEL character (ASCII form \a or \007) is interpreted as the string to take either for the icon name or the window title (or both). In our case we have the Z Shell prompt escape sequence %~ which will expand to the current working directory.

Now if we put this in our chpwd() function, every time the working directory is changed, the window title is updated.

function chpwd() {
    print -Pn "\e]2;%~\a"
}

If you place this in your .zshrc, every new ZSH instance will use this setting. Of course you can also write things such as the user and the host to the window title:

function chpwd() {
    print -Pn "\e]2;%n@%M: %~\a"
}

I've put a list of all the prompt escape sequences in the links below.

What else could we use chpwd() for? Well, you can of course not only update the window title with it. You can also do things like sourcing ZSH config files automatically:

function chpwd() {
    if [ -r $PWD/.zsh_config ]; then
        source $PWD/.zsh_config
    fi
}

If there is a file called .zsh_config in the current working directory, it is automatically sourced. This can be useful if you need special settings for a directory such as a different prompt. But be careful with this! It can be very dangerous because you can't control the contents of such a file before it is executed! Sometimes it is better to do folder-specific configurations directly inside the chpwd() function:

function chpwd() {   
    if [[ $PWD == '/home/johndoe' ]]; then
        echo "Hi, you're now entering John's home directory!"
        
        if [[ $PROMPT_OLD != "" && $PROMPT_OLD != $PROMPT ]]; then
            PROMPT=$PROMPT_OLD
        fi
        PROMPT_OLD=$PROMPT
        PROMPT="(john's home) $PROMPT"
    else
        PROMPT=$PROMPT_OLD
    fi
}

There are lots of possibilities. You can do whatever you want with this function. But what if you don't want to override the chpwd() function directly (e.g. because you have several actions and you want to keep them modular or you don't want too override some pre-defined behavior)? Then you can also use the shell parameter $chpwd_functions. This is an array of function names. All of these functions are executed in order when changing the current working directory.

function my_special_chpwd_function() {
    echo "Hello World"
}
chpwd_functions=(${chpwd_functions[@]} "my_special_chpwd_function")

You can add as many functions as you want to this array. If a function does not exist, it is skipped silently. If a function produces an error, execution is stopped for all subsequent functions.

Read more about chpwd():

Trackbacks

Comments

There have been 2 comments submitted yet. Add one as well!
Bryan Bugyi
Bryan Bugyi wrote on : (permalink)
I just finished writing a script that provides a safer and more convenient solution for defining local aliases and functions (like you could use the .zsh_config method above for). If interested in this functionality, check it out: github://bbugyi200/LocalAlias
Lucius
Lucius wrote on : (permalink)
The last section on the parameter array is really helpful. Thanks.

Write a comment:

E-Mail addresses will not be displayed and will only be used for E-Mail notifications.

By submitting a comment, you agree to our privacy policy.

Design and Code Copyright © 2010-2024 Janek Bevendorff Content on this site is published under the terms of the GNU Free Documentation License (GFDL). You may redistribute content only in compliance with these terms.