119

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?

36 Answers 36

1

I never did like pushd and popd because they require foresight. Screw that, let's just keep track of the last several directories on our own and then make them available with a cd-to-old-dirs function. I call it cdo. Put this in your rc file (e.g. ~/.bashrc):

function precmd() { __path_log; }    # to install in zsh, harmless in bash
PROMPT_COMMAND="__path_log"          # to install in bash, harmless in zsh

# Populate the array DIRHIST with the last 8 dirs visited (not for direct use)
__path_log() {
  local d dh first=true
  if [ -d "$__DIRHIST" ] && [ "$__DIRHIST" != "$PWD" ]; then
    # $__DIRHIST is the last dir we saw, but we miss foo in 'cd foo; cd bar'
    # so we use $OLDPWD to catch it; so you'd need a THIRD change to fool us.
    for d in "$__DIRHIST" "${DIRHIST[@]}"; do
      if [ -n "$first" ]; then unset DIRHIST first; DIRHIST[1]="$OLDPWD"; fi
      if [ "$OLDPWD" = "$d" ] || [ "$PWD" = "$d" ] || [ ! -d "$d" ]; then
        continue
      fi
      dh=$((1+${#DIRHIST[@]}))
      [ $dh -lt 9 ] && DIRHIST[$dh]="$d" # push up to 8 directories
    done
  elif [ -z "$__DIRHIST" ]; then
    DIRHIST[1]="$OLDPWD"
  fi
  __DIRHIST="$PWD"
}

cdo() {
  local d n=0
  if [ -z "${DIRHIST[1]}" ] || [ -z "$1" ]; then
    cd ${OLDPWD+"$OLDPWD"}
    return $?
  fi
  case "$1" in
    ls )   for d in "${DIRHIST[@]}"; do echo "$((n=n+1)) <$d>"; done \
             |sed "s:<$HOME:<~:;s:</home/:<~:" |column \
             |GREP_COLORS='ms=0;32' grep --color -e '\b[0-9] <' -e '>' ;;
    [1-9]) cd "${DIRHIST[$1]}" ;;
    * )    [ -d "$1" ] && cd "$1" || echo "Usage: cdo [NUM|ls]" >&2; return 2 ;;
  esac
}

The following example uses a prompt of hash directory dollar (# dir $), chosen because Stack Overflow will make prompts gray:

# ~ $ cd /tmp
# /tmp $ cdo
# ~ $ cdo ls
1 </tmp>
# ~ $ cd /
# / $ cdo ls
1 </home/adam>  2 </tmp>
# / $ cdo
# ~ $ cdo ls
1 </>   2 </tmp>
# ~ $ cdo 2
# /tmp $ cd test
# /tmp/test $ cd ../test2
# /tmp/test2 $ cdo ls
1 </tmp/test>   3 </home/adam>
2 </tmp>        4 </>
# /tmp/test2 $ cdo 4
# / $ cd
# ~ $ cdo ls
1 </>           3 </tmp/test>
2 </tmp/test2>  4 </tmp>

It's really neat to see that other people have had the same general idea as me (I thought I had been original!). @SamTroliman's mention of fastcd, @null's xd, and @phildobbin's j2 all look quite similar. See also duplicate question 84445, which has a zsh answer using setopt auto_pushd. I still prefer my own code, but ymmv.

0

working directory(wd) from atomic seems to be a good package for this: https://github.com/karlin/working-directory

0

Based on your criteria, I think simply defining an alias for each frequently used path in your ~/.bashrc is the way to go. I use this method personally.

alias taxes='cd /users/bob/documents/home/finances/taxes'
alias elvis='cd /dropbox/2016/files/music/elvis'

As I mentioned for a related question (link), if you've gone down the directory tree and want to go back up, .. is my personal favorite. You can jump around within a branch of the tree quite easily with .. going up one directory and ../.. two and ../../.. three, etc. You can also go up and down a different branch with the same command, such as cd ../../example or cd ../../../example/example etc. For a simple switch that goes back and forth between directories, cd - or $OLDPWD are your best bets.

0

I have implemented 2 bash functions:

cdh (cd history): it auto-remembers the last 9 directories und you can back to one of them by entering the number.

cdb (cd bookmarks): you can assign any character to the current directory and later go to this directory by entering this character.

cdh and cdb both work with autocd (aka "cd witout cd").

See http://fex.belwue.de/fstools/bash.html

0

By far the best solution for rapid directory navigation in bash and zsh terminals is to install z - jump around script. This must-have script came recommended by Google Chrome Devtools developer, Paul Irish, in his 2013 Fluent keynote. I can't live without it.

DESCRIPTION Tracks your most used directories, based on 'frecency'.

After a short learning phase, z will take you to the most 'frecent' directory that matches ALL of the regexes given on the command line, in order.

For example, z foo bar would match /foo/bar but not /bar/foo.

[...]

Frecency is a portmanteau of 'recent' and 'frequency'.

0

I've written a script just for that. Here's the link to it on Github.

Here is an example usage:

Let's add a pev variable first:

$ pev add longpath '/A/very/very/long/path/I/frequently/need'
# output:
# environment variable "pev_longpath" added successfully. "pev show" to see the list of pev variables.

Now let's see a list of pev variables defined so far:

$ pev show
# output:

  |   NAMES          VALUES
  |   ----------     ----------
  |   pev_longpath   "/A/very/very/long/path/I/frequently/need"

Then change directory to it:

$ cd $pev_longpath

or copy something into one of its subdirectories:

$ cp somefile $pev_longpath/and/deeper/than/that

In fact, pev variables are no different from other environment variables, they're just probably easier to manage. Please feel free to tell me my errors since I don't have much experience with shell scripting. HTH.

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