When I type cd ~foo
, I'd like bash to take me to some directory foo
as a shortcut for typing the full directory path of foo
. and I'd like to be able to cp ~foo/bar.txt ~/bar.txt
to copy a file from the /foo/
directory to the home directory... So basically, I want something that works exactly like ~/
does, but where I specify what the directory should be. [I'm sure I should jfgi, but I don't know what to fg]
-
zsh has built-in support for this. It's called "named directories"– SildorethApr 17, 2015 at 18:36
-
I was looking for some shell-bookmarking tool for too long, and finally I've ended up with my own (fuzzy-search-based) solution that I like much more that anything else I've seen before. Check this answer: unix.stackexchange.com/a/209892/46011– Dmitry FrankJun 17, 2015 at 17:40
7 Answers
The way I used to do this is to create a directory that contains symlinks to the directories you want shortcuts do, and add that directory to your CDPATH. CDPATH controls where cd
will search when you switch directories, so if that directory of symlinks is in your CDPATH you can cd
to any of the symlinked directories instantly:
mkdir ~/symlinks
ln -s /usr/bin ~/symlinks/b
export CDPATH=~/symlinks
cd b # Switches to /usr/bin
The downside of course is it won't work if there's a directory in your current directory named "b" -- that takes precedence over the CDPATH
I normally dislike answers that say "first you need to switch shells", but this exact feature exists in ZSH, if you're willing to use that instead; it's called named directories. You export a variable foo
, and when you refer to ~foo
it resolves to the value of $foo
. This is especially convenient because it works in commands besides cd
:
echo hi > /tmp/test
export t=/tmp
cat ~t/test # Outputs "hi"
-
2In what ways does this ZSH feature differ from doing: echo hi> /tmp/test;export t=/tmp; cat $t/test At least on my machine, this works just fine. The only difference is the character you have to type.– Steven DSep 1, 2010 at 16:37
-
referring the op to zsh is the right thing to do. i've not missed that feature once in 15 years. seems like the kind of thing some people get really obsessed about while others don't care. that's why there is more than one shell.– user601Sep 1, 2010 at 17:06
-
2@Steven It's pretty similar, but ZSH knows it's a named directory in this case so it can treat it specially in prompt expansions and shell built-in commands Sep 1, 2010 at 18:34
-
1
-
1"The downside of course is it won't work if there's a directory in your current directory named "b" -- that takes precedence over the CDPATH" ... You could use
CDPATH=":~/symlinks"
instead. See unix.stackexchange.com/questions/456866/… Jul 17, 2018 at 21:30
You could write a wrapper function for cd
and call it "cd" (ultimately the function will call builtin cd
- using the builtin
keyword). You could use a prefix character that Bash won't expand on the command line before your function sees it and that's unlikely to appear as the initial character in your directory names, perhaps ":". You would want to make it more robust, but here's a simple outline:
# format: [semicolon] shortcut colon destination [semicolon] ...
export CDDATA='foo:/path/to/foo;bar:/path/to/bar;baz:/path/to/baz'
cd () {
local dest=$1
if [[ $dest == :* ]]
then
[[ $CDDATA =~ (^|;)${dest:1}:([^;]*)(;|$) ]]
dest=${BASH_REMATCH[2]}
fi
if [[ -z $dest ]]
then
cd
else
builtin cd "$dest"
fi
}
cd :bar # pwd is now /path/to/bar
-
1
-
1Thanks for this suggestion - made my really simple solution on top of it: aaverin.github.io/unix/macox/2014/05/26/bash-named-folders– AAverinMay 27, 2015 at 7:01
with bash:
~foo
is reserved for the home directory of the user foo. I would not recommend creating users just for that convenience.
You can make your life easier (or harder) when changing directories by setting the CDPATH
environment variable (look it up in bash(1)
).
Apart from that, the only way to think of would be to set environment variables for those directories you want to abbreviate.
$ FOODIR=/var/lib/misc
$ cp ~/bar.txt $FOODIR
Bash variables can be used to create a bookmarking system. Variables will work with any command and bash will tab complete the variable name. In newer versions of bash, if a / is appended to the variable name, the path the variable contains can be tab completed as well.
mydir=/home/chris/dir
ls $my # Tab completion works on variable name.
ls $mydir/ # Tab completion is equivalent to that with ls /home/chris/dir/
# (doesn't work in older versions of bash).
For persistence, variable declarations can be kept in a file that is sourced from .bashrc. Since this file is a bash script, it can contain declarations that reference other variables, such as aur="${HOME}/AUR"
, or that only run on certain hosts if [[ $HOSTNAME == foo ]]; then bar=baz; fi
, which is useful if you reuse config files across multiple hosts and users.
The following bash function (to be added to .bashrc, or sourced from it) allows bookmarks to be added to and removed from the bookmarks file. It is fairly new and not guaranteed to be free of bugs.
bookmark_file=~/.bookmarks
source "$bookmark_file"
bm() {
usage='Usage:
bm add <name> <path> Create a bookmark for path.
bm add <name> Create a bookmark for the current directory.
bm update Source the bookmark file.
bm remove <name> Remove a bookmark'
case $1 in
add)
local path
if [[ $# -eq 2 ]]; then
path=.
elif [[ $# -eq 3 ]]; then
if [[ -e $3 ]]; then
path="$3"
else
echo "bm: ${3}: No such file or directory."
return 1
fi
else
echo "$usage"
return 1
fi
if declare | grep "^${2}=" > /dev/null; then
echo "bm: The name $2 is in use."
return 1
fi
path=$(readlink -f "$path")
echo ${2}=\""$path"\" >> "$bookmark_file"
eval ${2}=\""$path"\"
return 0
;;
update)
if [[ $# -eq 1 ]]; then
source "$bookmark_file"
return 0
fi
;;
remove)
if [[ $# -eq 2 ]]; then
unset $2
local contents=$(grep -v "^${2}=" "$bookmark_file")
echo "$contents" > "${bookmark_file}.tmp"
rm -f "$bookmark_file"
mv "${bookmark_file}.tmp" "$bookmark_file"
return 0
fi
;;
esac
echo "$usage"
return 1
}
An way would be creating an alias for cd which replaces ~c
to the wanted path. Or just use zsh ;)
-
2Yes, I thought about doing that, like alias ~c="cd /daten/cvs/plugin_root" but that only helps with cd, while named directories can be used with every command.– fschmittSep 22, 2010 at 11:01
For changing directories, you could use wcd: Wherever Change Directory
With that, it'll be like wcd plugin_root
.
I have the below function which will create alias on the fly,
s () {
if [[ "x$1" != "x" ]]
then
alias $1="cd $PWD;pwd"
echo "alias $1=\"cd $PWD;pwd\""
else
echo "Usage: s[s] <directory bookmark name>"
return 1
fi
}
When I want to bookmark a directory, I just type s dirName
. This creates a alias like alias dirName="cd /my/current/directory/;pwd"
. so I can come back to this directory by just typing dirName
. I have a version which saves it into bash_aliases as well. This works in any shell.