Submit Hint Search The Forums LinksStatsPollsHeadlinesRSS
14,000 hints and counting!

A more efficient replacement for basename UNIX
Many people use the basename program to obtain the base name of a full pathname, such as in (using the Borne Shell sytax):
Pathname=/usr/bin/archibald
Filename=`basename $FILE`
A far more efficient method, which doesn't require a new process (a very expensive OS task) nor extra memory space, is to use the powerful Shell built-in variable substitution. Thus the above can be done simply by:
Pathname=/usr/bin/archibald
Filename="${Filename##*/}"
If basename is used in many places, this can provide a significant benefit.

System performance is usually improved by making many small improvements. Rarely is there a single change that dramatically improves performance -- so my advice is to make all the small ones you can.
    •    
  • Currently 2.75 / 5
  You rated: 5 / 5 (4 votes cast)
 
[5,584 views]  

A more efficient replacement for basename | 5 comments | Create New Account
Click here to return to the 'A more efficient replacement for basename' hint
The following comments are owned by whoever posted them. This site is not responsible for what they say.
Corrections needed to post
Authored by: barrysharp on Sep 02, '02 03:31:15PM

The two examples given are in error (probably a typo).

The first example using basename should be

<b>
FULLPATH=/usr/bin/archibald
Filename=`basename $FULLPATH`
</b>

and second example using the Shell substitution should be

<b>
FULLPATH=/usr/bin/archibald
Filename="${FULLPATH##*/}"
</b>

Regards... Barry Sharp



[ Reply to This | # ]
This may hurt cross-platform scripts
Authored by: a1291762 on Sep 02, '02 06:22:30PM

If you're writing a shell script that you want to take to another platform at a later time, you don't want to use non-posix features. If you're running that script on Solaris, you have to be even more careful as it's /bin/sh isn't posix compliant.

Built in feature of ksh/zsh/bash like arithmatic '(( foo = foo + 1 ))' or 'let foo = foo + 1' and this 'basename' functionality aren't part of the posix standard (or they might be but they won't work in /bin/sh for some versions of Unix, most notably Solaris).



[ Reply to This | # ]
This may hurt cross-platform scripts
Authored by: barrysharp on Sep 02, '02 08:02:27PM

Agreed -- if portability across various UNIX flavors is paramount to your shell script's operation then one must obviously consider the aspect you describe. However, putting that aside (and of course one can always case the Shell substitution method to avoid its use) removing basename from multiple execution in the hundreds or thousands can be beneficial.

I'm responsible for health monitoring systems at my workplace and any reduction in process creation over the span of years makes our system more productive. As I said in the original post/hint, performance/productivity is obtained in a step-by-step process.

Thanks for your comment.

Regards... Barry Sharp



[ Reply to This | # ]
This may hurt cross-platform scripts
Authored by: mzs on Nov 11, '09 04:42:23AM

I did a trick with IFS=/ for a long time, starting back with some scripts that I wrote originally for SunOS in '95 that then needed to work in HPUX, AIX, and IRIX as well soon after: Here is an example that I just came-up with from foggy memory:

/bin/sh -c 'progname() {
eval progname=\$$#
}

IFS=/
progname $0
IFS="
"

echo "$progname"' /foo/bar/baz
baz

It worked great. The trick is that eval does not spawn a subshell. A generic 'setter' routine can be written using the same tricks. You might think that you can use set instead of a function, but be wary of dashes. As a side benefit, it prevented people setting IFS breaking my broken shell scripts.



[ Reply to This | # ]
excellent
Authored by: mervTormel on Sep 03, '02 10:15:10AM

thanks to you both for pointing out these subtleties.



[ Reply to This | # ]