Remember bash directory stack across sessions?

Bash will remember command history across sessions, but not the directory stack created with pushd. Is there any way to remember the directory stack as well?


How about using the dirs -p output?
You could save it from your .bash_logout and sort-of re-load it with a minor script in the .bash_login

See more at Directory Stack Builtins bash page.


I finally found a way to determine which shell I'm in consistently across sessions: the environmental variable SHELL_SESSION_ID, which the KDE session manager supports for Konsole (not sure about other desktop environments). With that said, the solution I put together based on user nik's answer:

In .bashrc, in the setup code for interactive shells, I added this:

# Don't remember directory stacks for subshells, just the top level
# shell.
if [[ -z "$BASH_SESSION_ID" ]]; then
    # Get bash-session the X Windows session manager, if possible.
    if [[ -n "$SHELL_SESSION_ID" ]]; then
        export BASH_SESSION_ID=$SHELL_SESSION_ID
    else
        export BASH_SESSION_ID="DEFAULT"
    fi
    .  ~/.bash_dirs
    load_dirs
fi

BASH_SESSION_ID is used rather than directly using SHELL_SESSION_ID so that for environments that don't have SHELL_SESSION_ID, something else can be used.

The contents of .bash_dirs is this:

_DIRS_DIRS=~/.dirs

# Silently make sure ~/.dirs exists
\mkdir -p $_DIRS_DIRS

_DIRS_FILE=$_DIRS_DIRS/$BASH_SESSION_ID

save_dirs() {
    \dirs -l -p > $_DIRS_FILE
}

load_dirs() {
    # Start out with a fresh directory stack.
    \dirs -c

    # Make sure there's at least an empty file.
    if [[ ! -f "$_DIRS_FILE" ]]; then
        touch $_DIRS_FILE
    fi

    # Start out in the directory we left off at
    for dir in $(cat $_DIRS_FILE) ; do
        \cd $dir  > /dev/null 2>&1

        # Just need the first line
        break
    done

    # Restore saved dir stack in reverse order.
    for dir in $(cat $_DIRS_FILE | tac) ; do
        # But don't duplicate the directory we left off at
        if [[ $PWD != $dir ]]; then
            \pushd -n $dir > /dev/null 2>&1
        fi
    done
}

# NOTE: aliases can't take parameters, so we have to alias to functions.

_dirs_pushd()
{
    \pushd "$@"
    save_dirs
}
alias pushd=_dirs_pushd

_dirs_popd()
{
    \popd "$@"
    save_dirs
}
alias popd=_dirs_popd

# In case 'dirs -c' is used.
_dirs_dirs()
{
    \dirs "$@"
    save_dirs
}
alias dirs=_dirs_dirs