There is an app for this. It costs $9 a month, has a menu bar icon, syncs your “workspaces” to the cloud, and once asked for permission to send you notifications. Its core feature is remembering which folder you were in.
Your shell already does that. For free. Here are the parts you forgot you had.
Go back where you just were
cd - jumps to the directory you were in before the last cd. It is a builtin. You do not install it.
cd ~/projects/lifehacker.dev
cd /var/log # off to investigate something
cd - # back to the project, no typing the path again
It prints the directory it’s switching to, which is a nice touch nobody asked the menu bar app to do.
Run cd - twice and you bounce between two directories forever. That covers roughly 80% of why people open the app.
Keep a stack of directories
For more than two places, the shell has a directory stack. pushd goes somewhere new and remembers where you were; popd walks back.
pushd ~/projects/lifehacker.dev # stack: lifehacker.dev ~
pushd /etc/nginx # stack: nginx lifehacker.dev ~
dirs -v # see the whole stack, numbered
dirs -v prints something like:
0 /etc/nginx
1 ~/projects/lifehacker.dev
2 ~
popd removes the top entry and drops you onto the next one:
popd # back to ~/projects/lifehacker.dev
popd # back to ~
You can also jump to a numbered slot with pushd +1. This is a stack of breadcrumbs you can actually eat.
Bookmark the three folders you actually use
The stack is per-session. For the directories you visit every single day, you want names that survive a reboot. Three lines, backed by a plain file. Drop these in your ~/.bashrc or ~/.zshrc:
mark() { echo "$1=$(pwd)" >> ~/.marks; }
jump() { cd "$(grep "^$1=" ~/.marks | tail -1 | cut -d= -f2-)"; }
Reload your shell (source ~/.bashrc), then teach it the places you live:
cd ~/projects/lifehacker.dev
mark work
cd ~/Downloads/where-pdfs-go-to-die
mark dl
Now, from anywhere:
jump work # cd into ~/projects/lifehacker.dev
jump dl # cd into the PDF graveyard
mark appends name=path to ~/.marks. jump greps for the name, takes the last match (so re-marking a name wins), and cds there. The cut -d= -f2- keeps everything after the first =, so paths with = in them survive. It works identically in bash and zsh.
Want to see your bookmarks? It’s just a file:
cat ~/.marks
That is the whole product. The file is the database. The grep is the search engine.
When this goes wrong
The failure mode here is naming. Do not name a function after a builtin or a common command. If you’d called the jump function cd, your shell would happily run your function instead of the real cd everywhere, forever, and you would spend an hour wondering why directory changes got weird. Same trap with aliasing over ls, grep, or cd.
Check before you name anything. type tells you what a name resolves to right now:
type cd
# cd is a shell builtin
type jump
# bash: type: jump: not found (good — the name is free)
If type jump says “not found,” the name is safe to use. If it says “is a function” or “is aliased to,” pick a different name or you’ll shadow something you wanted.
The other small gotcha: mark stores $(pwd), an absolute path. Move the folder later and the mark points at nothing — jump will fail with cd: no such file or directory. Re-mark it. The fix is the same three lines you already have.
The tally
total cost: $0
total lines: 3
total smugness: unlimited