The first step in my attempt to build a more productive environment was to set up my own dotfiles project. I did not want to loose the setup or manually copy bits and pieces from one machine to another. I found http://dotfiles.github.io to be a good starting point.

I'm constantly trying to improve my working environment. If you already have a nice collection of dotfiles, I'd love to hear about your favorite bits.

More than just an alias

Reading other peoples dotfiles was quite inspiring, but there is one very simple trick that I'd like to highlight here: Define the most commonly used commands as single letter functions.

A function allow you to do more than a simple alias g='git'. For example, it can define meaningful default behavior in case you invoke it without arguments:

function g {
  if [[ $# > 0 ]]; then
    git $@
  else
    git status --short --branch
  fi
}

That prints a nice and compact git status summary. If you do provide arguments, it behaves like an alias to git. I've stolen the g function from someone elses dotfiles and I've used it so much, it inspired me to write more functions myself.

The 'v' function

Oftenly, I started working on something by opening vim, finding a source file, finding the corresponding test case and then trying to remember what I actually wanted to do. I guess you know what I'm talking about, regardless of which editor you are using. I had v as an alias for vim, but I wanted to be able to open files with similar names with a single command (e.g. calendar.js and calendar-test.js. I changed v to a function that uses find if an argument is given. Later, I extracted the f function out of v because it's already useful by itself:

F_CMD='find . -type d \( -path "**/node_modules" -o -path "**/.*" \) -prune -o -wholename "$1"'
function f {
  if [[ $# > 1 ]]; then
    eval "$F_CMD -exec grep -nHF \"$2\" {} \; ;"
  elif [[ $# > 0 ]]; then
    eval "$F_CMD -print"
  else
    echo 'Usage: f file_name [file_content]'
  fi
}

This will search all files in the current directory, ignoring node_modules and hidden directories. You can specify any part of the file path. If you want to search for somethign lile test-*.js in the file name, remember to put it in quotes or bash will expand it before searching. If a second argument is given, it greps through all the files that matched.

This function is then used by v. It passes the results of f to vim. I didn't try, but I guess this works as well with other editors like mate and subl (let me know if you tried):

function v {
  if [[ $# > 0 ]]; then
    if [[ $1 == "*"* ]]; then
      RESULTS=$(f "$1*")
      COUNT=`echo $RESULTS | wc -w`
      if [[ $COUNT > 5 ]]; then
        read -p "Found $COUNT results. Open all? (Y/n) " -n 1
        echo
        if [[ $REPLY =~ ^[Nn]$ ]]; then
          return
        fi
      fi
      vim $RESULTS
    else
      vim $1
    fi
  else
    vim
  fi
}

If you pass one argument and it starts with a *, it will use the f function to find matching files and open them in vim. This allows me to write v *calendar to open all files with calendar in their name. If the argument does not start with a *, it behaves just like an alias for vim.

Functions in your dotfiles?

Feel free to copy and tweak for your own needs. I'd be interested in the improvements you made.

What is your favorite shell function? I'd love to learn from your experiences.


comments powered by Disqus