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?

Peter Mortensen
  • 1,029
  • 1
  • 8
  • 10
dsollen
  • 804
  • 1
  • 12
  • 25
  • 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: http://jeroenjanssens.com/2013/08/16/quickly-navigate-your-filesystem-from-the-command-line.html – Theophrastus Dec 18 '15 at 00:53
  • 2
    What shell are you using? – Gilles 'SO- stop being evil' Dec 18 '15 at 01:03
  • @Theophrastus Heh — that's basically what I reimplemented not quite as elegantly in my answer. – mattdm Dec 18 '15 at 01:05
  • related: http://superuser.com/questions/874574/how-do-you-cd-to-the-directory-of-another-screen-window. If you use `screen`, that's a way to get other shells `cd`ed to the location of one where you typed out the full path. I've had it in my .bashrc since writing that post, and use it fairly often. – Peter Cordes Dec 18 '15 at 11:34
  • 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
  • @dingalapadum a good comment, and I will likely use that. I'm always looking to increase my knowledge of linux shortcuts (the real problem is retaining them, I swear I keep forgeting VI shortcuts between uses lol) – dsollen Dec 18 '15 at 15:52
  • As a completely different suggestion, and assuming you are using a GUI, perhaps several different windows? I have 5-10 different directories I need to work in, and have a shell window for each, with each window on its own virtual desktop. When switching to another work task, and its directory, I switch desktops. – Thomas Padron-McCarthy Dec 19 '15 at 06:47

6 Answers6

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:

Thomas Dickey
  • 75,040
  • 9
  • 171
  • 268
  • 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
17

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

Mark Stewart
  • 796
  • 1
  • 7
  • 20
14

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

mattdm
  • 39,535
  • 18
  • 99
  • 133
  • 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 01: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
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/

Rui F Ribeiro
  • 55,929
  • 26
  • 146
  • 227
  • 2
    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
Ewan Mellor
  • 128
  • 4
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.

Peter Mortensen
  • 1,029
  • 1
  • 8
  • 10
Kaz
  • 7,676
  • 1
  • 25
  • 46