A z-shell function to quickly cd into projects I think many know the problem of working with multiple projects: private projects, company projects, probably even projects for multiple companies.

From day-one, I've always searched for better ways to handle all those projects on the file system level.  I think I figured out a nice basic directory structure that works for me and my workflow:

~/code/$company_name/$project_name/[$application_name]


But, even with auto-completion and a $CODE var that pointed to ~/code, I had to type a lot more than I wanted when I had to switch between some projects.

So, for the sake of laziness (I also heard some smart guys call it "efficiency," but nah, I'm just lazy) and to learn a bit more about my shell, I decided to write a function that will do some of the work I'm not willing to do.

These were the functional requirements I defined for that function:


quickly cd into a project by given company and project name
possibility to add an optional application name for projects with multiple applications
possibility to pass a flag to create new project directories


Since I'm still a junior developer (1-year work experience, no degree, autodidact) and don't have much experience with shell-scripting, I'm pretty sure there is a lot to improve in my solution.

And since I'm always on the search for improvements, I decided to show my code to those of whom might be more experienced in this than me.

function pcd () {
  local create=false
  local target_dir="$HOME/code"
  local argument_count=$#

  local root
  local app_name
  local project_name

  # When first param is -c, set create flag to true and remove the param
  if [[ $1 == "-c" ]]; then
    create=true
    (( argument_count=argument_count-1 ))
    shift
  fi

  # the root (private, company1, company2, etc...)
  # I really would like to make that optional too, but
  # that would require 
  root=$1

  # $PROJECT_ALIASES is a associative array to map some
  # project aliases to their actual names, it's set globally
  # since it's used in other scripts to and maintained through
  # it's own script
  project_name=$PROJECT_ALIASES[$2]

  # if the passed project string wasn't an alias,
  # assume it was the raw project name
  if [[ ! -n $project_name ]]; then
    project_name=$2
  fi

  # the app folder (for multi application projects, optional)
  app_name=$3

  # validate required params
  if [[ ! (( -n $root &amp;&amp; -n $project_name )) ]]; then
    echo "[ERROR] - Please pass at least a root dir and a project name" &gt;&amp;2
    return 1
  fi

  target_dir="$target_dir/$root/$project_name"
  if [[ -n $app_name ]]; then
    target_dir="$target_dir/$app_name"
  fi

  # When the create flag is true (-c), create target directory
  if [[ $create == true ]]; then
    mkdir -p $target_dir
  fi

  # Finally, cd to the targeted directory
  cd $target_dir
}
Remove unused variables

The variable argument_count is not used for anything, so you should remove it.

Simplify shell arithmetics

Instead of this:


(( argument_count=argument_count-1 ))



You could simplify using the postfix operator:

(( argument_count-- ))


Simplify condition

This condition can be written simpler:


if [[ ! (( -n $root &amp;&amp; -n $project_name )) ]]; then



Like this:

if ! [[ -n $root &amp;&amp; -n $project_name ]]; then


Note that you could also drop both of the -n flags there,
the expression will still mean the same:

if ! [[ $root &amp;&amp; $project_name ]]; then


For the same reason, I suggest to drop all the -n in all conditions.

Always double-quote path variables

At some places you did a good job double-quoting path variables:


  target_dir="$target_dir/$root/$project_name"
  if [[ -n $app_name ]]; then
    target_dir="$target_dir/$app_name"
  fi



At others you didn't:


  # When the create flag is true (-c), create target directory
  if [[ $create == true ]]; then
    mkdir -p $target_dir
  fi

  # Finally, cd to the targeted directory
  cd $target_dir



Make it a habit to double-quote path variables always.