18

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?

  • 4
    you may want to look into pushd and popd – Rui F Ribeiro Dec 17 '15 at 20:28
  • i find Jeroen Janssen's approach to be adaptable and low-cost for this exact need: jeroenjanssens.com/2013/08/16/… – Theophrastus Dec 18 '15 at 0:53
  • 2
    What shell are you using? – Gilles 'SO- stop being evil' Dec 18 '15 at 1:03
  • @Theophrastus Heh — that's basically what I reimplemented not quite as elegantly in my answer. – mattdm Dec 18 '15 at 1:05
  • 3
    not exactly what you are looking for, but still might come in handy when jumping back and forth between two directoris: cd - will cd into the last directory were previously. Hence, if you do it twice you'll go back to where you started... very nice for the situation "oh i forgot to edit someFile.txt at the previous location" => Simply: cd -, edit someFile.txt cd - – dingalapadum Dec 18 '15 at 13:36
12

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. :)

  • very interesting. One catch though, it still requires typing out the full link, or at least enough of the link to become non-ambiguous, before I can complete with jd. Any way to add aliases to the jd commands to shorten them? or make them relative to a directory where I can store symbolic links I suppose. – dsollen Dec 17 '15 at 22:13
  • @dsollen See update :) – mattdm Dec 18 '15 at 1:03
  • this worked perfectly. In all honesty I didn't expect a good answer to this question, but this is pretty much exactly what I wanted. I anticipate quite a bit of use of this and it feels clean enough to add to the list of things I modify whenever I get a new VM (I even have an automated way to clone my standard environmental changes to a new vm lol). Thanks alot. At some point when I have more free time I'll figure out how the syntax for the COMPREPLY works ;) – dsollen Dec 18 '15 at 15:39
18

Shell aliases have the feature that you can do (some) name-completion on them (usually bound to tab). Alternatively, you can use the CDPATH feature, which "recently" (within the past 5-6 years) has been improved to support name-completion. If that works for you, it has the advantage that the what you type is the actual name of the directory rather than a mnemonic for it.

According to the bash manual

CDPATH
A colon-separated list of directories used as a search path for the cd builtin command.

Further reading:

  • Did not know about the CDPATH environment variable, thank you. I might add my git_repos directory to that variable.... – Wildcard Dec 18 '15 at 18:29
16

For the directories you frequent often, but don't change daily, another option is just to have several alias commands in your .bashrc file:

alias cdo="cd /u01/app/oracle"
alias cdw="cd /var/www/html" 

A friend has about 50 of those; I have a handful; quick and easy. Just

cdo

to change directory to /u01/app/oracle

  • Indeed. I have used this mechanism since the early 1990s. – wallyk Dec 18 '15 at 2:31
7

I recommend pushd and popd.

I personally do find them handy when doing development work / reading source code, when multiple directories are involved.

They effectively implement a stack structure/LIFO, where you PUSH a directory (pushd), and the next POP directory command (popd) retrieves it.

So, when inside a dir, you would do:

pushd .

And when you need to retrieve it, you do

popd

You can perform multiple pushd (s), and do the corresponding popd (s) later on, to return to the directories.

I will leave here a link.

http://www.eriwen.com/bash/pushd-and-popd/

  • 1
    This is the solution I use also, with the exception that I don't use popd much. I fill my dirs list (which is populated by pushd commands) with all the directories I want to visit/work in for that chunk of time, then I run pushd +1. Then, I can cycle through the directories with a simple !pu which is very fast. (Note that on both Ubuntu and CentOS, pushd is the only command available on a clean install that starts with pu.) – Wildcard Dec 18 '15 at 18:25
3

You could just put them as variables in your ~/.bashrc, and then they're only a $ away.

$ cat ~/.bashrc
if [ "$PS1" ]
then
    export myproj=~/todays/fancy/project
fi

$ cd $myproj
3

The obvious answer is variables, those symbolic things in the shell that stand for other things, similarly to symbolic links in the filesystem.

path/to/project $ project=$PWD
path/to/project $ cd $elsewhere   # Previously created
path/to/elsewhere $ cd $project
path/to/project $ logout          # Variables gone, as required

In any decent shell, you get Tab completion on variable names which further helps.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.