Bash .. Going Up

I've been doing a lot of work in the bash shell lately and thought I'd share one of the hacks that makes life just a little easier. For me, the 'cd ..' command is awkward. Especially when trying to go up several directories. cd ../../../.. It's easy to get lost on which directory you are on.

I tried looking for a better way online, but couldn't find anything. Because of this, I came up with my own little bash function. And here it is, copied directly from my .bash_aliases file.

# Go up directory tree X number of directories
function up() {
	COUNTER="$@";
	# default $COUNTER to 1 if it isn't already set
	if [[ -z $COUNTER ]]; then
		COUNTER=1
	fi
	# make sure $COUNTER is a number
	if [ $COUNTER -eq $COUNTER 2> /dev/null ]; then
		nwd=`pwd` # Set new working directory (nwd) to current directory
		# Loop $nwd up directory tree one at a time
		until [[ $COUNTER -lt 1 ]]; do
			nwd=`dirname $nwd`
			let COUNTER-=1
		done
		cd $nwd # change directories to the new working directory
	else
		# print usage and return error
		echo "usage: up [NUMBER]"
		return 1
	fi
}

Basically what this function does is allows you to type up X to go up X number of directories. So if I wanted to go up 3 directories, in my bash prompt I would just type up 3 instead of cd ../../...

Additionally, up defaults to going up a single directory. So instead of typing up 1 for cd .., you just have to type up. I've found that I can type up a lot faster than hitting the '.' key twice. For all the time I spend in the bash command prompt, little improvements like this go a long way.

If you think this might help you out, go ahead and copy that function into your .bash_aliases and enjoy.

An explanation

For those of you who aren't content to just copy/paste this function into your .bash_aliases, and actually want to know how it works, here's a breakdown of the code above.

COUNTER="$@";
# default $COUNTER to 1 if it isn't already set
if [[ -z $COUNTER ]]; then
	COUNTER=1
fi

This beginning chunk passes any arguments given to $COUNTER. If there is no argument, then $COUNTER is set to 1. -z checks if a variable is set to an empty string (i.e. null).

# make sure $COUNTER is a number
if [ $COUNTER -eq $COUNTER 2> /dev/null ]; then

This is a great trick I learned from http://grzechu.blogspot.com/2006/06/bash-scripting-checking-if-variable-is.html for checking if a variable is numeric or not. It returns 1 if $COUNTER is a number and 0 if it isn't. In the else block, at the bottom of the script, I have it print a usage statement telling them to provide a number and then I return a 1. Returning a 1 in a shell script means something went wrong. Returning a 0 means the script executed without any problems. If the function gets to the end without any return statements it will default to returning a 0.

So all of that code is for getting the input, setting it to a default and doing some basic error checking. Now onto the meat of this bash function.

nwd=`pwd` # Set new working directory (nwd) to current directory

I think the comment on this line make it pretty clear what we're doing. This is our starting directory and we are going to go up from here.

# Loop $nwd up directory tree one at a time
until [[ $COUNTER -lt 1 ]]; do
	nwd=`dirname $nwd`
	let COUNTER-=1
done

The until statement is just another form of a while loop in bash. Only it loops while the statement is false instead of while it is true, i.e. "until" the statement becomes true. So here we are looping until our $COUNTER variable is less than 1, which would be 0.

Each iteration of the loop we set $nwd to the next directory up. We do this by using the dirname command which chops off the last directory in $nwd. The nice thing about dirname is that once you get to the root directory /, it just returns / without throwing any errors. So we don't need to check if $COUNTER is more than the number of directories in our current path. It will just get up to the root directory and stop there.

And of course we need to decrement $COUNTER each iteration.

cd $nwd # change directories to the new working directory

Finally we change directories to $nwd. In my original script I changed directories inside the until loop. Instead of setting $nwd, I had a cd .. command. However, doing that meant that I couldn't cd - back to the directory I had started from. Changing the script so that it only does the cd command once meant that cd - still works to get me right back to the original directory. By the way, if you don't know about cd -, it's a very convenient command for jumping back to the directory you were previously in.

If you have any questions about this function, or see ways to improve it, please let me know. I may be reinventing the wheel here, but I couldn't find anything online to add this functionality so I thought I'd post my own solution. If you know of a better way to do this, please post it in the comments.

This entry was posted in Linux, Tips and tagged , , , , , . Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • JETM

    Another way to do it:

    # up n
    up ()
    {                                                                                                 
      [[ $# -eq 0 ]] && cd ..                                                                         
      if [[ $1 =~ ^[0-9]+$ ]] && [[ $1 -gt 0 ]]                                                       
      then                                                                                            
          dirs=1                                                                                      
          until [[ $dirs -gt $1 ]]                                                                    
          do                                                                                          
              command=”${command}../”                                                                 
          dirs=$(($dirs+1))                                                                           
          done                                                                                        
          cd $command                                                                                 
          command=”                                                                                  
      fi                                                                                              
    }

  • olli

    Nice script, but it fails if there are space in the dir name. My version:

    # Go up directory tree X number of directories
    function up() {
    COUNTER=”$@”;
    # default $COUNTER to 1 if it isn’t already set
    if [[ -z $COUNTER ]]; then
    COUNTER=1
    fi
    # make sure $COUNTER is a number
    if [ $COUNTER -eq $COUNTER 2> /dev/null ]; then
    nwd=”`pwd`” # Set new working directory (nwd) to current directory
    # Loop $nwd up directory tree one at a time
    until [[ $COUNTER -lt 1 ]]; do
    nwd=”`dirname “${nwd}”`”
    let COUNTER-=1
    done
    cd “${nwd}” # change directories to the new working directory
    else
    # print usage and return error
    echo “usage: up [NUMBER]”
    return 1
    fi
    }

    • http://orangesplotch.com Matt Carpenter

      Thanks for the correction. Yes, I have had this bite me in the past, and I’ve updated my own script but hadn’t updated the code in this post. I appreciate you taking the time to reply with a fix.