Symlink – Equivalent of Alias for a Symbolic Link

cd-commandsymlink

I find myself needing to jump around a few directories in my home folder often and get tired of writing them. I would like a quicker approach, which would traditionally be a symbolic link.

However, I don't want to clutter up my home directory with dozens of symbolic links. I could create some ~/links/ directory and clutter it with symbolic links, but it still is ugly. Besides, I may want to create symbolic links which change each day (defined in .bashrc) to jump to present days directory.

Is there a way to effectively alias a symbolic link, creating something that will be recognized as a link for quick navigation, but won't actually appear when I do an ls of my home directory, and won't last beyond the current session?

Best Answer

You could use tab completion. By default on many Linux distributions, bash is set up so that when you hit the [TAB] key, you're given a list of possible matches, or if there's just one match, it's all filled out. For cd, this is normally a list of subdirectories of the current working directory. You could overwrite that, but I suggest instead making an alias, like jd for "jump directory":

alias jd=cd

and then, defining the "bookmarks" you want as completions for jd. Look at the bash man page for a lot more options (including auto-generating the results on the fly from a command or function), but the easiest way is just a list of words, with -W:

complete -W "/srv/www ~/tmp ~/work" jd

Now, type jd and hit [TAB], and you'll see your "bookmarks". Type any ambiguous part, and then hit [TAB] to complete. (In the above, the ~s expand to my home directory, so the first [TAB] gives me a /, and if I hit w and [TAB] again, /srv/www is filled out.)

Of course, put this in ~/.bash_profile to make it persist.

Or, we can take this to the next level. Make a directory ~/.shortcuts — starting with a dot, it'll be hidden and not muss up your nice clean home directory — and fill that with symlinks to your desired directories. Then, put this in your ~/.bash_profile:

_list_shortcuts() 
{ 
    COMPREPLY=($( compgen -W "$( ls ~/.shortcuts )" -- ${COMP_WORDS[COMP_CWORD]} ))
}
jd()
{
    cd -P ~/.shortcuts/$1
}
complete -F _list_shortcuts jd

This defines a slightly more complicated completion in the fuction _list_shortcuts to build the list of names, and makes jd be a function rather than a simple alias, since we want it to act differently from just cd. The -P flag to cd makes it resolve the symlinks, so everything becomes transparent magic. Your shortcut names don't even have to match the targets.

So:

$ ls -l ~/.shortcuts/
total 0
lrwxrwxrwx. 1 mattdm mattdm 16 Dec 17 19:44 tmp -> /home/mattdm/tmp
lrwxrwxrwx. 1 mattdm mattdm 17 Dec 17 19:44 WORK -> /home/mattdm/work
lrwxrwxrwx. 1 mattdm mattdm  8 Dec 17 19:44 www -> /srv/www
$ jd tmp
$ pwd
/home/mattdm/tmp
$ jd WORK
/home/mattdm/work

And, for an extra dose of fancy, make jd list all of your shortcuts when executed without any parameters:

jd()
{
    if [[ -z "$1" ]]; then
      (cd ~/.shortcuts; stat -c '%N' *)
    else
      cd -P ~/.shortcuts/$1
    fi
}

Note: I use compgen -W $( cmd ) instead of compgen -C 'cmd' because the latter never works for me and I don't understand why. That might be a new question of my own. :)

Related Question