dcsimg

Ands and Ifs

In the past few months, this column has explored the intricacies of Linux's bash shell. Since we're on a roll, we're going to continue this month by looking at the shell's logical operators and conditional statements -- the ands and ifs. Along the way, we'll use conditional statements to construct a simple archive command that can help you use every available byte of disk storage space.

In the past few months, this column has explored the intricacies of Linux’s bash shell. Since we’re on a roll, we’re going to continue this month by looking at the shell’s logical operators and conditional statements — the ands and ifs. Along the way, we’ll use conditional statements to construct a simple archive command that can help you use every available byte of disk storage space.

Getting the Size of a File

If you’re a PC veteran, you may recall the days of the 5 MB hard drive. By today’s standards, these drives were pricey, pokey, and puny. Today, even 80 GB drives are common. However, even your 80 GB drives are probably packed to the gills.

One way to better use your available disk space is to compress many of your large text files. The gzip utility is ideally suited to this task. The problem is merely one of identifying the proper files to compress.

Since there’s little to be gained by compressing a small file, candidates for compression should be large files. And, since uncompressing a file involves a small inconvenience, it’s best to compress only files that aren’t in regular use. We could use the find command, which was explained in the April 2001 column (check it out online at http://www.linux-mag.com/2001-04/newbies_01.html). However, let’s see if we can do the job the hard way, learning something and gaining some flexibility along the way.

First, let’s create a command that displays the size of the file specified as the command’s argument. Here’s a suitable command, which we’ll call filesize:


du -k $1 | cut -f 1

The du displays the size of the file whose name is specified as its argument. The -k argument causes the size to be given in kilobytes. The $1 argument is replaced by the first argument of the filesize command; that is, if you execute the command:


filesize /var/log/messages

The command actually executed is:


du-k/var/log/messages| cut-f 1

The | operator (the pipe redirection operator) sends the output of the du command to the cut command. The cut-f1 command displays only the first word of each line of its input, deleting any other words. So, when the du command produces the output:


243 /var/log/messages

the cut command displays only the file size, 243 KB.

The if Statement

Now that we’re able to obtain the size of a file, we’re ready to compress only large files. To do so, we’ll need to execute the gzip command conditionally; that is, only for large files. The Linux shell includes two statements that could serve our purpose — if and case (which we’ll look at next month). Let’s take a look at the if statement, which has the general form:


if command

then

commands

fi

If you’ve programmed in any language from Algol to Zeta, you’ll likely recognize how the if statement works without explanation. If not, don’t fret; the if is a simple beast.

Here’s how it works. First, the if statement executes the command that follows the keyword if. Like every Linux command, that command will return a numeric value called the exit status. The exit status is available in the shell variable $?. What matters is the value of the exit status. If the exit status is 0, the result is deemed true; otherwise, it’s deemed false. The value 0 (true) is generally associated with successful completion of a command; other values generally indicate the nature of the error that occurred. In any case, if the exit status has the value 0 (true), the if statement executes the commands following the keyword then; otherwise, it doesn’t.

One trick to bear in mind: the layout of the if statement is important. The keywords if, then, and fi are recognized only when they appear at the beginning of a line. So, when writing an if statement, you should follow the form given.

As an example, suppose you issue the following command:


if rm badfile

then

echo It worked.

fi

The command will first attempt to delete the file named badfile and will set the exit status based on the result. If the deletion was successful, the echo statement will be executed; otherwise, it will not.

Testing, One, Two, Three

We can use the if statement to help us identify the files that have abs of flab rather than abs of steel. But, to do so, we’ll need the help of the test command, which we’ll use to set the exit status. As it happens, that’s the sole purpose of the test command, which is almost always used in combination with the if or if-else statements.

The test command has the general form:


test expression

where expression controls the operation of the test command, identifying the sort of test to be performed. The test sets the exit status based on the result of the test. The test command is used so often that the Linux shell supports a special way of issuing it. The construct:


[ expression ]

is equivalent to:


test expression




Table One: Expressions Used with the test Command




































ArgumentsMeaning
\( expression \) expression is true
! expressionexpression is false
expression1 -a expression2both expression1 and expression2 are true
expression1 -o expression2either expression1 or expression2 is true
file1 -ef file2file1 and file2 have the same device and i-node numbers
file1 -nt file2the modification time of file1 is later than that of file2
file1 -ot file2file1 is older than file2
integer1 -eq integer2integer1 is equal to integer2
integer1 -ge integer2integer1 is greater than or equal to integer2
integer1 -gt integer2integer1 is greater than integer2
integer1 -le integer2integer1 is less than or equal to integer2
integer1 -lt integer2integer1 is less than integer2
integer1 -ne integer2integer1 is not equal to integer2
[-n] stringthe length of string is non-zero
string1 != string2the strings are not equal
string1 = string2the strings are equal
-b filefile exists and is block special
-c filefile exists and is character special
-d filefile exists and is a directory
-e filefile exists
-f filefile exists and is a regular file
-g filefile exists and is set-group-ID
-G filefile exists and is owned by the effective group ID
-k filefile exists and has its sticky bit set
-L filefile exists and is a symbolic link
-O filefile exists and is owned by the effective user ID
-p filefile exists and is a named pipe
-r filefile exists and is readable
-s filefile exists and has a size greater than zero
-S filefile exists and is a socket
-t [ fd ] the specified file descriptor fd ( stdout by default) is opened on a terminal
-u filefile exists and its set-user-ID bit is set
-w filefile exists and is writable
-x filefile exists and is executable
-z stringthe length of string is zero


The test command supports a variety of tests, as shown in Table One. An option in forming test expressions lets you substitute -l string in place of any integer test expression. This special expression returns the length of the specified string. As an example, here’s a typical use of the test command:


if [ -e Badfile ]

then

echo Badfile exists.

else

echo Badfile does not exist.

fi

This command will display the text Badfile exists if the file named Badfile exists and the text Badfile does not exist otherwise.

Files with Abs of Flab

Okay, let’s now use the if and test commands together to check out our flabby files. Recall that backquotes cause the shell to execute the enclosed command and substitute the result of command execute for the quoted string. Therefore, the value of the shell expression:


`du -k $1 | cut -f 1`

will be the size, in kilobytes, of the file whose name is given by the shell argument, $1.

Let’s use this expression in combination with the test command:


if test `du -k $1 | cut -f 1` -ge 1000

then

echo The file $1 has abs of flab.

fi

Place this script in a file named myarchive and give yourself execute access by issuing the command:


chmod u+x myarchive

Test the script by using it to weigh in a file; for example, you can use the following:


myarchive thefile

If the file named thefile has a size of at least 1000 KB, the script should report that the file has “abs of flab.”

Sedentary Files

As explained, we’re interested in flabby text files, not merely flabby files. So we need to further qualify candidates for compression. The file command can help us here. If you were to issue:


file candidate

file would report the name of the candidate file, followed by a colon and space, and the type of the file. If the candidate file is a text file, the file will report the type “ASCII text.”

The following is a shell expression that reports the type of the file which has a name contained in the shell variable $1:


`file $1 | cut -f 2 -d ‘ ‘`

The cut command used in the above example is somewhat more involved than those previously used. The additional arguments tell the command to use space as a delimiter. This is necessary because file separates its output using spaces, whereas du separates its output using a TAB character, which is also the default delimiter employed by cut.

Here’s how to write an if statement that tests the type of a file:


if test `file $1 | cut -f 2 -d ‘ ‘` = ASCII

then

echo File $1 is an ASCII file.

fi

Place this script in a file named myarchive2 and give yourself execute access to the file by issuing the following command:

chmod u+x myarchive2

Test the script by using it to weigh in a file; for example:


myarchive2 thefile

If the file named thefile is a text file, the script should report that the file “is an ASCII file.”

Integration: The Ifs and the Ands

We can now write an if statement that tests whether a file is flabby, and we can write an if statement that tests whether a file is a text file. All that remains is to write an if statement that will test both conditions.

To do so, we can use the test command’s -a expression, which denotes the conjunction AND. The -a expression joins two subexpressions, both of which must be true for the expression as a whole to be considered true. An example of this conjunction is shown in Listing One.

Notice the script uses a backslash to continue the first line, which would otherwise be too long to be conveniently read and understood. Place this script in a file named myarchive3 and give yourself execute access to the file by issuing the command:


chmod u+x myarchive3

Notice that the revised script doesn’t merely report the characteristics of the file whose name is specified as an argument. It runs the gzip command to compress the file. This command replaces the file with a new, compressed file having as the first part of its name the name of the original file and the file extension .gz. To uncompress a file compressed using gzip, issue the following command:


gunzip file.gz

where file.gz is the name of the compressed file.

Test the myarchive3 script by using it to weigh in a file; for example:


myarchive3 thefile

If the file named thefile is a big text file, the script should report that the file “is a flabby text file” and compress it. Don’t attempt to use this script to compress files that are used by programs (such as configuration files). If you accidentally compress a file that really should not be compressed, simply use the gunzip command to uncompress the file.

On the Case

You’ve now seen the ifs and the ands. But, as the saying goes, that’s not all. Next month’s column will cover the case statement, a still more powerful cousin of the if statement.

Stay tuned…




Listing One: Joining if Statements with -a


if test `du -k $1 | cut -f 1` -ge 1000 \

-a `file $1 | cut -f 2 -d ‘ ‘` = ASCII

then

echo File $1 is a flabby text file.

gzip $1

fi



Bill McCarty is an associate professor at Azusa Pacific University. He can be reached at bmccarty@apu.edu.

Comments are closed.