OS X Lion has "Resume" feature, i. e. when you reopen an app it restores all windows and their contents. That works for Terminal as well. But if you use Zsh instead of Bash it doesn't restore opened directory. How can I fix this?

  • Related to the answers below: making terminal.app aware of the directory is also useful for opening new terminals in the same directory as the current one
    – nhooyr
    Jun 13, 2019 at 10:27

2 Answers 2


UPDATE: This isn't entirely correct, for reasons mentioned in the comments. Use the answer below. Thanks @ChrisPage for going the extra mile :)

The answer can be found by reverse engineering how bash does it in /etc/bashrc. I tried many approaches from around the net but Apple's way seems to work best (go figure).

In your .zshrc add the following

# Set Apple Terminal.app resume directory
if [[ $TERM_PROGRAM == "Apple_Terminal" ]] && [[ -z "$INSIDE_EMACS" ]] {
  function chpwd {
    local SEARCH=' '
    local REPLACE='%20'
    local PWD_URL="file://$HOSTNAME${PWD//$SEARCH/$REPLACE}"
    printf '\e]7;%s\a' "$PWD_URL"


Happy resuming.

For clarify, this answer pertains to the mysterious message in OS X Lion's Terminal.app preferences:

**Programs notify Terminal of the current working directory using escape sequences. You may need to configure your shell or other programs to enable this behavior.*

This answer works when you're using zsh as your shell. Terminal Resume for bash has already been implemented by Apple.

  • 1
    Probably not a big thing in practice, but I see the stock /etc/bashrc has the last line of chpwd as printf '\e]7;%s\a' "$PWD_URL" with the double quotes. Thanks for the tip. Aug 2, 2011 at 19:11
  • This is now making its way into oh-my-zsh (see github.com/robbyrussell/oh-my-zsh/pull/522). You'll need to make sure you've turned on the osx plugin in your zshrc. Aug 3, 2011 at 17:06
  • 2
    Also note that this code only percent-encodes spaces. For bonus points, make it percent-encode all illegal URL characters (and see if you can do it without invoking any programs). This is important if you want it to work with all valid pathnames. Also, some characters aren't even considered part of escape sequences, so percent-encoding is required to get them to the terminal. I was able to do this for bash, but I haven't tried testing it with zsh.
    – Chris Page
    Aug 19, 2011 at 11:08
  • 1
    The quotes around "$PWD_URL" are required to prevent the pathname from being munged. EDIT: This is required in bash, but optional in zsh. I prefer to use the quotes consistently so it's portable.
    – Chris Page
    Aug 26, 2011 at 0:50
  • Thanks Ryan, Chris. I've updated the script to use the double quotes for consistency. Aug 29, 2011 at 6:21

Here's my adaptation of /etc/bashrc for zsh. I've included percent-encoding of all URL characters that require it, which is important if you want this to work with all valid file and directory names.

This registers a precmd hook, which allows more than one function to be registered in other scripts and configuration files.

UPDATED March 2019: Set LC_ALL to empty so it doesn’t override LC_CTYPE. Use precmd to update the working directory at each prompt instead of using chpwd to update it every time it is changed—command pipelines may change it temporarily and the terminal shouldn’t display those. Also, it can be helpful to have each prompt update the terminal state in case it was changed during the previous command. Use printf -v to explicitly write to the variable instead of using subshell syntax.

# Tell the terminal about the working directory whenever it changes.

if [[ "$TERM_PROGRAM" == "Apple_Terminal" ]] && [[ -z "$INSIDE_EMACS" ]]; then

    update_terminal_cwd() {
        # Identify the directory using a "file:" scheme URL, including
        # the host name to disambiguate local vs. remote paths.

        # Percent-encode the pathname.
        local url_path=''
            # Use LC_CTYPE=C to process text byte-by-byte. Ensure that
            # LC_ALL isn't set, so it doesn't interfere.
            local i ch hexch LC_CTYPE=C LC_ALL=
            for ((i = 1; i <= ${#PWD}; ++i)); do
                if [[ "$ch" =~ [/._~A-Za-z0-9-] ]]; then
                    printf -v hexch "%02X" "'$ch"

        printf '\e]7;%s\a' "file://$HOST$url_path"

    # Register the function so it is called at each prompt.
    autoload add-zsh-hook
    add-zsh-hook precmd update_terminal_cwd
  • Thanks, the accepted solution didn't work for me, but this one does.
    – eelco
    Sep 8, 2011 at 10:00
  • This one is working for me as well.
    – sikachu
    Feb 6, 2012 at 22:13
  • 4
    It should also be noted that this solution is already in oh-my-zsh, just activate the terminalapp plugin.
    – Simon
    Dec 16, 2013 at 10:11
  • 2
    Just to be clear, @Simon means this is now in oh-my-zsh, added since this answer was written.
    – Chris Page
    Dec 16, 2013 at 22:27
  • 1
    @ChrisPage: Thanks for this. I installed oh-my-zsh to get this feature, but have uninstalled it because it did too much nonsense. Your answer works great. Anyway, for those who have installed oh-my-zsh, they can put plugins=(terminalapp) (or a list, like plugins=(git osx terminalapp) say) in their ~/.zshrc to get exactly the contents of your answer loaded for them. May 11, 2015 at 20:56

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .