|
Four fun Unix commandsA look at basename, dirname, time, and tee |
In this last of four columns on "small fry" Unix commands, Mo shows you how to snip directory paths and filename extensions with thebasename
anddirname
commands. He also explains how to usetee
to write the output from a piped command into a file. Finally, Mo covers thetime
command, which can be used as a simple performance measuring tool. (2,000 words)
Mail this article to a friend |
basename
The basename
command will strip off the directory portion of a filename path
and return only the filename itself. In the following example, basename
is
used to strip the directory path from the filename so it returns simply
file.txt
.
$ basename /this/is/a/file.txt file.txt $
In the example above, the file and path don't necessarily even exist. The
basename
command analyzes the string and takes out the pieces it
estimates to be the directory path. Basically, it leaves the last piece of the
string that doesn't contain a slash (/). It also removes any trailing slash in
order to identify the base portion of the name. In the following listing, the
final slash is removed before evaluating the string and returning the word
file as the "base" for the string.
$ basename /this/is/a/file/ file $The
basename
utility is very useful for situations in which files are
replicated across multiple directories. In a hypothetical system, a series of
directories contain the current versions of documents, the newest versions of
documents to replace the current versions, and two earlier versions of the
same documents where they've been replaced. Assuming that the directories
are named new, current, old and oldest, a process is needed to
check the names of all the new documents in the new directory. Any documents with the same
name in the old directory are moved to the oldest directory, any documents
with the same name in the current directory are moved to the old directory,
and finally the new documents are moved to the current directory. Using a
for name
loop, the code to do this would look as follows (the listing
is numbered for explanatory purposes):
1 for name in /docs/new/* 2 do 3 fname=`basename $name` 4 if [ -f /docs/old/$fname ] 5 then 6 mv /docs/old/$fname /docs/oldest/$fname 7 fi 8 if [ -f /docs/current $fname ] 9 then 10 mv /docs/current/$fname /docs/old/$fname 11 fi 12 mv /docs/new/$fname /docs/current/$fname 13 doneThe
basename
command is used to extract just the
filename portion into the variable fname
. From there, the $fname
variable is used to construct various tests and copies. The for name
loop at
line 1 sets the variable $name
to each filename that matches /docs/new/*
and then executes the logic between lines 2 and 13. At line 3 basename
is used to
extract just the file portion of the name into the variable $fname
. Once the
base portion of the filename is identified, a series of tests and
moves can be executed. At line 4 the logic tests to see if a file of the same
name exists in the /docs/old directory. If it does, it's moved to /docs/oldest
at line 6. This is repeated for the /docs/current and docs/old directories
at lines 8 through 11. Finally, at line 12 the file in /docs/new is moved into /docs/current. The logic at line 12 doesn't bother testing for the existence of the file because the for name
logic started at line 1 has established that something does exists in /docs/new.
This logic assumes that the /docs/new directory will only contain files that
are to be installed in /docs/current and will not contain subdirectories.
Removing extensions
The basename
utility also allows the extension or suffix to be stripped from a
file basename. The extension to be stripped is added after the file path. In the following example, .txt
is added after the filename. The return from basename
is the single word file:
$ basename /this/is/a/file.txt .txt file $
To illustrate this hypothetically, assume that documents in the master directory are copied to a holding directory for comments. Any comments are written to a file with the extension .comment. For example, a document named proposal.doc might have a corresponding file named proposal.comment containing any comments on the document.
A process to gather up the comments has two jobs to do. First it must check that comments have been entered for a document and remove the copy of the document and the comments. Its second task is to raise an alert about any documents that have not been commented on. A process to do this is illustrated in the following numbered listing:
1 for name in /docs/for_comment/*.doc 2 do 3 bname=`basename $name .doc` 4 cname=${bname}.comment 5 dname=${bname}.doc 6 if [ -f /docs/for_comment/$cname ] 7 then 8 mv /docs/for_comment/$cname /docs/master/$cname 9 rm -f /docs/for_comment/$dname 9 else 10 echo "No comments received for $dname" 11 fi 12 done
At line 1, the name of every doc file in /docs/for_comment is
extracted into the $name
variable. At line 2, the filename is
stripped of both the directory information, and the file extension.
At lines 4 and 5, this root is built up again into two variables
containing filename.doc and filename.comment. At line 6, a test is
made for a file with a .comment extension. If one is found, the
comment file is moved back into the master directory, and the
temporary version of the document that was placed in
/docs/for_comment is removed. If no comment file is found, a
message is displayed on the console that comments are missing for
the document. This is repeated for each doc file in /docs/for_comment.
dirname
The dirname
utility is the complement of basename
. It
returns the "path" component of a file pathname string, as shown in
the following listing. In the second dirname
example,
dirname
also removes the trailing slash before
attempting to understand the string. The result is that the
dirname
portion of /x/y/z/
is /x/y
:
$ dirname /this/is/a/file.txt /this/is/a dirname /x/y/z/ /x/y $
dirname
has no options for the command and simply
returns the directory portion of a file path. It is not used as
often as basename
.
Looking at performance with time
The time
command is excellent for analyzing the
performance of a shell script or command. Simply type
time
followed by the command that you wish to time.
Three results are printed when the program or script finishes
executing: the actual length of time (real-world time spent on the
program), the total time spent in the program, and the total time
spent on CPU overhead. The first figure is perhaps the most useful,
but the third figure will tell you how busy your CPU is.
$ time bigjob.sh real 10m 10.55s user 4m 08.47s sys 1m 12.14s
Some older versions of time
report the results in seconds only, as in the
following listing:
$ time bigjob.sh real 610.55 user 248.47 sys 72.14
tee
The tee
utility is one of my personal favorites and is
very simple. The command is intended to be used in a pipe to capture
the standard output of another command and display it on the screen, as
well as copy it to a file. In the following example, the directory
listing is displayed on the screen, and also copied to the file
dir.txt. Using cat
to type out the dir.txt file shows
that it contains the same information that was displayed on the screen.
$ ls -l|tee dir.txt total 141 -rwxrwxrwx 1 mjb group 16850 Apr 12 16:13 SMALL01.DOC -rwxrwxrwx 1 mjb group 14881 Apr 12 20:51 SMALL02.DOC -rwxrwxrwx 1 mjb group 17758 Jun 13 01:29 Small03.doc -rwxrwxrwa 1 mjb group 12791 Jul 12 22:44 Small04.doc -rwxrwxrwx 1 mjb group 4232 Jun 12 00:03 Smallxx.doc drwxrwxrwx 1 mjb group 0 Jul 12 21:25 docs -rwxrwxrwx 1 mjb group 261 Jun 13 01:08 hello.cbl -rwxrwxrwx 1 mjb group 184 Jun 13 00:59 hello.txt -rwxrwxrwa 1 mjb group 343 Jul 12 21:32 mver -rwxrwxrwa 1 mjb group 83 Jul 12 19:52 sh_histo -rwxrwxrwx 1 mjb group 455 Apr 12 18:10 simpmenu -rwxrwxrwx 1 mjb group 600 Apr 12 18:39 simpmenu.txt -rwxrwxrwa 1 mjb group 17 Jul 12 22:24 sleepy -rwxrwxrwx 1 mjb group 189 Jun 13 01:13 smallfry.txt $ cat dir.txt total 141 -rwxrwxrwx 1 mjb group 16850 Apr 12 16:13 SMALL01.DOC -rwxrwxrwx 1 mjb group 14881 Apr 12 20:51 SMALL02.DOC -rwxrwxrwx 1 mjb group 17758 Jun 13 01:29 Small03.doc -rwxrwxrwa 1 mjb group 12791 Jul 12 22:44 Small04.doc -rwxrwxrwx 1 mjb group 4232 Jun 12 00:03 Smallxx.doc drwxrwxrwx 1 mjb group 0 Jul 12 21:25 docs -rwxrwxrwx 1 mjb group 261 Jun 13 01:08 hello.cbl -rwxrwxrwx 1 mjb group 184 Jun 13 00:59 hello.txt -rwxrwxrwa 1 mjb group 343 Jul 12 21:32 mver -rwxrwxrwa 1 mjb group 83 Jul 12 19:52 sh_histo -rwxrwxrwx 1 mjb group 455 Apr 12 18:10 simpmenu -rwxrwxrwx 1 mjb group 600 Apr 12 18:39 simpmenu.txt -rwxrwxrwa 1 mjb group 17 Jul 12 22:24 sleepy -rwxrwxrwx 1 mjb group 189 Jun 13 01:13 smallfry.txt $
Normally tee
creates the named file newly, but the -a
option
causes the new information to be appended to the file. For example the following command
would extend the dir.txt file that has just been created:
$ echo "Those are all the files"|tee -a dir.txt Those are all the files $ cat dir.txt total 141 -rwxrwxrwx 1 mjb group 16850 Apr 12 16:13 SMALL01.DOC -rwxrwxrwx 1 mjb group 14881 Apr 12 20:51 SMALL02.DOC -rwxrwxrwx 1 mjb group 17758 Jun 13 01:29 Small03.doc -rwxrwxrwa 1 mjb group 12791 Jul 12 22:44 Small04.doc -rwxrwxrwx 1 mjb group 4232 Jun 12 00:03 Smallxx.doc drwxrwxrwx 1 mjb group 0 Jul 12 21:25 docs -rwxrwxrwx 1 mjb group 261 Jun 13 01:08 hello.cbl -rwxrwxrwx 1 mjb group 184 Jun 13 00:59 hello.txt -rwxrwxrwa 1 mjb group 343 Jul 12 21:32 mver -rwxrwxrwa 1 mjb group 83 Jul 12 19:52 sh_histo -rwxrwxrwx 1 mjb group 455 Apr 12 18:10 simpmenu -rwxrwxrwx 1 mjb group 600 Apr 12 18:39 simpmenu.txt -rwxrwxrwa 1 mjb group 17 Jul 12 22:24 sleepy -rwxrwxrwx 1 mjb group 189 Jun 13 01:13 smallfry.txt Those are all the files $
The tee
utility is very useful for logging messages
while still allowing them to display on the screen. Assuming that
job.sh
displays information on the screen while it's processing,
the following listing will copy everything that goes to the screen
to the file job.log. In this example the log file is set up with
date and time information and then the job is run appending the
information to the log file.
$ echo "Starting job.sh"|tee job.log $ date|tee -a job.log $ job.sh|tee -a job.log Processing Check File Check Entries Valid - No Errors Printing Checks End Of Job $ cat job.log Starting job.sh Mon Jul 13 13:36:22 PDT 1998 Processing Check File Check Entries Valid - No Errors Printing Checks End Of Job $
The tee
utility can cut down on a lot of double logging, where one message is
sent to the screen and another or the same message is also captured in a log file.
|
Resources
About the author
Mo Budlong, president of King Computer Services Inc., specializes in
Unix and client/server consulting and training and currently
publishes the COBOL Just In Time Course, a crash course for
the Year 2000 problem as well as COBOL Dates and the Year
2000, which offers date solutions.
Reach Mo at mo.budlong@sunworld.com.
If you have technical problems with this magazine, contact webmaster@sunworld.com
URL: http://www.sunworld.com/swol-08-1998/swol-08-unix101.html
Last modified: