Linux Shell Programming

Here we have a free and complete book about Shell

The thirst of the "free knowledge" is welcome.

Comandos Shell Script

Syntactic Diagram
Júlio Neves
Júlio Neves
Home | Articles Português Español

Buy the book

Changelogs

  Pub Talk 1  

  Pub Talk 2  

  Pub Talk 3  

  Pub Talk 4  

  Pub Talk 5  

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
Pinguim com placa de atenção (em inglês) 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
Pinguim com placa de dica (em inglês) 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

Creative Commons license - Attribution and Non-Commercial (CC) 2009 By Visitors of Júlio Neves´s Pub.
All content of this page may be used under the terms of the Creative Commons License: Atribuição-UsoNãoComercial-PermanênciaDaLicença.