Submit Hint Search The Forums LinksStatsPollsHeadlinesRSS
14,000 hints and counting!

Create a persistent directory stack in zsh UNIX
The directory stack keeps track of the various directories you've visited in a given shell session. Here is a way to make the stack persistent using zsh. The aim is to make it easier to switch between frequently visited directories. The basic idea for this was taken from a 1991 Usenet posting by Uri Guttman. Other bits come from Paul Falstad's Z Shell Guide.

First, make a new file with the following contents:
#!/usr/bin/env ruby

dirs = [] 
ARGF.each { |line| dirs.push(line) }

dirs.reverse.each { |line|
  puts "pushd #{line.chomp.gsub(/s/, ' ')}"
}
Name the file savedirs.rb, save it somewhere in your path, and make it executable with chmod +x savedirs.rb.

Next, add these lines to your ~/.zlogout file (create it if necessary):
# Save directory stack
dirs -p | savedirs.rb > ~/.dirstack
Finally, add these lines to your ~/.zshrc file:
DIRSTACKSIZE=8
setopt autopushd pushdminus pushdsilent pushdtohome
alias dh='dirs -v'

# Restore directory stack
source ~/.dirstack
You can use dh (directory history) to show the stack:
% dh
0       /var
1       /etc
2       /Applications
3       ~/Development/Scripts
Use cd -3 to change to ~/Development/Scripts, for example. The directory stack will now be saved across shell sessions, with the added bonus that your shell will now open in the directory you were in last.
    •    
  • Currently 3.67 / 5
  • 1
  • 2
  • 3
  • 4
  • 5
  (3 votes cast)
 
[8,273 views]  

Create a persistent directory stack in zsh | 16 comments | Create New Account
Click here to return to the 'Create a persistent directory stack in zsh' hint
The following comments are owned by whoever posted them. This site is not responsible for what they say.
Create a persistent directory stack in zsh
Authored by: wgscott on Aug 12, '05 10:41:44AM
Wataru Kagawa and I have been working on a GUI/command-line zsh directory stack access utility sort of along these lines. If you or anyone is interested, you can get it here:

[ Reply to This | # ]
Create a persistent directory stack in zsh
Authored by: jholland on Aug 12, '05 12:46:54PM

Thanks! I will check out all of your zsh stuff, in fact.



[ Reply to This | # ]
Create a persistent directory stack in zsh
Authored by: rv8 on Aug 12, '05 04:34:23PM

This looks wonderful, except I can't get it to work.

I've got the fink zsh_4.2.5-20 and zsh-templates_0.9.2-1 packages installed on OS X 10.4.2. If I type "gdirs" in a terminal, I get:

% gdirs
Error: Pashua could not be found

Is there some setup work I need to do, or should It Just Work TM?

Note: "dirstack" works - thank you very much. I only learned of this today, and can already see how useful it will be. Your zsh-templates are like an onion to me, and I have only peeled off a few layers yet.

---
Kevin Horton

[ Reply to This | # ]

Create a persistent directory stack in zsh
Authored by: wgscott on Aug 12, '05 05:18:13PM

Sorry, Kevin.

For now, put the following line in the bottom of

~/.zshenv (not ~/.zshrc):

export GUIDIRS_PASHUA='no'

Now it will work as pictured on the web page.

Wataru and I were experimenting with a Pashua-based GUI rather than Applescript and evidently something is not right.

It is looking for

/Library/init/zsh/local-functions/etc/Pashua.app/Contents/MacOS/Pashua

but since you installed it with fink, it is in

/sw/share/zsh/templates/Library/init/zsh/local-functions/etc/Pashua.app/Contents/MacOS/Pashua

Thanks!

You caught a bug that I need to fix...



[ Reply to This | # ]
Fixed - thanks.
Authored by: rv8 on Aug 12, '05 05:23:50PM

That fixed it. Thanks.

---
Kevin Horton



[ Reply to This | # ]
Fixed - thanks.
Authored by: wgscott on Aug 12, '05 08:00:17PM

I've now fixed it for real in the next edition. Thanks, and sorry!



[ Reply to This | # ]
Small enhancement
Authored by: jholland on Aug 12, '05 02:54:04PM
If you change:

alias dh='dirs -v'

to:

alias dh='dirs -v ; echo -n "\nGo to: " ; read n ; cd -$n'

you will be prompted to choose from the list (by number). Also, you can set DIRSTACKSIZE to a larger number if you want it to remember more directories.

[ Reply to This | # ]
Create a persistent directory stack in zsh
Authored by: bjast on Aug 13, '05 01:01:24AM

This zsh script is cool. I've been trying to write something like this in bash.

Can it be done? Or does zsh offer exclusive 'tools' to make this possible.

In playing around with zsh I've notice it is immensely flexible. But I do most of my work in bash.

Thanks again!

bjast



[ Reply to This | # ]
Create a persistent directory stack in zsh
Authored by: fxn on Aug 13, '05 05:11:12PM
I have this zsh function defined in ~/.zshrc
function go {
    case "$1" in
    "sim"  ) cd $HOME/isoco/prj/simweb/simma;;
    "hops" ) cd $HOME/isoco/prj/hops;;
    "cvs"  ) cd $HOME/isoco/prj/hops/cvs/isoco;;
    "web"  ) cd $HOME/hashref;;
    "src"  ) cd $HOME/src;;
    "tmp"  ) cd $HOME/tmp;;
    "ms"   ) cd $HOME/prj/metashop;;
    "halk" ) cd $HOME/prj/halk;;
    "lds"  ) cd $HOME/courses/lds-2004;;
    "ppx"  ) cd $HOME/courses/ppx-2004;;
    "wxp"  ) cd /Library/Python/2.3/sm/wxp;;
    *      ) echo Unknown alias $1;;
    esac
}
This provides aliases so that
    $ go halk
cds into the directory associated to "halk" no matter where you are.

[ Reply to This | # ]
Create a persistent directory stack in zsh
Authored by: wgscott on Aug 13, '05 08:27:21PM

You can do this with cd with the CDABLE_VARS option.



[ Reply to This | # ]
Create a persistent directory stack in zsh
Authored by: wgscott on Aug 13, '05 09:20:36PM

I re-read what you have, and I think what you want is to add /Users/$USER to your CDPATH



[ Reply to This | # ]
Create a persistent directory stack in zsh
Authored by: eater on Oct 02, '05 02:37:51PM
What is the purpose of the gsub(/s/, ' ')? To replace instances of 's' with spaces? I had to remove that to make the script work on my system.

[ Reply to This | # ]
Create a persistent directory stack in zsh
Authored by: ra5ul on May 30, '07 12:09:28PM

gsub(/\s/, '\ ')

(escape spaces). the '\'s probably got stripped out.



[ Reply to This | # ]
Create a persistent directory stack in zsh
Authored by: ra5ul on May 28, '07 12:11:57AM

nice ideas. i've come up with another working solution:

in ~/dirstack:
dirstack()

in ~/.zlogout:
cd
tempstack=()
for ((i=1; i<=$#dirstack; i++)); do tempstack[i]=\"$dirstack[i]\"; done
source $ZDOTDIR/dirstack
for ((i=1; i<=$#tempstack; i++)); do dirstack[i]=$tempstack[i]; done
echo "dirstack=($dirstack)" >| $ZDOTDIR/dirstack

in ~/.zshrc:
source $ZDOTDIR/dirstack
setopt autopushd pushdsilent pushdignoredups

this solves the three problems of:
a. repeated ~ entries in the stack
b. directories with spaces in them
c. erasing the stack on a quick login - logout



[ Reply to This | # ]
Create a persistent directory stack in zsh
Authored by: ra5ul on Jun 04, '07 04:36:37PM
it's probably better to put the source $ZDOTDIR/dirstack line in ~/.zprofile. that way you can still source ~/.zshrc during your session.

[ Reply to This | # ]
Merged saved stack
Authored by: jdsmith on Dec 07, '11 01:20:34PM
I came up with a solution that merges together the directory stacks of parallel sessions, writing the merged list on logout. If you regularly have multiple terminals open on the same machine, this ensures that all the directory history you accumulate is saved (and sensibly interleaved). Since there is no date-stamp for a proper history, I put at the end of the list any common "tail" less-recently visited directories.

Place this in ~/.zprofile (to load the saved dirstack):


# Load the saved Zdirs Stack
if [ -f ~/.zdirs -a ${#dirstack} -eq 0 ]; then
    dirstack=( ${(f)"$(< ~/.zdirs)"} )
    popd > /dev/null
fi
And put this in ~/.zlogout (to merge and save the stack on logout):

set -A tdirs ${(f)"$(dirs -pl)"} # Current directory stack
if [ -e ~/.zdirs ]; then
    set -A zdirs ${(f)"$(<~/.zdirs)"} # Saved stack
    # Find matching list tails
    for i in {1..$#zdirs}; do
	[ \! -z ${(M)${(F)tdirs}%${(F)zdirs[$i,-1]}} ] && {
	    (( tail_length=$#zdirs-$i+1 )); # This length tail matches
	    break; 
	}
    done 
    # Trim the matched tail off tdirs
    set -A tdirs $tdirs[1,-(( $tail_length+1 ))] $zdirs
fi

print -l ${(u)tdirs} >! ~/.zdirs   


[ Reply to This | # ]