\

Aqui temos um livro livre e completo sobre Shell

Os sedentos do "saber livre" são muito benvindos.

Você está aqui: TWikiBar > TWikiBarTalk011
Controles: EDITAR ANEXAR MAIS MAIS ALTERACOES IMPRIMIR - Última Atualização: [24 Apr 2014 - V.7]

Pub Talk Part XI



This is a very new translation from Portuguese to English. Please contribute to the development of this site indicating errors and and/or suggesting corrections and materials for this person.

     - Hey man, how are you?

     - All right, but remember that you asked me to make a program that when the size of a screen varied in its center dynamically appear in reverse video, the amount of rows and columns the way that Linux normally do? Yeah I did but the appearance wasn't equal.

     - I do not care for the look, what I wanted is that you exercise what we have learned. Let me see what you did.

$ cat tamtela.sh #!/bin/bash # # Puts the center of the screen in reverse video, # the amount of columns and rows # when the screen size changes. # trap Change 28 # 28 = signal generated by the change in size # of the screen and Change is the function that will make it.

Bold=$(tput bold) # Mode of emphasis Rev=$(tput rev) # Mode of reverse video Norm=$(tput sgr0) # Restores the default screen

Change () { clear Cols=$(tput cols) Lins=$(tput lines) tput cup $(($Lins / 2)) $(((Cols - 7) / 2)) # Center of the screen echo $Bold$Rev$Cols X $Lins$Norm }

clear read -n1 -p "Change the size of the screen or press something to finish "

     - Perfect! To hell the look, then I'll teach you a few tricks to improve it what matters is that the program is working well and is streamlined.

     - Gosh, I lost the most time trying to find how to increase font ...

     - Leave it there and today we will see some very interesting and useful things.

Named Pipes

Another type of pipe is named pipe, which is also called FIFO. FIFO is an acronym First In First Out it refers to the property in which the order of the bytes entering the pipe is the same as that of the output. The name in named pipe is, actually the name of a file. The type file named pipes are displayed by the command ls like any other, with a few differences, see:

$ ls -l pipe1 prw-r-r-- 1 julio dipao 0 Jan 22 23:11 pipe1|

The p the leftmost column indicates that fifo1 is named pipe. The rest of the bits of permissions control who can read or write to the pipe, work as a normal file. In most modern systems a vertical bar (|) in LINUX systems placed at the end of the file name, is another tip, and where the color option is enabled, the file name is written in red by default.

In older systems, the named pipes are created by the program mknod normally located in the directory /etc.

In modern systems, the same task is done by mkfifo. The mkfifo program receives one or more names as an argument and creates pipes with these names. For example, to create a named pipe to the name pipe1 do:

$ mkfifo pipe1

As always, the best way to show how something works is by giving examples. Suppose we have created the named pipe shown above. We will now work with two sessions or two virtual consoles or one of each. In one of them do:

$ ls -l > pipe1

and other make:

$ cat < pipe1

Voila! The output of the command executed on the first console was displayed on the second. Note that the order in which the commands were not matter.

If you paid attention, noticed that the first command executed, seemed to have "hung, frozen." This happens because the other end of the pipe was still not connected, then the operating system suspended the first process until the second "open" the pipe. For a process that uses pipe not stay in wait mode, it is necessary that at one end of the pipe have a "talkative" process and in the other a "listener" and the example we gave, the ls was "talkative" and the cat was the "phone booth".

A very useful application of named pipes is allow programs unrelated to communicate with each other, the named pipes are also used to synchronize processes, since at a certain point you can put a process to "listen" or to "speak" in a given named pipe and then it will only come out if another process "talk" or "listen" that pipe.

You have seen that the use of this tool is great for synchronize processes and to lock files in order to avoid loss/corruption of information due to concurrent updates (competition). A few examples to illustrate these cases.

Synchronization processes

Suppose you shoot parallel two (processes) programs whose block diagrams of their routines are like the following figure:

Graph of Named Pipe

The two processes are triggered in parallel and in BLOCK1 of Program1 the three classifications are triggered as follows:

    for Arq in BigFile1 BigFile2 BigFile3
    do
        if  sort $Arq 
        then
            Send=go
        else
            Send=stop
            break
        fi
    done
    echo $Send > pipe1
    [ $Send = stop ] &&
        {
        echo Error while sorting files
        exit 1
        }
    ...

Thus, the if command tests each classification being performed. Case a problem occurs, the following classifications will be aborted, a message containing the chain stop is sent by pipe1 and program1 is dropped with an abnormal end.

While the Program1 ran their first block (the classifications) the Program2 executed his BLOCK1, processing routine of opening and parallel menu to Program1, thereby gaining a good time interval.

The fragment of code Program2 below, shows the transition of its BLOCK1 to BLOCK2:

    OK=`cat pipe1`
    if  [ $OK = va ]
    then
        ...
        Print routine
        ...
    else    #  Received "stop" in OK
        exit 1
    fi

After running his first block, the Program2 will "listen" the pipe1, still standing until the classifications of Program1 finish testing the following message passed by pipe1 to decide if the files are righteous to be printed, or if the program should be discontinued. Thus it is possible to trigger asynchronously programs and sync them when needed, gaining enough processing time.

Lock of files

Suppose you wrote a CGI (Common Gateway Interface) in Shell to count how many hits receives a certain URL and counting routine is as follows:

    Hits="$(cat page.hits 2> /dev/null)" || Hits=0
    echo $((Hits++)) > page.hits

This way if the page receives two or more concurrent accesses, one or more may (will) be lost, just that the second access is done after reading the file page.hits and before recording, ie it is sufficient that the second access be done after first having performed the first line of script and before the second run.

So what to do? To solve the competition problem we will use a named pipe. We created the following script will be the daemon will receive all requests to increment the counter. Note that it will be used by any page on our site that you need an accountant.

$ cat counthits.sh #!/bin/bash

PIPE="/tmp/pipe_counter" # file named pipe # dir where counters files of each page will be placed DIR="/var/www/counter"

[ -p "$PIPE" ] || mkfifo "$PIPE"

while : do for URL in $(cat < $PIPE) do FILE="$DIR/$(echo $URL | sed 's,.*/,,')" # NOTE1: in the sed above, as needed to look # A bar, use comma as separator. # NOTE2: when running as a daemon comment the next line echo "file = $FILE"

n="$(cat $FILE 2> /dev/null)" || n=0 echo $((n=n+1)) > "$FILE" done done

As only this script change the files, there is no competition problem.

This script is a daemon, that is, will run in the background. When a page access experience, she will write your URL in the pipe file. To test, run this command:

    echo "test_page.html" > /tmp/pipe_counter 

To avoid errors in each page that we want to add the counter, add the following line:

    <!--#exec cmd="echo $REQUEST_URI > /tmp/pipe_counter"-->

Note that the variable $REQUEST_URI contains the filename that the browser requested.

This last example is the result of an idea that I traded with friend and master Shell, Thobias Salazar Trevisan who wrote the script and put it in his excellent URL. I advise all who want to learn Shell to give a look at it (Take a look and add it to your favorites).

Ahhh! You think about it named pipes is exhausted? Was mistaken. I'll show a different use from now on.

Process substitution

I just showed a lot of tips named pipes, now I will show that Shell also uses named pipes a rather unique way, which is the substitution process. A substitution process occurs when you put a command or pipeline of commands between parentheses and a < or a > stuck in front of the left parenthesis. For example, typing the command:

$ cat <(ls -l)

Will result in the command ls -l run in a subshell as is normal (by being in parentheses), but will redirect the output to a named pipe temporary, that the Shell creates, nominates and removes later. So the cat will have a valid file name to read (which will be this named pipe and whose associated logical device is /dev/fd/63), and we will have the same output as that generated by the listing of ls -l, but giving one or more steps than usual, that is more burdensome to the computer.

How can we note it? Easy ... See the following command:

$ ls -l >(cat) l-wx------ 1 jneves jneves 64 Aug 27 12:26 /dev/fd/63 -> pipe:[7050]

It is... It really is a named pipe.

You must be thinking that this is a madness of nerd, right? So suppose you have two directories: dir and dir.bkp and want to know if the two are equal (that old doubt: will my backup is up to date?). Just compare the data with files from directories with cmp command, doing:

$ cmp <(cat dir/*) <(cat dir.bkp/*) || echo bored backup

or better yet:

$ cmp <(cat dir/*) <(cat dir.bkp/*) >/dev/null || echo bored backup

In the above form, the comparison was performed on all lines of all files in both directories. To accelerate the process, we could only compare the long listing of both directories, because any modification that suffers a file is shown in the date/time of change and/or file size. See how it would look:

$ cmp <(ls -l dir) <(ls -l dir.bkp) >/dev/null || echo bored backup

This is merely a didactical example, but there are so many commands that produce more than one output row, which serves as a guide for others. I want to generate a listing of my files, numbering them and in the end give the total number of files of the current directory:

    while read arq
    do
        ((i++)) # so it is not necessary to initialize i
        echo "$i: $arq"
    done < <(ls)
    echo "In the current directory (`pwd`) there is $i files"

Alright, I know there are other ways to perform the same task. Using the command while, the most common way to solve this problem would be:

    ls | while read arq
    do
        ((i++)) # so it is not necessary to initialize i
        echo "$i: $arq"
    done
    echo "In the current directory (`pwd`) there is $i files"

When you executed the script, would seem to be all right, but the command echo after the done you will see that the value of $i was lost. This is due to the fact that variable being incremented in a subshell created by the pipe (|) and ending in command done, taking with him all the variables created inside it and changes in all variables, including those created externally.

Just to show you that a variable created outside of subshell and changed in inside loses changes made to its end, run the following script:

    #!/bin/bash
    LIST=""                  # Created in the main shell
    ls | while read FILE     # Start of subshell
    do
        LIST="$FILE $LIST"   # Changed within the subshell
    done                     # End the subshell
    echo :$LIST:

At the end of the run you will see that only appear two colons (::). But earlier this example I said it was merely didactic because there are better ways of doing the same task. Look at these two:

$ ls | cat -n -

or, using the proper substitution processes:

$ cat -n <(ls)

One last example: you want to compare arq1 and arq2 using the comm command, but this command requires that the files are sorted. So the best way to proceed is:

$ comm <(sort arq1) <(sort arq2)

This form saves you perform the following operations:

$ sort arq1 > /tmp/sort1 $ sort arq2 > /tmp/sort2 $ comm /tmp/sort1 /tmp/sort2 $ rm -f /tmp/sort1 /tmp/sort2

Guys, our Pub Talk came to an end frown . I enjoyed myself here and I received many accolades for the work done over twelve months and, best of all, I made ​​many friends and drank many beers of free with the readers who I found by congresses and lectures I've been doing for our beloved Brazil.

What I will write here is not combined do not even know if it will be published, but as the editors of this journal are two crazy beauty (both Rafael), is well able to let go. It is this: if you want to keep the Pub Talk, fill the mailbox of Linux Magazine asking for it and already choose the next theme among sed + regular expressions or awk language.

Anyway, if we can not sensitize the direction of the magazine, I say farewell to everyone sending a big hug to the bearded and kisses the girls and thanking the more than 100 e-mails I received (all complimentary) and all duly answered.

A toast to the health of us all!

- Waiter, close my account because I'm changing pub.

Any doubt or lack of companionship for a beer or even to speak ill of politicians just send an email to of me.

Thanks!


Licença Creative Commons - Atribuição e Não Comercial (CC) 2017 Pelos Frequentadores do Bar do Júlio Neves.
Todo o conteúdo desta página pode ser utilizado segundo os termos da Creative Commons License: Atribuição-UsoNãoComercial-PermanênciaDaLicença.