Quick directory navigation in the bash shell

66,935

Solution 1

If you're just switching between two directories, you can use cd - to go back and forth.

Solution 2

There is a shell variable CDPATH in bash and ksh and cdpath in zsh:

CDPATH    The search path for the cd command. This is a colon-separated
          list of directories in which the shell looks for destination
          directories specified by the cd command.

So you can set in your ~/.bashrc:

export CDPATH=/Project/Warnest:~/Dropbox/Projects/ds

Then cd docs and cd test will take you to the first found such directory. (I mean, even if a directory with the same name will exist in the current directory, CDPATH will still be consulted. If CDPATH will contain more directories having subdirectories with the given name, the first one will be used.)

Solution 3

Something else you might try is a tool called autojump. It keeps a database of calls to it's alias (j by default) and attempts to make intelligent decisions about where you want to go. For example if you frequently type:

j ~/Pictures

You can use the following to get there in a pinch:

j Pic

It is available of Debian and Ubuntu, and included on a per-user basis in ~/.bashrc or ~/.zshrc by default.

Solution 4

If it's a small number of directories, you can use pushd to rotate between them:

# starting point
$ pwd
/Project/Warnest/docs
# add second dir and change to it
$ pushd ~/Dropbox/Projects/ds/test
~/Dropbox/Projects/ds/test /Project/Warnest/docs
# prove we're in the right place
$ pwd
~/Dropbox/Projects/ds/test
# swap directories
$ pushd
/Project/Warnest/docs ~/Dropbox/Projects/ds/test

unlike cd -, you can use this with more than two directories


Following up on Noach's suggestion, I'm now using this:

function pd()
{
    if [[ $# -ge 1 ]];
    then
        choice="$1"
    else
        dirs -v
        echo -n "? "
        read choice
    fi
    if [[ -n $choice ]];
    then
        declare -i cnum="$choice"
        if [[ $cnum != $choice ]];
        then #choice is not numeric
            choice=$(dirs -v | grep $choice | tail -1 | awk '{print $1}')
            cnum="$choice"
            if [[ -z $choice || $cnum != $choice ]];
            then
                echo "$choice not found"
                return
            fi
        fi
        choice="+$choice"
    fi
    pushd $choice
}

example usage:

# same as pushd +1
$ pd 1

# show a prompt, choose by number
$ pd
 0 ~/Dropbox/Projects/ds/test
 1 /Project/Warnest/docs
 2 /tmp
? 2
/tmp ~/Dropbox/Projects/ds/test /Project/Warnest/docs

# or choose by substring match
$ pd
 0 /tmp
 1 ~/Dropbox/Projects/ds/test
 2 /Project/Warnest/docs
? doc
/Project/Warnest/docs /tmp ~/Dropbox/Projects/ds/test

# substring without prompt
$ pd test
~/Dropbox/Projects/ds/test /Project/Warnest/docs /tmp

etc. Obviously this is just for rotating through the stack and doesn't handle adding new paths - maybe I should rename it.

Solution 5

I use alias in bashrc to do those cds.
such as:

alias wdoc='cd ~/Project/Warnest/docs'
alias dstest='cd ~/Dropbox/Projects/ds/test'
Share:
66,935

Related videos on Youtube

saiy2k
Author by

saiy2k

Visit Grassroots

Updated on September 18, 2022

Comments

  • saiy2k
    saiy2k over 1 year

    I would like to frequently switch between directories that are in totally unrelated paths, for example /Project/Warnest/docs/ and ~/Dropbox/Projects/ds/test/.

    But I don't want to type cd /[full-path]/ all the time. Are there any shortcut commands to switch to previously worked directories?

    One solution I could think of is to add environment variables to my bash .profile for the frequently used directories and cd to them using those variables.

    But is there any other solution to this?

  • saiy2k
    saiy2k over 12 years
    is bashrc a file like .profile? in which I need to add those lines?
  • Felix Yan
    Felix Yan over 12 years
    ~/.bashrc or /etc/bash.bashrc. I did not use .profile before, so don't know the relationship between them :-(
  • saiy2k
    saiy2k over 12 years
    that ccd() function need to typed in the terminal prompt or somewhere else? can u pls explain?
  • Admin
    Admin over 12 years
    scripts bashrc will start everytime you open terminal. profile with startup.
  • saiy2k
    saiy2k over 12 years
    added those lines to my .bash_profile and it works great.. thx :)
  • Ulrich Schwarz
    Ulrich Schwarz over 12 years
    @saiy2k: sorry, yes. The function line goes into your .bashrc (you can type it in your terminal to test, but it'll be gone when you close that window), the lines before set up the test case of "testdir" becoming a name for /tmp, and the last line is the test to see if it works.
  • Izkata
    Izkata over 12 years
    Ooh, I knew about pushd and popd for traversal, but not that pushd could rotate what's been used so far...
  • jw013
    jw013 over 12 years
    It should be mentioned that in general, you'll want the first entry in $CDPATH to be . (an explicitly entry, i.e. : also works). Otherwise you'll end up with the odd behavior where CDPATH dirs take precedence over directories in the current working directory, which you probably do not want.
  • Peer Stritzinger
    Peer Stritzinger over 12 years
    No need to change to zsh for TAB completeion since bash has it all the same. For other functionality maybe but not for this.
  • Mr. Shickadance
    Mr. Shickadance over 12 years
    How this has eluded me for so long is a mystery. Thank you very much for this excellent tip.
  • quodlibetor
    quodlibetor over 12 years
    Autojump is probably the best tool for this, it takes a little while to build up the database of common dirs, but once it does I think you'll find that you can't live without it. I know every time I'm on someone else's computer I feel crippled.
  • fire in the hole
    fire in the hole about 12 years
    I do pretty much the same thing, but without the export. That way, CDPATH is not exported to scripts with potentially weird or harmful effects. See here for more discussion and examples.
  • polemon
    polemon about 12 years
    @PeerStritzinger Bash introduced that kind of functionality in BASH 4.0, but compared to zsh, it is still quite far behind. Saying "all the same" is certainly incorrect.
  • Peer Stritzinger
    Peer Stritzinger about 12 years
    Well zsh is ceartainly the übershell but just for tab completion there is no need to change (question was asked for bash). Besides bash 4.0 was introduced about 3 years ago ...
  • Michael Durrant
    Michael Durrant about 12 years
    +1 Certainly one of my favorites and one that somehow many experts have 'missed'.
  • Amir
    Amir about 11 years
    Is this a product you are associated with?
  • Serge Stroobandt
    Serge Stroobandt almost 11 years
    The very same script was also published in the Linux Gazette, Issue #109, December 2004.
  • Jpark822
    Jpark822 over 10 years
    "bash and ksh and cdpath in zsh" ... and in tcsh (just answering a question based on that over on Super User and found this while looking for similar answers on SE).
  • Jakob Bennemann
    Jakob Bennemann almost 10 years
    These are helpful aliases, but I'm not entirely sure that they will match the OP's needs. You might consider expanding on your answer to suggest how these might be directly helpful for the OP's issue.
  • user3189106
    user3189106 almost 10 years
    Thanks for pointing me to cdargs. Simply sudo apt-get cdargs on ubuntu. BTW the youtube video is really bad but the tool is great.
  • somethingSomething
    somethingSomething over 9 years
    @Dean The link goes to a music video and says that Geocities has closed.
  • Dean
    Dean over 9 years
    @somethingSomething Added alternate links.
  • mikeserv
    mikeserv over 9 years
    This is POSIX-specified, I think. At least, the POSIX for cd refers to it.
  • User
    User over 9 years
    thanks love this tool! And although cd - is handy to know if you don't already know it, I think this is a much better solution than the current top answer.
  • G-Man Says 'Reinstate Monica'
    G-Man Says 'Reinstate Monica' over 9 years
    How does this work? If it's aliases, what does this tool do for you that you can't do by manually editing .bashrc?
  • Sam Toliman
    Sam Toliman over 9 years
    It launches daemon that records visited directories in ~/.fastcd for launched shells(bash). "j" launches tool that shows you the last visited directories, with the ability to quickly cd. Modification of .bashrc is required to make the "j" alias. You can see source code for more information, i guess
  • G-Man Says 'Reinstate Monica'
    G-Man Says 'Reinstate Monica' over 9 years
    Thanks for your quick response. This is the sort of information that should be in the answer. Please edit your answer to include this info.
  • Michael Mrozek
    Michael Mrozek about 8 years
    This is like tab-completing, but worse in every way
  • moodboom
    moodboom almost 8 years
    I have several specific project folders i go to regularly, this is the easiest way to set them up and maintain them. Also, for me, it results in the absolute least number of characters typed of all the solutions here. KISS! :-)
  • gena2x
    gena2x over 7 years
    You can't do this with tab completing with euqal amount of keypressing unless Project is only file starting with P, etc. Also you have to wait for completion each time, using * you have no need to wait.
  • Michael Mrozek
    Michael Mrozek over 7 years
    I think you have it backwards -- you can't do P* unless Project is the only file starting with P. Tab completion can cycle (by default in most shells; you need to rebind tab to menu-complete in bash), and resolves instantly in simple cases like this, there's no waiting around for it
  • gena2x
    gena2x over 7 years
    Regarding 'you can't do it' - you can, try it, you missing whole point if you think you can't. Try echo /u*/b*/g++
  • gena2x
    gena2x over 7 years
    After that, try to do same with completion. Measure how much time you spent. /u<tab><tab><tab>r/b<tab>/g++ - 13 keypresses, and some confusion. /u*/*/g++ - 9 keypresses. almost 50% faster to type.
  • gena2x
    gena2x over 7 years
    Another problem with completion is that you can't do things like /abc/*ject*/my*.odt
  • Michael Mrozek
    Michael Mrozek over 7 years
    I understand what you mean, it's faster as long as you're sure you've typed an unambiguous path, but something like /P*/W*/*/mydoc* sounds like it would work fine until one day you happened to make another file that matches that glob, and suddenly you end up opening both at once. /u*/*/g++ is impressively few characters, but hopefully nothing else in any of the subfolders of any of my root folders starting with u is named g++. (As a nice compromise, in some shells you can use tab to expand globs in-place as you go)
  • gena2x
    gena2x over 7 years
    Right. Now, imagine you making 'mistake' in 5% of cases and have to fallback to tab-completion. You still have a great benefit of typing less in 95% of the cases. And if you really know your system well, you usually also know that there is nothing else starting with u in / and there is no other g++ anythere in /usr.
  • ctrl-alt-delor
    ctrl-alt-delor over 7 years
    Installed system-wide on what systems?
  • nealmcb
    nealmcb about 7 years
    @richard It is available as a package (e.g. apt-get install autojump in Ubuntu, but also for many others as documented on their page) for system-wide installation, but each user needs to load it into their shell environment so it can override cd to keep track of where you're going
  • Pablo A
    Pablo A almost 7 years
    Important to say source /usr/share/autojump/autojump.sh should be added to ~/.bashrc for autojump to work.
  • wisbucky
    wisbucky almost 6 years
    Yes, this is sufficient for a few favorite dirs. No need to install any other utilities. Just put the export statements in your ~/.bashrc, and they'll always be available.
  • BenKoshy
    BenKoshy almost 6 years
    I switched to a new Ubuntu PC. Life without autojump is intolerable.
  • user2180794
    user2180794 over 5 years
    history | grep cd
  • Adam Katz
    Adam Katz about 5 years
    When a shell function calls exit, you exit the interactive shell. Those "meaningful aliases" could just be alias back='cd -' and alias up='cd ..' — but don't worry, those commands will never return false (no previous directory? it sends you home! already in root? it's a no-op!) and therefore you'll never exit. Also consider alias back='cd $OLDPWD' (note the single quotes) since it won't have any output (cd - tells you where it is sending you, which is likely unnecessary since your prompt has that info)
  • Adam Katz
    Adam Katz almost 5 years
    Change the function to f() { cd "$(xd -g "$@")"; } to properly handle spaced directories and spaces in the arguments to xd (you probably don't need the path). If you never use xd in another manner, you can alternatively do xd() { cd "$(command xd -g "$@")"; } (alternatively, use /usr/bin/xd in place of command xd – you can always run command xd … if you need to bypass it).
  • Sumak
    Sumak over 3 years
    I'd recommand placing aliases in ~/.bash_aliases for maintenance purpose. It requires your .bashrc to be aware of this file, add if [ -f ~/.bash_aliases ]; then . ~/.bash_aliases fi in your .bashrc (it may already be there)