Episode: 4607 Title: UNIX Curio #3 - basename and dirname Source: https://hub.hackerpublicradio.org/ccdn.php?filename=/eps/hpr4607/hpr4607.mp3 Transcribed: 2026-07-31 16:15:02 (official HPR transcript) --- This is Hacker Public Radio Episode 4607, for 2026-03-31 Today's show is entitled, "UNIX Curio #3 - basename and dirname" The host is Vance and the duration is 00:13:08 The flag is Clean, and the license is CC-BY-SA The summary is "Pulling apart filenames" Hi there, I'm Vance and welcome to Unix Curio Number 3. This series is dedicated to exploring little known and occasionally useful, trinkets lurking in the dusty corners of Unix-like operating systems. Hopefully it doesn't seem like I'm picking on Linux Journal, but as with Unix Curio Number Number 1 about Shaw, that's Hector Public Radio Episode 4587. This entry has been inspired by an article of theirs. See the show notes for links to the article and other references. The author was demonstrating a clever bash shell script function that would take a file name and send the file to standard output, or if the file name ended in .gz, it would decompress the file and send the result to standard output. This way you could run the function against a set of text files, some of which are compressed and some not, and have only text appear on your screen instead of unreadable binary gibberish. The way that he accomplished this was to take the value of the first positional parameter given to the function, represented by $1.1, remove the extension .gz off the end if present, and test whether a file with the resulting name exists. If it does, the function would just run cat with the file. Otherwise, if the name with .gz at the end exists, it would run g on zip with the height and c option to decompress the file and send it to standard output. The method chosen to remove the .gz extension was to pipe the name through an appropriate pro command. This earned the author some criticism on the website and in letters to the magazine for cranking up a whole pro interpreter just to chop three characters off the end of a file name. Our curio for today is a standard unix utility made for just this purpose called base name. Along with its sibling, during name, it is used to pull apart path names to get the part that you want. What base name does is remove any leading path on the name given to it, and if a suffix is specified as well, removes that also. If a directory path is given, with or without a trailing slash, it returns the last part with no slashes. I'll explain with some examples, but they might be a little easier to understand if you read the show notes. It isn't always clear to listen to commands and code that are read out loud. Running base name space slash bin slash gzip would return gzip. That's the last part. Running base name space slash bin slash gzip space dot SO would also return gzip. In this case, since the path name argument that you gave it doesn't end with dot SO, the only part that gets removed is the leading path. But what if it does? Running base name space slash user slash lib slash libz.so, space dot SO would return libz. The final part of the path name without the provided extension. The suffix can be any text, it doesn't have to be an extension or start with a dot. Although that is the way that base name is most often used. When you provide a directory name to the command, such as base name space slash user slash lib, you would get the last part. In this case, just lib with no slashes. The counter part, dername does essentially the opposite. It removes the last part of the path name and returns a directory name with no trailing slash. Running dername space slash user slash lib slash lib z dot SO would return slash user slash lib. Running dername space slash user slash lib would return slash user. Running dername against a name that contains no slashes simply returns a dot representing the current working directory. I should point out that neither of these utilities cares whether a file or directory with the given name actually exists. All they do is act on the text string that's been fed to them. If you want to use the resulting output in a script, you should take care to use the test command with the appropriate option to check that the file or directory exists before trying to do something with it. To give a historical perspective, base name came first. It was present in Bell Laboratory's 7th edition Unix and made its way into the University of California's BSD 2.9. According to the free BSD manual page, dername did not appear until later in AT&T's system 3. It did not go into the University of California's BSD until version 4.4. Standardization of these commands followed a similar pattern. Base name first appeared in 1987 in the X-open portability guide which preceded and then existed alongside POSIX. All it appears that a dername specification didn't emerge until the early 1990s. Not all of these standards are freely available online, so it is difficult for me to track down exactly when certain things were added. However, it is clear that these utilities have been standardized for over 30 years, so it's a pretty safe bet that you'll find them both unless you're using a very old Unix-like system. Getting back to the shell script, we can replace the name editing part by taking the output of dername, space, dollar sign 1, follow it with a slash character, then follow that with the output of base name, space, dollar sign 1, space.gz. It will give us the same result and we can be sure it will work on any Unix-like system, no pearl necessary. Many of you might be thinking, I could do that with said too, and you're right. Basically the command the original script fed to pearl would work exactly the same with said, because said is a standard utility, it should already be present on every Unix-like system, while pearl might not be. One might suspect that as a general purpose text processor said would be slower than base name and dername. To see how they compared, back when I originally wrote this article in 2010, I ran each method 5,000 times with a different randomly generated file name each time. It turns out that the critics were right, as the pearl method took the longest time to run at 59 seconds. Using base name and dername took 44 seconds, a nice improvement, but said blew past that at 34 seconds. Probably the fact that the script needed to make only one call to said versus two for base name and dername made the difference. Helpful suggestions in response to the article revealed a shell curio. You might have seen the curly brace syntax for parameters. For example, say you have a file name in a variable named f. To show the file name with a letter x appended, you can't use echo space dollar sign fx because that means a variable with the name fx. Instead you would put curly braces around the f and follow that with x. The shell only interprets what's inside the curly braces as being a variable name. Modifiers can also go inside the curly braces and one of these, the percent sign, is just what we need to chop off that extension. This works in bash, the z shell that's z as in zebra, the corn shell, and any shell conforming to the posics standard. However, it does not work in the c shell that's c as in Charlie or older implementations of the born shell that predate posics. We can rewrite the part of the original function that removes the dot gz using dollar sign, left curly brace, one percent sign, dot gz, right curly brace, and forego any outside utilities. Performance. After half a second to process those 5,000 file names, not bad at all. Thanks for listening and keep an eye out for our next Unix Curio, which will be about archiving utilities and formats, here on hiker public radio. If you have a question or a suggestion for a future topic, please comment on this episode on the hpr website. You have been listening to the Hacker Public Radio podcast, at hackerpublicradio.org. Today's show was contributed by a HPR listener like yourself. If you ever thought of recording a podcast, then visit the HPR site to find out how easy it really is. Hosting for HPR has been kindly provided by anhonesthost.com, the Internet Archive, rsync.net, and the HPR Community Content Delivery Network. Unless otherwise stated, today's show is released under a Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.