November 6, 2007

Four ways to extract the current directory name

Author: Sergio Gonzalez Duran

When you're programming a shell script, you often only need the current directory name, not the whole path that the pwd command returns. Here are four ways you can extract only the current directory.

Using basename

Using the basename command is the easiest and simplest way to extract the current directory:

basename /usr/local/bin
bin

However, it isn't useful in a shell script with changing directory variables. You can combine it with pwd inside backticks to make it more dynamic:

cd /usr/local/binbasename `pwd`
bin

Using parameter substitution with echo

The bash scripting language is full of nice tricks, including parameter substitution, which allows you to manipulate or expand variables. You can use parameter substitution with the ${var##pattern} syntax, which removes from $var the longest part of $Pattern that matches the front end of $var. Take a look at an example:

cd /var/log/squidecho ${PWD##*/}
squid

PWD is the environment variable that holds the current path, and ## is the instruction that tells the script to remove everything it finds up to */. In other words, it removes everything until the last /, leaving only the last string, which here is the current directory, squid. You can learn more about parameter substitution and other ways to manipulate variables in the Advanced Bash-Scripting Guide.

Using awk and rev

A more elaborate solution uses a combination of awk (a pattern-scanning utility) and rev (a utility that reverses lines from a file or from stdin):

cd /usr/share/cups/datapwd | rev | awk ââ¬âF \/ '{print $1}' | rev
data

It's a lot easier to understand this kind of script step by step:

pwd
/usr/share/cups/data
pwd | rev 
atad/supc/erahs/rsu/
pwd | rev | awk ââ¬âF \/ '{print $1}'
atad
pwd | rev | awk ââ¬âF \/ '{print $1}' | rev
data

The -F option indicates that you should separate by fields, where the field delimiter is /, and that you should print field 1.

Using sed

Finally, you can parse pwd output in the stream editor sed using an elaborate regular expression. This approach may be educational, but it's not practical:

cd /home/smith/musicpwd | sed 's,^\(.*/\)\?\([^/]*\),\2,'
music

For a better understanding of how this works, remove the escape character (\), which is required for special characters such as "(":

sed 's,^(.*/)?([^/]*),\2,'

s substitutes one string for another. It looks for two patterns, which are indicated between the first comma and the second comma. The first pattern (^(.*/)?) searches from the beginning of the line (^) until the last occurrence that it finds of / (in the example, it matches /home/smith/). The second pattern (([^/]*)) searches everything from the last pattern except the / character , which is indicated by [^/]*, where ^ at the beginning of the square brackets means not. This results in both /home/smith/ and music. The second part of this regular expression is the substitution, indicated by \2. In sed, this is called a back reference. As its name implies, it goes back and recalls a previously used reference. There may be nine of these, named \1, \2, \3, and so on. In the example, \2 refers to the second pattern found, which is music -- the result expected.

As you can see, Linux gives you many ways to find a directory name. Having many choices for the same chore is one of its strengths.

Categories:

  • Tools & Utilities
  • System Administration