I had to modify Jeroen's code to get the `marks` shortcut working under Mac OS 10.8:<p><pre><code> export MARKPATH=$HOME/.marks
function jump {
cd -P $MARKPATH/$1 2> /dev/null || echo "No such mark: $1"
}
function mark {
mkdir -p $MARKPATH; ln -s $(pwd) $MARKPATH/$1
}
function unmark {
rm -i $MARKPATH/$1
}
function marks {
ls -l $MARKPATH | sed 's/ / /g' | cut -d' ' -f9- && echo
}</code></pre>
I set my version up with a -f on the unmark rm so that I don't need to be prompted to remove it. Also added some basic completion for both jump and unmark<p><pre><code> export MARKPATH=$HOME/.marks
function jump {
cd -P $MARKPATH/$1 2>/dev/null || echo "No such mark: $1"
}
function mark {
mkdir -p $MARKPATH; ln -s $(pwd) $MARKPATH/$1
}
function unmark {
rm -if $MARKPATH/$1
}
function marks {
ls -l $MARKPATH | sed 's/ / /g' | cut -d' ' -f9- | sed 's/ -/\t-/g' && echo
}
_completemarks() {
local curw=${COMP_WORDS[COMP_CWORD]}
local wordlist=$(find $MARKPATH -type l -printf "%f\n")
COMPREPLY=($(compgen -W '${wordlist[@]}' -- "$curw"))
return 0
}
complete -F _completemarks jump unmark</code></pre>
To have completion with bash you can use this:<p><pre><code> function _jump {
local cur=${COMP_WORDS[COMP_CWORD]}
local marks=$(find $MARKPATH -type l -printf "%f\n")
COMPREPLY=($(compgen -W '${marks[@]}' -- "$cur"))
return 0
}
complete -o default -o nospace -F _jump jump
</code></pre>
Bash completion really needs better docs :-|
Reminds me of z, which I use all the time. Anyone else use z? If you have not heard of it, get it now <a href="https://github.com/rupa/z" rel="nofollow">https://github.com/rupa/z</a>.<p>z is a wonderful complement to cd. After cd into a folders with z set up, a file stores all folders navigated to sorted by frecency, then simply jump to a folder with z [foldernameregex].
For Windows users I have a closely related shameless plug:<p><i>cdhere</i> navigates your cmd.exe to wherever the current topmost Explorer window is pointed at.<p>It's not the same as the OP's trick, of course, but since you're voluntarily using Windows, I'm going to assume you "live" on the command line less than the average UNIX user, and more on GUI tools such as good old Explorer.<p><a href="https://github.com/eteeselink/cdhere" rel="nofollow">https://github.com/eteeselink/cdhere</a>
You can also use ranger [1] to change directories, especially if you want to explore the directory tree quickly when you don't know exactly where to jump to. Install it and add the following to ~/.bashrc:<p><pre><code> function ranger-cd {
tempfile='/tmp/chosendir'
/usr/bin/ranger --choosedir="$tempfile" "${@:-$(pwd)}"
test -f "$tempfile" &&
if [ "$(cat -- "$tempfile")" != "$(echo -n `pwd`)" ]; then
cd -- "$(cat "$tempfile")"
fi
rm -f -- "$tempfile"
}
# This binds Ctrl-O to ranger-cd:
bind '"\C-o":"ranger-cd\C-m"'
</code></pre>
(This script comes from the man page for ranger(1).)<p>Edit: Modified the above script for use with zsh (and multiple users):<p><pre><code> ranger-cd() {
tempfile=$(mktemp)
ranger --choosedir="$tempfile" "${@:-$(pwd)}" < $TTY
test -f "$tempfile" &&
if [ "$(cat -- "$tempfile")" != "$(echo -n `pwd`)" ]; then
cd -- "$(cat "$tempfile")"
fi
rm -f -- "$tempfile"
}
# This binds Ctrl-O to ranger-cd:
zle -N ranger-cd
bindkey '^o' ranger-cd
</code></pre>
[1] <a href="http://ranger.nongnu.org/" rel="nofollow">http://ranger.nongnu.org/</a>.
I found this is a useful addition to his scripts... I can't live without my tab completion!<p><pre><code> _jump()
{
local cur=${COMP_WORDS[COMP_CWORD]}
COMPREPLY=( $(compgen -W "$( ls $MARKPATH )" -- $cur) )
}
complete -F _jump jump</code></pre>
I've been using Bashmarks (<a href="https://github.com/huyng/bashmarks" rel="nofollow">https://github.com/huyng/bashmarks</a>) for years, which appears to be basically the same thing but with a less verbose interface.
Here is a fully functional (albeit minimal) Windows version: <a href="http://appleseedhq.net/stuff/marks-v1.zip" rel="nofollow">http://appleseedhq.net/stuff/marks-v1.zip</a>. Tested on Windows 7 (does not require PowerShell).<p>GitHub: <a href="https://github.com/dictoon/marks" rel="nofollow">https://github.com/dictoon/marks</a><p>Edit: to install, unzip anywhere and add to your path. Then:<p><pre><code> C:\Windows> mark win
C:\Windows> marks
win => C:\Windows
C:\Windows> cd ..
C:\> jump win
C:\Windows>
</code></pre>
Marks will be stored in a marks\ subdirectory (relatively to the mark.bat file).
Clever!<p>With fish 2.0, the shell stores a list of "cd" commands issued from a specific directory, so mostly just typing "cd" yields an auto-completion hint out of the box.
cool!
I'm a command-line junkie as well.
So, I've been doing something similar for quite a while.<p>Here's what I have done :<p><pre><code> function ccb ()
{
FOO=`pwd`;
echo >> ~/shortcuts.sh;
echo alias $1=\'pushd $FOO\' >> ~/shortcuts.sh;
echo >> ~/shortcuts.sh;
. ~/shortcuts.sh
}
</code></pre>
simple but quite effective.<p>Now, all I have to do is type ccb and give a shortcut name to register a shortcut. Then whenever i want to jump to that directory, I just have to type the shortcut.<p>Eg :<p><pre><code> foo@bar deeply-nested-dir# ccb deepd
foo@bar deeply-nested-dir# cd
foo@bar ~# deepd
foo@bar deeply-nested-dir#
</code></pre>
My method lacks the a) delete shortcut and b) list shortcut features that the above solution gives, though.
This is really neat. I have added it to alias.sh for easy inclusion: <a href="http://alias.sh/filesystem-markers-jump" rel="nofollow">http://alias.sh/filesystem-markers-jump</a>
Here's a `fish 2` shell version, that works on the Mac.
You can add it as `~/.config/fish/functions/mark.fish`:<p><pre><code> set MARKPATH $HOME/.marks
function jump
cd $MARKPATH/$argv; or echo "No such mark: $argv"
end
function mark
mkdir -p $MARKPATH; and ln -s (pwd) $MARKPATH/$argv
end
function unmark
rm -i $MARKPATH/$argv
end
function marks
ls -l $MARKPATH | cut -d' ' -f12-; and echo
end</code></pre>
Cool, simple but very useful!<p>Bonus: if you want autocompletion for the jump and unmark commands, just add the following lines (in zsh):<p><pre><code> function _marks {
reply=($(ls $MARKPATH))
}
compctl -K _marks jump
compctl -K _marks unmark</code></pre>
I don't understand the advantage of using handwritten function instead of the
shell builtins.
The `mark` function could be replaced by `alias -g`, `jump` could be replaced
by `cd` and `unmark` could be replaced by `unalias` :<p><pre><code> % cd ~/Dev/W3/m-r-r.github.io
% alias -g :blog="$PWD"
% jekyll build -d /tmp/out/ && cd /tmp/out
% ./index.html
% cd :blog
% pwd
/home/m-r-r/Dev/W3/m-r-r.github.io
% alias -g
:blog='/home/m-r-r/Dev/W3/m-r-r.github.io'
:dev='/home/m-r-r/Dev'
:c='/home/m-r-r/Dev/C'
:python='/home/m-r-r/Dev/Python'
:vim='/home/m-r-r/.vim'
</code></pre>
In addition, this method works with any shell command:<p><pre><code> % pwd
/tmp/out
% make -C :blog publish
% git clone git://git.complang.org/ragel.git `echo :c`/ragel
% vim `echo :vim`/templates/\*.rl
</code></pre>
On the other side, the aliases are not saved at exit unless you write a function
to do it:<p><pre><code> % tail -n 15 ~/.zshrc
function aliases {
(
alias -L -r
alias -L -g
alias -L -s
) | uniq
}
function save-aliases {
aliases > ~/.zsh_aliases
}
if [ -f ~/.zsh_aliases ]; then
. ~/.zsh_aliases
fi</code></pre>
I also do something similar but slightly different: <a href="https://github.com/roobert/dotfiles/blob/master/.zsh/robs/functions/bookmarks.zsh" rel="nofollow">https://github.com/roobert/dotfiles/blob/master/.zsh/robs/fu...</a><p>my method involves storing the bookmarks in a file but loading them into zshs directory hash. This means the directories are tab completable and if you have AUTO_CD set then you can change directory with simply: ~dir_name, otherwise: cd ~dir_name.
I've been using the following in some form for over 3 decades!
(now in zsh)<p><pre><code> alias .=cd
</code></pre>
In /bin/sh "." sources a script. While this can be common in a script, one rarely does this interactively so I usurped . for the most common operation!<p><pre><code> alias ,=pushd
alias ,,=popd
alias ,.=dirs
</code></pre>
Think of cd as a goto, pushd as a call, popd as a return and dirs as a stack trace!<p><pre><code> ..() { cd ../$* }
cdpath=(. .. ~/src ~)
</code></pre>
Use of cdpath can be confusing so it is best to show part of $PWD in the prompt:<p><pre><code> PS1="%* %5. %h%(#.#.:) "
</code></pre>
This ends the prompt with a # if you are running as superuser.<p>These aliases/functions are enabled in .zshrc (<i>only</i> if run interactively -- that is, they are included below the following test):<p><pre><code> if [[ ! -o interactive ]] ; then return; fi
</code></pre>
The "benefit" of Jeroen's mark/unmark is that these paths persist (and can be used from any window running a shell. I have not found much need for that + I can have different $dirs in different windows. Also, given that my shell windows (under screen) persist for a very long time, I don't need symlink's persistence!<p>Alternatively I define "." to be a function that does arg specific operation (cd if a dir, acroread if .pdf, vi if text etc.).
This is great, but I don't see why this is better than autojump.<p>* Autojump automatically saves marks,<p>~~~
cd Downloads # And you are done.
~~~<p>* You don't have to think about mark names,<p>~~~
cd Projects/Python # It will be called `python`.
~~~<p>* You don't need to remember mark names,<p>~~~
j haskell # If you want `Projects/Haskell`, odds are the mark is auto-named `haskell`.
~~~<p>* You can specify only some part of mark name;<p>~~~
j bar # And you are in `Stuff/foobar`.
~~~<p>Other than that, this is, as I said before, great! Looking forward to go through the source code to learn more about Bash.
I noticed that 'mark' doesn't work if you have spaces in a directory name which you can't avoid on the Mac (I tried to mark an interior folder inside the iPhone Simulator which is inside "~/Library/Application Support/iPhone Simulator/". Wrapping in quotes seems to do the trick:<p><pre><code> function mark {
mkdir -p $MARKPATH; ln -s "$(pwd)" $MARKPATH/$1
}</code></pre>
Cool!, I usually want to open a new terminal window and move to the same directory I am working in, I use these handy aliases :<p>alias here='pwd | pbcopy'<p>alias there='cd $(pbpaste)'<p>So now type `here` in current terminal window and type `there` in new terminal window to move to same directory!<p>[This works on Mac on other OS you could use xcopy or equivalent clipboard copy program]
This is a very informative thread for people trying to streamline their daily shell experience. I'm looking forward to experimenting with the utilities mentioned here. I spend a significant amount of time in, and moving between CVS sandboxes. All my sandboxes have the same internal directory structure, but the root of the path changes. To speed up navigation time I created a tool to replace directory names with aliases. The aliases are persistent. They can also be "stacked", which allows you to specify a sandbox as an alias, then reuse your existing aliases to navigate within the sandbox. Auto-completion in the shell is an excellent companion as well. More information on "stacked.aliases", as well as the source can be found here: <a href="https://github.com/ttomaino/stacked_aliases/wiki" rel="nofollow">https://github.com/ttomaino/stacked_aliases/wiki</a>. I include one example to illustrate:<p>As an example, the following two sandboxes contain the Broadcom Ethernet driver:<p>/build/username/sandbox_a/software/vendors/linux/linux-2.6.35.7/drivers/ethernet/broadcom
/build/username/sandbox_b/software/vendors/linux/linux-2.6.35.7/drivers/ethernet/broadcom<p>Use the add alias command aa <alias name> <directory> to create aliases for the sandboxes:<p>aa a /build/username/sandbox_a
aa b /build/username/sandbox_b<p>Then create an alias for the Broadcom directory:<p>aa brcm software/vendors/linux/linux-2.6.35.7/drivers/ethernet/broadcom<p>To change to the Broadcom directory in sandbox_a, just stack the appropriate aliases using the ua command. Stacking is done by stringing the aliases together with a period delimiter:<p>ua a.brcm<p>To change to the Broadcom directory in sandbox_b:<p>ua b.brcm
Great idea!<p>I don’t want symlinks to be resolved (/var/www becomes /private/var/www on os x) so I modified it to store the path in the file:<p><pre><code> export MARKPATH=$HOME/.marks
function jump {
mark=$(head -n 1 "$MARKPATH/$1" 2>/dev/null)
if [[ $mark != '' ]]; then
cd $mark
else
echo "No such mark: $1"
fi
}
function mark {
mkdir -p "$MARKPATH"; echo "$(pwd)" > "$MARKPATH/$1"
}
function unmark {
rm -i "$MARKPATH/$1"
}
function marks {
find "$MARKPATH" -type f | while read filename
do
printf "%-12s -> %s\n" $(basename ${filename}) $(head -n 1 ${filename})
done
}
</code></pre>
I think the if syntax is zsh so probably won’t work with bash.
I just do this (in zsh):<p><pre><code> setopt autopushd pushdminus pushdsilent pushdtohome pushdignoredups
</code></pre>
Which automatically pushes (unique) directories I've visted into $dirstack.<p>Then I have an alias:<p><pre><code> d () {
local dir
select dir in $dirstack
echo $dir
break
done
test "x$dir" != x && cd $dir
}
</code></pre>
That gives me a list of directories to jump to in my history:<p><pre><code> ~/src/git/emacs-prelude $ d
1) /home/kelvie/tmp/typhoon 3) /home/kelvie/src/git
2) /home/kelvie/tmp 4) /home/kelvie
?#
</code></pre>
So I just type 1-4 to go back to a directory I've previously been in.
I'm too lazy to type "jump" so I've modified it to automatically add a Bash alias for each one as well.<p><a href="https://github.com/davejamesmiller/dotfiles/blob/master/.bash/mark.bash" rel="nofollow">https://github.com/davejamesmiller/dotfiles/blob/master/.bas...</a>
I have no idea if anyone else does this, but I use tmux a lot for different projects. I usually have vim in one tab, logs in another, and tests in another. However, each tab I open I need to cd into the same directory. As such I came up with this helper for zsh. Every time I change a directory it records it. When I start a new session (new tmux or iTerm tab) it goes straight to that directory:<p><pre><code> # record directory in ~/.lastpwd
record_pwd() {
pwd > ~/.lastpwd
}
chpwd_functions=(record_pwd)
# go to last directory when opening a new shell
if [[ -d `cat ~/.lastpwd` ]]; then
cd `cat ~/.lastpwd`
fi
</code></pre>
For other shells that don't have something like chpwd_functions you could just alias cd.
I've been doing a very similar thing for a few years: <a href="https://chris-lamb.co.uk/posts/optimising-directory-navigation-multiple-terminals" rel="nofollow">https://chris-lamb.co.uk/posts/optimising-directory-navigati...</a>
Interesting idea. I've the bash built-in "pushd" and "popd" for a long time for similar reasons, but those effectively limit you to treating the history as a stack rather than an arbitrary list.
This reminds me of NCD (Norton Change Directory) which then went on to inspire many tools, like the excellent KCD and WCD. These tools index rather than create symlinks, though.
"Like many others, I spend most of my day behind a computer."<p>I tend to spend my time in front of one. Is there an advantage to being behind it?<p>But jokes aside, I added this to my bashrc, looks useful.
I use CDargs <a href="http://www.skamphausen.de/cgi-bin/ska/CDargs" rel="nofollow">http://www.skamphausen.de/cgi-bin/ska/CDargs</a>
This is how I know I am old I create a symlinks in my home directory to oft used locations and get there with
cd ~/linkname
Has the added bonus of making my short path be ~/linkname rather than ~/some/very/deep/pocket/in/some/git/repo
Nice idea, reminds me of ncd from a far away, foggy past. I suggest some escaping on the directory name parameter though. If you're not careful, you're going to run into trouble with paths that have spaces or risk some nasty security issues with embedded special characters.
That looks clever and useful, I wasn't expecting that. I do maintain a few aliases to jump around, but this looks more efficient. Not sure though if I'll like "jump foo" better than simply "foo" that I use now, but maintaining those aliases is a pita.
I've add a new bash version based on Jeroen's code, it's more easier to use in a Bash environment.<p>Welcome to use, thanks for Jeroen's smart work.<p><a href="https://github.com/dangoakachan/mark-directory" rel="nofollow">https://github.com/dangoakachan/mark-directory</a>
I have a similar tool but it also manages shell environment variables, allowing you to jump around and/or switch working projects. You can check it out at: <a href="http://github.com/timtadh/swork" rel="nofollow">http://github.com/timtadh/swork</a>
I used some of this code to implement a more orthodox utility using flags instead of different syntax for different commands.<p><a href="https://github.com/parski/Wormhole" rel="nofollow">https://github.com/parski/Wormhole</a><p>It works great! Great blog post.
My Z-Shell predicts and auto-completes everything I do often perfectly, thus typing 2-3chars not only get's me deep into directories, but also do actions I need. But maybe the idea of folder bookmarks can still be useful, idk.
I've updated the completion code to work on ubuntu and os x:<p><a href="http://neil.grogan.ie/2013/08/quickly-navigate.html" rel="nofollow">http://neil.grogan.ie/2013/08/quickly-navigate.html</a>
<a href="http://code.google.com/p/go-tool/wiki/GettingStarted" rel="nofollow">http://code.google.com/p/go-tool/wiki/GettingStarted</a> Works on all OSes.
Here is one that works with zsh: <a href="https://github.com/bufordtaylor/swiftcommandline" rel="nofollow">https://github.com/bufordtaylor/swiftcommandline</a>
This does look very similar to the setup I am using (<a href="https://github.com/huyng/bashmarks" rel="nofollow">https://github.com/huyng/bashmarks</a>)