This is a read-only archive. Find the latest Linux articles, documentation, and answers at the new Linux.com!

Linux.com

Feature: Tools & Utilities

Four ways to extract the current directory name

By Sergio Gonzalez Duran on November 06, 2007 (9:00:00 AM)

Share    Print    Comments   

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/bin
basename `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/squid
echo ${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/data
pwd | 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/music
pwd | 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.

Sergio Gonzalez Duran is a Linux administrator, systems developer, and network security counselor who also teaches Linux courses and publishes the Spanish-oriented Linux and open source Web site linuxtotal.com.mx.

Share    Print    Comments   

Comments

on Four ways to extract the current directory name

Note: Comments are owned by the poster. We are not responsible for their content.

Four ways to extract the current directory name

Posted by: Anonymous [ip: 127.0.0.1] on November 06, 2007 09:31 AM
The awk and sed solutions given are far more complicated than they need to be.
Simpler solutions are:


pwd | awk -F / '{ print $NF }'

pwd | sed 's,.*/,,'

#

Strange that bash does not have a simple indexOf

Posted by: Anonymous [ip: 153.110.6.241] on November 06, 2007 11:28 AM
In other languages as REXX or java or .... One can test for a string in a string and get back a position which can be used in a substring. But not in Linux shell .......?

#

One more way to extract the current directory name

Posted by: Anonymous [ip: 59.145.136.1] on November 06, 2007 11:44 AM
echo `pwd` | rev | cut -f1 -d"/" | rev

#

Re: One more way to extract the current directory name

Posted by: Anonymous [ip: 217.113.238.142] on November 10, 2007 01:04 PM
why not just
pwd | rev | cuf -f1 -d'/' | rev
?

#

Four ways to extract the current directory name

Posted by: Anonymous [ip: 147.88.200.144] on November 06, 2007 12:29 PM
An easier way or at least a shorter command than
pwd | rev | awk –F \/ '{print $1}' | rev
would be
pwd | awk -F \/ '{ print $NF }'

awk knows the variable $NF which contains the "number of fields" so { print $NF } gives you the last field


just my 2¢

#

Four ways to extract the current directory name

Posted by: Anonymous [ip: 89.219.147.3] on November 06, 2007 01:18 PM
Hehe, I join in laughter with fake stevie here. Multiple rev's and awk and piping for such a trivial task? Kind of like taking a car engine apart thru the exhaust pipe -- hey man, why walk 10 ft straight on the pavement when you can take a 100 km detour thru mud, water and fire.

Stick with the first example if you don't know what you're doing.

#

Re: Four ways to extract the current directory name

Posted by: Anonymous [ip: unknown] on November 08, 2007 02:24 PM
Totally disagree with you, I have been doing C and bash programming for a long time, and sometimes (not very often really) I need the current directory name, I always used basename `pwd` to extract it, but thanks to this tutorial I found out the much better alternative echo ${PWD##*/}, I use parameter substitution a lot, but never thought about this one. With this choice no overhead is produce when running the script, perhaps to you this little overhead doesn't matter, but most of the C programmers or good programmers in any language are always searching ways to tweak a little bit more, and a little bit more and so many times until the program runs as smooth as possible.
Good article.

#

Four ways to extract the current directory name

Posted by: Anonymous [ip: 68.15.208.161] on November 06, 2007 01:47 PM
If you guys had actually read the article, you'd notice that all you really need is basename `pwd`, one command, two words. That's pretty simple, the rest of the article was a good tutorial for programmers and developers who actually use their machines, feel free to skip it if it was over your head... Really Steevie? how would you do this in Windoze... oops I mean DOS?

#

Re: Four ways to extract the current directory name

Posted by: Anonymous [ip: 98.135.1.236] on November 07, 2007 05:52 AM
In a compromised system, the proper binaries ("ls", "grep", "sed", etc., and yes, even "pwd") may not be available. You may need something like "echo ${PWD##*/}" to get real, uncompromised output.

#

Any way to extract the script's directory

Posted by: Anonymous [ip: 216.27.162.2] on November 06, 2007 03:03 PM
Is there any way to extract the directory in which the shell script actually resides?

(As in, if I put a script in /usr/local/bin/script.sh and execute it from ~, is there a way to have the script know it is physically in /usr/local/bin?)

Thanks!

#

Re: Any way to extract the script's directory

Posted by: Anonymous [ip: 24.35.36.4] on November 06, 2007 03:45 PM
which $( basename $0 )

#

Re(1): Any way to extract the script's directory

Posted by: black rabbit on November 06, 2007 04:04 PM

[Modified by: black rabbit on November 06, 2007 04:05 PM]

#

Re: Any way to extract the script's directory

Posted by: Anonymous [ip: 65.79.229.3] on November 09, 2007 05:39 PM
There are some examples at <a href="http://crashingdaily.wordpress.com/2007/09/22/bashing-perl-findbin/">http://crashingdaily.wordpress.com/2007/09/22/bashing-perl-findbin/</a>

These examples resolve relative paths and expand ~ to physical paths.

#

Re: Any way to extract the script's directory

Posted by: black rabbit on November 06, 2007 03:39 PM
echo ${0%/*}
[Modified by: black rabbit on November 06, 2007 03:40 PM]

#

Unnecessary

Posted by: Anonymous [ip: 69.248.159.33] on November 06, 2007 04:03 PM
The current directory's name is always... wait for it... "."

Sorry.

#

Four ways to extract the current directory name

Posted by: Anonymous [ip: 199.209.144.27] on November 06, 2007 04:07 PM
pwd | awk –F \/ '{print $NF}'

#

Number 5: Perl Way(s)

Posted by: Anonymous [ip: 12.2.142.7] on November 06, 2007 04:10 PM
Perl's command line methods are similar to awk, but there are multiple options:

For example: you could use a substitution to remove all but the last element of the path:

pwd | perl -p -e 's/.*\/([^\/]+)$/$1/o'

In the above, '-p' tells per to read in all input lines one at a time to the $_ variable and then print the value of $_ when processing is done. The '-e' tells perl to execute the string that follows as a script to operate on $_. the 's/' starts the substition type regular expression which will operate on $_. The '.*\/' matches any characters up to and including a forward slash. '([^\/]+)' captures a string that does not contains any backslashes, and the '$' at the end ensures this captured string is at the end of the input line. The resulting $1 (the captured string) is then assigned as the new value of the implicit $_ variable which was passed to the substitution and will be printed out (since we specified '-p' at the command line).

Another way would be to use a split into an array and then print the last element of the array:
This can take two different forms:

pwd | perl -e '@a=split(/\//o,<>);print $a[-1];'

pwd | perl -p -e '@a=split(/\//o,$_);$_=$a[-1];'

In the first example, we omit '-p' and simply read in stdin directly via the '<>' operator, and this data is split by the '/\//o' regular expression (which matches on all backslashes) into an array '@a', and then the print command sends the last element of the array 'a[-1]' to stdout.

In the second example, we leverage the fact that 'split()' implicitly splits the input data in $_, and then we can simply reassign $_ to the last element in @a, which is $a[-1].

#

Re: Please, let perl die

Posted by: Anonymous [ip: 80.108.103.172] on November 07, 2007 08:38 AM
Please, let perl die.

It is an ancient language with ugly syntax and nowhere going into the C/C++ bindings world.

The world belongs to Ruby and Python.

Bye, perl.

#

Re(1): Please, let perl die

Posted by: Anonymous [ip: 204.193.45.69] on November 07, 2007 11:56 AM
Perl has beautiful syntax and is so easy to use.

There is plenty of space for lots of languages, just because someone chooses one language you do not like does not mean you have to p*ss on their choice. Grow up and then we can debate things in an adult fashion.

#

Four ways to extract the current directory name

Posted by: Anonymous [ip: 209.30.37.151] on November 06, 2007 08:59 PM
If I were needing the name of the current directory (and I have never needed it so far, because as someone else said, '.' is always right) then I would use the parameter substitution feature of bash. All the rest are going to be starting at least 1 (if not several) new processes.

#

Unneccesary, but how you get the name from "." ?

Posted by: Anonymous [ip: unknown] on November 07, 2007 02:42 AM
Someone post (and agree) that these scripts are unnecesarry because the current directory is always ".", but how do you get the name of the directory from "."?

#

Typo or perhaps something more sinister(?)

Posted by: Anonymous [ip: 76.246.139.253] on November 07, 2007 09:35 PM
The line:
"atad/supc/erahs/rsu/"

Should be:
"atad/spuc/erahs/rsu/"

Else, that is one wild rev. . .

#

This story has been archived. Comments can no longer be posted.



 
Tableless layout Validate XHTML 1.0 Strict Validate CSS Powered by Xaraya