\
~) and open the file with vi ?
- Sure I do. Show me the money and tell me how you did it.
exit 0?
- Ahhh! I found the number after exit will be the program's return code (the $?, remember?), and, as everything succeded ok, it would finish with $? = 0. But, if you notice, you'll see, in case of the file name doesn't be sent or the user didn't have the write privileges in this file, the return code would be different of zero.
- Good boy, you learned cool, but is better to clarify exit 0, only exit or even don't put exit, make the same return code ($?) as zero. Now let me talk about loop instructions. But, first things first, I'll thell you about program block concept.
'Till now, we saw some program blocks. When we saw an example about a cd inside a directory like this:
cd lmb 2> /dev/null ||
{
mkdir lmb
cd lmb
}
the code inside two keys ({}) makes a command block. Also in our last exercise, in which we saved a file before edit it, there are various command blocks inside the then and fi from if.
A command block can be inside a case, or between a do and e done.
- Hold on Julio, what are these do and done that I don't remember you had tell me about ? And look, I'm really paying attention !
- Yeah, you're right. I didn't tell it because the right time wasn't arrived. All loop instructions execute the block command found between do e o done.
for, while and until, that I'll start to explain one by one from now.
for command. But, what you don't know is the for, a built-in Shell instruction (that means the command's source code is part of Shell's source code ), is many times more powerfull than its other languages correlated command.
Lets understand its syntax, first in plain english, and then the real deal.
for var in val1 val2 ... valn
do
cmd1
cmd2
cmdn
done
The variable var assumes any values from the list val1 val2 ... valn and for each one of these values, the command block made by cmd1, cmd2 e cmdn is executed.
Now we saw what that means, lets see the correct syntax:
for var in val1 val2 ... valn
do
cmd1
cmd2
cmdn
done
That is amazing ! There is no changes between the real life, our real language, and the for command syntax. Very easy to learn, then. Lets right to the samples, to correctly understand how the command works. Lets make a script to list all files in our directory separeted by colons, but first, see:
*) and expanded it whit the name os all files in the directory and the echo command sent them to screen separated by spaces. That understood, lets see how can we solve the proposed problem:
for saw that list, he said: "Yeah, space-separated lists... that's my groovy, baby !"
The command block to be executed was only the echo, with its -n option, listed the variable $Arq followed by colons (:), without a new-line character. The dolar ($) at the end of execution line is the prompt. that remained at the same line also because of the -n echo's option.
Another simple example (by now):
for's basic behavior.
See the power of the for: we're still in the its first syntax and I'm showing new ways to use it. Back in our chat, I told for used space-separated lista, but this is not the whole truth. It was only to make understanding easy.
For real, the lists are not separated by spaces unconditionally but, before go ahead, let me show you how is the behavior of a system variable called $IFS. Take a look at its value:
od -h) and I have:
| $IFS Variables Value | |
|---|---|
0a |
<ENTER> |
| Hexa | Means |
09 |
<TAB> |
20 |
<ESPACE> |
0a came from the final <ENTER> at the command. To maximize the explanation, lets see the other way:
At the cat command, option -e represents the <ENTER> whit a dolar ($) and the option -t represents the <TAB> as a ^I. I used colons (:) to show echo='s start and ending. This way, once again we can see that the variable =$IFS has three characters.
IFS means Inter Field Separator. Knowing this, I can prove that for command doesn't use space-separated lists, but lists separated by the $IFS value, which default are these characters we saw. To prove this, lets show a script that receives the singer name as parameter and shows the musics he plays, but first lets see how our musics file looks like:
IFS was setted to <ENTER> and colon (:) (as we can see in the quotes in different lines), because it is the responsible to separate the blocks Artistan~Musicam. In this way, the variable $ArtMus will receive each one of these blocks in the file ( notice that for receives the records without the album because of cut in its line). If it found the first parameter ($1) at the block, the second o segundo cut will list only the music name. Lets run it:
Musica10 = were listed too. Besides, our music file is quite simple. In the real life, the music and the artist have more than one name. Supose the artist was a couple named Paris & Britney (I really don't like neither to think about it... I'm affraid it can be true one day...LOL). In this case the =$1 was Paris and the rest of this beautifull name would be ignored in the search.
To avoid this, I should pass the artist name between quotes (") or change $1 by $@ (that means all passed parameters), that is the best solution but, in this case, I should change parameters checking and grep. The new check shoud be if I passed at least one parameter, instead of if I passed a parameter. The grep, this is what we get after the substituton of $* for its parameters:
echo "$ArtMus" | grep Paris & Britney
what would generate an error. The right way is:
echo "$ArtMus" | grep -i "Paris & Britney"
We put the -i option to ignore the case and the quotes was inserted to the artist name be recognized as a one array of chars.
We still need to fix the list of Artista10 error. To do this, the best way is tell to grep that the array of chars is at begining of $ArtMus (the regular expression to do this is ^) followed by a tilde (~). We need to redirect the grep messages to /dev/null to avoid block listing. So lets see the final program:
for var
do
cmd1
cmd2
cmdn
done
- What ? Whitout the in how he knows what value assumes ?
- Yeah, right ? This construction seems strange but it is quite simple. In this case, var will assume one by one each passed parameters.
Lets make some samples to better understanding. We'll do a script to receive a bunch of musics as parameters and list its authors:
for in which the variable $Musica will receive each one of the passed parameters, putting in $Str all albuns that contain the musics. Then, the other for search for eah block Artista~Musica in the records we have in $Str and lists each artist that plays that music.
Lets run to see if it works:
for that counts from a number with an addition until reachs a condition ?"
I will answer you: "I told you, homeboy, our for is much more coolio that the others ?" There is two ways:
1 - With our first syntax, as the following examples, run straigh at the prompt:
i assumed the integers 1 to 9 generated by the seq command and the echo's -n option was used to avoid line break after each number.
Still using for with seq:
seq form:
for ((var=ini; cond; incr))
do
cmd1
cmd2
cmdn
done
Onde:
var=ini - means the variable var starts with an initial value ini
cond - Means that the for loop will be executed while var doesn't reach the condition cond
incr - Means the addition variable var will have in each loop iteration.
Examples, examples, examples, to clarify the things:
i started from 1; the command block (the echo) will be executed while the variable i is less or equal than (<=) 9 and the i increment will be 1 in each loop iteration.
Notice that at the for command I didn't put a dolar ($) before i, and the increment notation (i++) is different from what we came seeing until now. This is possible because the double parentesis (or the let command) calls the shell arithmetic interpreter, that is more tolerant.
And, as I told about the let command, just to illustrate how it works and how versatile the for command can be, lets do the same, but with the last for part ommited, sending it to the command block.
for body and sent to command block. When I used the let, I even need to initialize the $i variable. See the following commands, in the prompt:
$j even exist and at the first let it assumed the zero value to, after the increment, get the value 1.
See how simple the things can be:
for command. That's enought for today. In the next time we talk about another loop instructions. I wish you to do a little script to count the words in a text file, passing its name as parameter. This counting must be done using for command to know it. You can't use wc -w.
- Hey Chico! Bring me the last one.
(CC) 2009 Pelos Frequentadores do Bar do Júlio Neves.