DEV Community

Juan Burgos
Juan Burgos

Posted on • Updated on

Easier shell directory navigation

This is another small post to highlight a useful little piece of code that solves a rather annoying problem I deal with on a daily basis.

While the solution is neither unique nor likely the cleanest method, it is one that's simple enough that others can likely find utility in expanding.

Suppose you're in the following situation in your dev environment:

$ cd ${PROJ_DIR}
$ pwd
~/dev/shared/network-interface/dev/shared/network/src/main/java/com/mybiz/network-interface/interface/impl
Enter fullscreen mode Exit fullscreen mode

Suppose further that you'd like to periodically jump between several different directories. It's really annoying doing cd ../../../ and so on, though you do have tools like cd ${OLDPWD} or cd - and such via BASH/ZSH. But this can still be tedious.

In comes the following shell method:

cdback() {
  local -r dirname=${1}
  [[ -z ${dirname} ]] && {
    echo "Missing required parameter: Parent Directory Name\n"
    return 1
  }
  ## Note: https://stackoverflow.com/questions/22537804/retrieve-a-word-after-a-regular-expression-in-shell-script
  ##       ZSH uses ${match} for array while bash has ${BASH_REMATCH}.
  ## Note: https://stackoverflow.com/questions/1335815/how-to-slice-an-array-in-bash
  ##       Made use of nested ${..} bash constructs to rebuild directory path.
  ## Note: Had to do the bash version a bit differently due to "substitution error" with nested ${..} construct.
  ##       Also, array indexing was different between zsh and bash for some reason...
  local -r pattern="^(.+)\/(${dirname})\/(.*)$"
  [[ ${PWD} =~ ${pattern} ]] && {
    [[ -n $ZSH_VERSION ]] && cd "${${match[@]:0:2}/ //}" || cd "$(echo ${BASH_REMATCH[@]:1:2} | tr ' ' '/')"
  } || {
    echo "Parent Directory '${dirname}' could not be found\n"
  }
}
Enter fullscreen mode Exit fullscreen mode

The idea behind this method is that we can use the power of regex to jump up the directory tree to a directory with a name that matches the first argument to the cdback method.

For example:

$ cd ${PROJ_DIR}
$ pwd
~/dev/shared/network-interface/dev/shared/network/src/main/java/com/mybiz/network-interface/interface/impl
$ cdback mybiz
$ pwd
~/dev/shared/network-interface/dev/shared/network/src/main/java/com/mybiz
cd ${OLDPWD}
$ pwd
~/dev/shared/network-interface/dev/shared/network/src/main/java/com/mybiz/network-interface/interface/impl
Enter fullscreen mode Exit fullscreen mode

This even works by repetition:

$ cd ${PROJ_DIR}
$ pwd
~/dev/shared/network-interface/dev/shared/network/src/main/java/com/mybiz/network-interface/interface/impl
$ cdback network
$ pwd
~/dev/shared/network-interface/dev/shared/network/src/main/java/com/mybiz/network-interface
$ cdback network
$ pwd
~/dev/shared/network-interface/dev/shared/network
$ cdback network
$ pwd
~/dev/shared/network-interface
Enter fullscreen mode Exit fullscreen mode

If you want to avoid repetition for similarly named directories, you can include parent/child directories like so:

$ cd ${PROJ_DIR}
$ pwd
~/dev/shared/network-interface/dev/shared/network/src/main/java/com/mybiz/network-interface/interface/impl
$ cdback shared/network-interface
$ pwd
~/dev/shared/network-interface
Enter fullscreen mode Exit fullscreen mode

There's more elegant ways to set this up and to support directories with spaces (but who does that really), but I found this setup immediately useful. Especially for heavily nested project directory structures.

Any comments/criticism are welcome! Hopefully folks find this useful.

Top comments (0)