Pub Talk Part IV
'My fellow!!! How have you been, mr. bin? Have you done the exercise I asked you to?'
'I surely did! When programming is the topic, if you don't practice, you don't learn. You've asked me a simple script that tells whether a user is logged in or not. I have made the following script:'
$ cat logado
#!/bin/bash
# searches whether a user is logged in or not
if who | grep $1
then
echo $1 is logged
else
echo $1 can't be seen anywhere around
fi
'Easy boy!! You look quite excited, but let's just ask for some beer first. John, two beers, please! And please, pour mine with no foam...'
'OK! Now that we've had our drinks, let's take a look:'
$ logado jneves
jneves pts/0 Oct 18 12:02 (10.2.4.144)
jneves is logged
'Well, it really works! I used my login as parameter and it told me I was logged in. Nevertheless, it told me something I didn't want to: a line of the who command. In order to avoid it, it's just necessary to send that line to the black hole called /dev/null. Check it out:'
$ cat logado
#!/bin/bash
# searches whether a user is logged in or not (version 2)
if who | grep $1 > /dev/null
then
echo $1 is logged
else
echo $1 can't be seen anywhere around
fi
'Now, let's test:'
$ logado jneves
jneves is logged
$ logado chico
chico can't be seen anywhere around

Remember the trick: most of the commands have a standard output and an error output (
grep is one of the few exceptions because it shows no error message when it doesn't find a string) and we should pay attention when it is necessary to send them to the black hole.
'But let's change the subject. The last time we met, I was showing you some conditional commands and, when I was thirsty as hell, you asked me how one can test conditions. Let's see the test command, then.'
The test Command
'Well, we are all acquainted to the use of
if testing conditions (which are always
greater than,
less then,
greater or equal,
less or equal,
equal and
not equal). When using Shell to test conditions, we can use the
test command, but it is a lot more powerful than we can imagine. Let me first show you the main options to test files in a disc:'
| Options of the test command to files |
-x file |
file does exist with execution grant |
| Option |
True if: |
-e file |
file does exist |
-s file |
file does exist and is bigger than zero |
-f file |
file does exist and is a regular file |
-d file |
file does exist and is a directory |
-r file |
file does exist with reading grant |
-w file |
file does exist with writing grant |
'Now, the main testing options for character chains:'
| Options of the test command for character strings |
c1 = c2 |
strings c1 & c2 are identical |
| Option |
True if: |
-e string |
string size is zero |
-n string |
string size is bigger than zero |
string |
the string string is bigger than zero |
'Thinking it's over? So sorry!!! Now the part you are not acquainted to, comparisons with numbers. Check out the table below:'
| Options of the test command for numbers |
n1 -le n2 |
n1 is less or equals than n2 |
| Option |
True if |
n1 -eq n2 |
n1 equals n2 |
n1 -ne n2 |
n1 and n2 are different |
n1 -gt n2 |
n1 is greater than n2 |
n1 -ge n2 |
n1 is greater or equals than n2 |
n1 -lt n1 |
n1 is less than n2 |
'Furthermore, consider the following operators'
| Operators |
-o |
logical OR |
| Operator |
Purpose |
Parenthesis ( ) |
Grouping |
Exclamation ! |
Denying |
-a |
logical AND |
'Wow! As you've seen, there is a lot of stuff here, and as I told you, our
if is much more powerful than others's. Let's see some examples of how it works, first, testing the existence of a directory:'
Example:
if test -d lmb
then
cd lmb
else
mkdir lmb
cd lmb
fi
'That example tests if there is a
lmb directory, or else, it creates such directory. I know you will probably question this logic saying the script is not optimized. I know, but I wanted you to understand it the way it is, so that we can use an exclamation point
(!) to deny the test command. Check it:'
if test ! -d lmb
then
mkdir lmb
fi
cd lmb
'This way, the
lmb directory would be created if (and only if) it did not exist. This denial comes from the exclamation point
(!) that preceeds the option
-d. At the end of the execution of this piece of script, you would certainly be in the
lmb directory.
Let's see other two examples to check the difference between numbers and chains.'
str1=1
str2=01
if test $str1 = $str2
then
echo The variables are equal.
else
echo The variables are not equal.
fi
'Running the piece of software above, the answer would be:'
The variables are not equal.
'Now, let's change it in order to have a numerical comparison:'
str1=1
str2=01
if test $str1 -eq $str2
then
echo The variables are equal.
else
echo The variables are not equal.
fi
'And let's run it again:'
The variables are equal.
'As you have seen above, we've had two different results because the string
01 is quite different from the chain string
1, though they are the same when considered numerically, since the number
1 is equivalent to the number
01.'
Examples:
'In order to show the use of conectors
-o (
OR) and
-a (
AND), check this example made at the prompt:'
$ Familia=felinae
$ Genero=cat
$ if test $Familia = canidea -a $Genero = lobo -o $Familia = felino -a $Genero = lion
> then
> echo Be aware
> else
> echo Can wave it
> fi
Can wave it

The angle brackets
(>) in the begining of the internal lines of the
if, are the continuation prompts (that are defined as
$PS2) and when our friend Shell identifies that a command will have a continuation in the following line, it automatically places it until the end of the command.
'Let's change the example to check if it still works:'
$ Familia=felino
$ Genero=cat
$ if test $Familia = felino -o $Familia = canideo -a $Genero = lion -o $Genero = lobo
> then
> echo be aware
> else
> echo Can wave it
> fi
Be aware
'The operation has, obviously, generated an error. That has happened because the option
-a preceeds the option
-o. This way, what was firstly evaluated was the expression:'
$Familia = canideo -a $Genero = lion
'That expression was evaluated as false, so that the answer was:'
$Familia = felino -o FALSE -o $Genero = lobo
'Solved, it would be:'
TRUE -o FALSE -o FALSE
'Since all the conectors are
-o, the final expression has resulted as
TRUE (considering that, when in a series of logical expressions connected by logic
OR, only one of those expressions must be true to the result become true) and the
then was wrongly executed. To make it work properly (again), let's try the following procedure:'
$ if test \($Familia = felino -o $Familia = canideo\) -a \($Genero = lion -o $Genero = lobo\)
> then
> echo Be aware
> else
> echo Can wave it
> fi
Can wave it
'This way, using the parentheses, the expressions are grouped with the connector
-o, which priorizes the execution and results in:'
TRUE -a FALSE
'The result of expressions connected by the operator
-a is true when all the expressions that it connects are true (which is not the case above). This way, the result was
FALSE and the
else was correctly executed.'
'If we decide to read a CD with songs of different singers, we could be temptated to use an if with a connector
-a, but it is better to bare in mind that bash provides us many resources, and it could be done more easily with a single
grep command, as in the following example:'
$ grep Musician1 musics | grep Musician2
'Similarly, if we pick a CD with songs of an
Musician1 and of an
Musician2, it is not necessary to use an
if with the connector
-o. The
egrep (or
grep -E, which is more proper for that situation) can also solve this problem. Check it out:'
$ egrep (Musician1|Musician2) musics
'Or (specifically for that case)
grep itself could help us out:'
$ grep Musician[12] musics
'Above, a regular expression was used. The vertical bar
(|) works as a logical
OR and the parentheses are used to limit that
OR. On the next
grep, on the other hand, the word
Artista must be followed by one of the values of the list between square brackets (
[]), that means,
1 or
2.'
'OK! I accept it when you tell me that shell's if is much more powerful than other's. But let me tell you one thing: that syntax
if test... is quite creepy... han?'
'Yeah, I think you're right. I don't like it either... no one does, I guess. I think that's why Shell has another syntax to substitute the
test command.'
Examples
'In order to do so, we'll use that example to switch directories. It was like that:'
if test ! -d lmb
then
mkdir lmb
fi
cd lmb
'Using a new syntax, it will be:'
if [ ! -d lmb ]
then
mkdir lmb
fi
cd lmb
'That means that the
test command can be replaced by a pair of square brackets (
[]), separated by blank spaces between the arguments, which would considerably increase the legibility of the command, since if would present a syntax similar to the one of other languages and that is why the
test command will be used henceforth.'
Please help me to finish or to correct this translation (from Portuguese)
Send me a e-mail
julio.neves@gmail.com
--
JulioNeves - 30 Sep 2006