Difference: TWikiBarTalkSnacks (1 vs. 17)

Revision 1723 Dec 2017 - Main.PauloSantana

Line: 1 to 1
 
META TOPICPARENT name="WebHome"
Changed:
<
<
Dari hari ke hari tugas seorang web marketer adalah meningkatkan popularitas situsnya dengan cara memasang strategi content marketing yang tepat. Aksi yang dilakukan termasuk menyebarkannya lewat social media, registrasi milis, jual beli online, ataupun toko fisik di lokasi. Semua usaha yang dilakukan untuk merubah pengunjung website menjadi pelanggan.
>
>

Snacks

Shell in delicious small pieces


 
Changed:
<
<
tips Pertama yaitu melalui Search engine optimization (SEO) harus Anda mulai sejak sedini mungkin, hal ini karena seo adalah salah satu investasi jangka panjang. Anda tidak tahu sampai kapan perusahaan anda memiliki budget untuk menjalankan iklan berbayar atau google adwords. perencanaan seo bisa anda mulai sejak proses pembuatan website bisnis sehingga web usaha anda bisa dengan mudah di optimasi nantinya jika sudah seo frindly sedari awal. Bila perlu kerjasama dengan para pemilik layanan Pembuatan Website yang bisa anda percayai dan bagus dalam sisi teknikal dan optimasi dengan benar.
>
>
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.
 
Changed:
<
<
Tips kedua agar content marketing Anda sukses adalah menulis isi situs untuk pengunjung Anda, bukan untuk mesin pencari keywords. Saat ini banyak situs bermunculan berisi artikel yang apabila Anda baca penuh dengan berbagai keywords namun kalimatnya tidak berstruktur sehingga tidak mudah untuk dimengerti. Artikel tersebut adalah artikel yang dibuat agar mudah mendongkrak ranking di mesin pencari.
>
>

Under construction forever


This page, despite being in the scope of the Pub Talk, was never published in Linux Magazine. It is about articles I have written for other media, helpful tips that I read over the internet apart (and in this case with the appropriate credits), contributions of personal of Software Livre wonderful and always ready to help and the unmissable Shell Script List


 
Changed:
<
<
Pastikan untuk menyebarkan unggahan Anda ke social media, karena peranan social media telah terbukti membantu pembaca menemukan unggahan Anda. Untuk beberapa orang menyerap informasi lebih mudah dilakukan secara visual. Minta seorang desainer professional infographic untuk mengerjakan content Anda, Infographic merupakan salah satu alternatif terefektif untuk menyampaikan informasi daripada membuatkan satu artikel berisi teks penuh.
>
>

Passing parameters with xargs

 
Changed:
<
<
Setelah Anda melakukan cara-cara untuk menarik pengunjung, sangat penting untuk memiliki sistem yang dapat memonitor seberapa efektif usaha yang telah Anda lakukan. Apakah menyebarkan lewat social media lebih efektif daripada infographic, atau sebaliknya.
>
>
Has a command whose primary function is to build lists of parameters and pass it to execute other programs or instructions. This command is the xargs and should be used as follows:
 
Deleted:
<
<
Tips terakhir adalah menjaga konsistensi Anda untuk memberikan update pada pengunjung agar situs Anda tidak hanya untuk sekali kunjung. Seo berhubungan erat dengan konten, semakin unik dan buka copy paste maka kemungkinan landing page bisnis anda bisa mudah naik ke halaman pertama. tentunya link building juga dibutuhkan, tidak perlu secara masif, yang penting backlink target Anda baik, memiliki DA PA tinggi dan lebih baik lagi jika satu niche atau tema web yang sama. Selain seo, anda bisa kombinasikan dengan channel digital marketing lainnya seperti sosial media, email marketing, iklan berbayar atau ppc sosmed. Jasa SEO saat ini sangat banyak, jadi anda tidak perlu takut jika memang tidak memiliki skill digital marketing atau bisa hire tim yang handal di online marketing.
 \ No newline at end of file
Added:
>
>
    xargs [command [initial argument]]

The xargs combines the initial argument with the arguments received from standard input, in order to execute the specified command one or more times.

Example:

We will search in all files bellow a given directory a character chain using the find command with the -type f option to search only the normal files, ignoring directories, special files, links, etc., and we make it more generic receiving the name of the inittial directory and the chain to be searched as parameters. To do this:

$ cat grepr # # Grep recursive # Search the character chain defined in $2 from $1 directory # find $1 -type f -print|xargs grep -l "$2"

In executing this script we seek, from the directory defined in the $1 variable, all files that contained the chain defined in the $2 variable.

Exactly the same thing could be done if the line of the program were the following:

    find $1 -type f -exec grep -l "$2" {} \;

The first process has two big disadvantages over the previous:

  • The first is quite visible: the running time of this method is much higher than that, because grep will be made in each file which is passed by find, one-to-one, whereas with xargs, will be past all, or at worst, the most part possible, of the list of files generated by find;

  • Depending on the amount of files found that cater to find, we can win that famous and fateful error message Too many arguments indicating an overflow of the execution stack of the grep. As stated previously, if we use the xargs he will send to grep the highest amount of possible parameters, enough not to cause this error, and if necessary perform the grep more than once.

Pinguim com placa de atenção (em inglês) Hey guys Linux that uses the colorful ls as door dyeing: in the following examples involving this instruction, you should use the option --color=none, if not there are high chances of the results don't occur as expected.

We now consider an example that is more or less the reverse of this we have just seen. This time, let's make a script to remove all files in the current directory, belonging to a particular user.

The first idea that comes up is, as in the previous case, use a command find, as follows:

    find . -user guy -exec rm -f {} \;

Would be almost certain the problem is that this way you not only remove the files from the guy in the current directory, but also all other subdirectories "hanging" in this. Let us see how:

    ls -l | grep " guy " | cut -c55- | xargs rm

Thus, the grep selected files that containing the chain guy in current directory listed by ls -l. The command cut only caught the name of the file, passing them for removal by rm using the xargs command as a bridge.

The xargs is also an excellent tool for creating one-liners (scripts only one line). See more of this to list all owners of files (including their links) "hanging" in the directory /bin and its subdirectories.

$ find /bin -type f -follow | xargs ls -al | tr -s ' ' | cut -f3 -d' ' | sort -u

Often /bin is a link (if I'm not mistaken, Solaris is) and -follows option forces the find following the link. The xargs command feeds the ls -al and the following command sequence is to get only the 3rd field (owner) and sort it returning only once each owner (option -u of the sort command, which equivalent to the uniq command).

Xargs options

You can use xargs options to build extremely powerful commands.

-i option

To illustrate this and begin to understand the main options this Instruction suppose we have to remove all the files with extension .txt in the current directory and display their names on the screen. See what we can do:

$ find . -type f -name "*.txt" | xargs -i bash -c "echo removing {}; rm {}"

The i option of xargs change braces ({}) by the string is receiving by the pipe (|). So in this case the braces ({}) will be replaced by the names of the files they satisfy the find command.

-n option

Look the fun we going to do with xargs:

$ ls | xargs echo > arq.ls $ cat arq.ls arq.ls arq1 arq2 arq3 $ cat arq.ls | xargs -n1 arq.ls arq1 arq2 arq3

When we send the output of ls to the file using xargs, we prove what was said previously, i.e., xargs sends all that is possible (enough not generate a stack overflow) at one time. Then we use a -n 1 option to list one at a time. Just to make sure look at the example below, where we list two on each row:

$ cat arq.ls | xargs -n 2 arq.ls arq1 arq2 arq3

But the row above could (and should) be written without the use pipe (|), as follows:

$ xargs -n 2 < arq.ls

-p option

Another cool of xargs option is the -p, is used to the system ask if you really want to execute the command. Let us say that in a directory you have files with extension .bug and .ok, the .bug are with problems that after corrected will be saved as .ok. Gives a look at the list in this directory:

$ ls dir arq1.bug arq1.ok arq2.bug arq2.ok ... arq9.bug arq9.ok

To compare the good with the bad files, do:

$ ls | xargs -p -n2 diff -c diff -c arq1.bug arq1.ok ?...y .... diff -c arq9.bug arq9.ok ?...y

-t option

Finally, the xargs also have the -t option where will show the instructions that set up before running them. I really like this option to help debug command that was mounted.

Resume

So we can sum up the command according to the following table:

-t   Displays the command line mounted before executing it  
  Option     Action
-i   Replaces the key pair ({}) by chains received  
-nNum   Send the maximum parameters received, up to a maximum of Nun for the command to be executed  
-lNum   Send the maximum rows received, up to a maximum of Nun for the command to be executed  
-p   Displays the command line mounted and asks if you want to run it  

Here Strings

First a programmer with an inferiority complex created the input redirection and represented it with a less than sign (<) to represent their feelings. Then another feeling worse, created the here document representing it by two less than signs (<<) why his sorrow was higher. The third thought, "these two do not know what to feel down"... Then created the here strings represented by three less than signs (<<<).

Jokes aside, the here strings is very useful and do not know why, it is a perfect stranger. In literature there is very little on the subject, we note that the here strings is often cited as a variant of here document, theory with which I disagree because its applicability is quite different from that. Its syntax is simple:

    $ command <<< $chain

Where chain is expanded and feeds the primary input (stdin) of command.

As always, we go straight to the examples of two most common uses for you to draw your own conclusions.

  • Use #1. Replacing the notorious construction echo "chain" | command, which forces a fork, creating a subshell and burdening the runtime.

Examples:

$ a="1 2 3" $ cut -f 2 -d ' ' <<< $a # Normally is done: echo $a | cut -f 2 -d ' ' 2 $ echo $NameArq My Documents # Arrrghhh! $ tr "A-Z " "a-z_" <<< $NomeArq # Replacing the echo $NomeArq | tr "A-Z " "a-z_" my_documents $ bc <<<"3 * 2" 6 $ bc <<<"scale = 4; 22 / 7" 3.1428

To show the improvement in performance, we will make a loop 500 times using the example given for the tr command: See now this sequence of commands with time measures:

$ time for ((i=1; i<= 500; i++)); { tr "A-Z " "a-z_" <<< $NameArq >/dev/null; } real 0m3.508s user 0m2.400s sys 0m1.012s $ time for ((i=1; i<= 500; i++)); { echo $NameArq | tr "A-Z " "a-z_" >/dev/null; } real 0m4.144s user 0m2.684s sys 0m1.392s

See now this sequence of commands with time measures:

$ time for ((i=1;i<=100;i++)); { who | cat > /dev/null; } real 0m1.435s user 0m1.000s sys 0m0.380s $ time for ((i=1;i<=100;i++)); { cat <(who) > /dev/null; } real 0m1.552s user 0m1.052s sys 0m0.448s $ time for ((i=1;i<=100;i++)); { cat <<< $(who) > /dev/null; } real 0m1.514s user 0m1.056s sys 0m0.412s

Observing this box you will see that in the first we used the conventional way, in the second we use a temporary named pipe to run a substitution process and in the third use here strings. You will also notice that unlike the previous example, here the use of here strings was not the fastest. But note well that this last case the command who is running on a subshell and that encumbered the process as a whole.

Let us see a quick way to insert a row as a header file:

$ cat num 1 2 3 4 5 6 7 8 9 10 $ cat - num <<< "Odd Even" Odd Even 1 2 3 4 5 6 7 8 9 10

  • Use #2. Another cool way to use here strings is connecting with a read command, not losing sight of what we learned about IFS (see here, in the explanation of the for command). The cat command with -vet options shows <ENTER> as $, the <TAB> as ^I and other control characters with the notation ^L where L is any letter. Let us look at the contents of a variable and then we read each of your fields:

Examples:

$ echo "$Line" Leonardo Mello (21)3313-1329 $ cat -vet <<< "$Line" Leonardo Mello^I(21)3313-1329$ # The tabs are white and <TAB> (^I) $ read Nom SNom Tel <<< "$Line" $ echo "${Nom}_$S{Nom}_$Tel" # Let's see if it read each of the fields Leonardo_Mello_(21)3313-1329 # Was read because the tabs fit with IFS

We can also read directly into a vector (array) see:

$ echo $Fruits Pear:Grape:Apple $ IFS=: $ echo $Fruits Pear Grape Apple # Without the quotes the shell shows the IFS as blank $ echo "$Fruits" Pear:Grape:Apple # Ahhh, it worked!! $ read -a aFruits <<< "$Fruits" # The -a option of the read command, read to a vector $ for i in 0 1 2 > do > echo ${aFruits[$i]} # Printing each element of the vector > done Pear Grape Apple

Peczenyj Rotational

I was, as I do every day, giving a read in emails in the "List Shell Script" when I saw a "discovery" totally unusual of Tiago Barcellos Peczenyj.

When I decided to create this collection of tips, remembered it and asked him to forward me that email again. The following is the email he sent me, I just enter the last example and took abbreviations.

Julio, I found a way to Shell create combinations making rotation with the indicated elements. We can generate all binaries 0000-1111 as follows:

$ A={0,1} $ eval echo $A$A$A$A 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111

A practical application that I see is to combine different values ​​without having to use the chain loops or seq

$ A={`seq -s , -f "_%g" 3`} $ eval echo -e $A$A$A |tr ' _' '\n ' | grep -vE '.+?(\b[0-9]+\b).+?\1' 1 2 3 1 3 2 2 1 3 2 3 1 3 1 2 3 2 1

In this case I combined the numbers 1-3 eliminating repetitions with grep. I used a tr 'bad' to better handle data, jumping line.

The grep is simple as you can see, I see if a certain part of the combination (. + (.+?(\b[0-9]+\b).+?=) exists in another part (\1), if there is I don't leave print because of the option v so

    1 1 2
    1 2 1
    1 1 1
will not print.

Now here is my example: one-liner below will generate all possible permissions (octal) for file arq (the example was stopped because there are 512 possible combinations of permissions).

$ A={`seq -s , 0 7`} $ eval echo -e $A$A$A | tr ' ' '\n' | xargs -i bash -c "chmod {} arq; ls -l arq" ---------- 1 julio julio 100 2006-11-27 11:50 arq ---------x 1 julio julio 100 2006-11-27 11:50 arq --------w- 1 julio julio 100 2006-11-27 11:50 arq --------wx 1 julio julio 100 2006-11-27 11:50 arq -------r-- 1 julio julio 100 2006-11-27 11:50 arq -------r-x 1 julio julio 100 2006-11-27 11:50 arq -------rw- 1 julio julio 100 2006-11-27 11:50 arq -------rwx 1 julio julio 100 2006-11-27 11:50 arq . . . . . . . . . . . . . . . . . . -rwxrwxrw- 1 julio julio 100 2006-11-27 11:50 arq -rwxrwxrwx 1 julio julio 100 2006-11-27 11:50 arq

Let's see this example step-by-step to understand it:

$ A={`seq -s , 0 7`} $ echo $A {0,1,2,3,4,5,6,7} $ eval echo -e $A$A$A 000 001 002 003 004 005 006 007 010 ... ... 767 770 771 772 773 774 775 776 777 $ eval echo -e $A$A$A | tr ' ' '\n' # The tr will change each space for a <ENTER> 000 001 002 003 . . . 774 775 776 777

Following the xargs ( click to xargs tips executes the bash -c command (serving to run a command line) which in turn executes chmod and ls -l to show that the permissions are changed.

Shell Arithmetic

Formerly we wore the expr command to do arithmetic operations and a lot of people still use, it is compatible with any flavor Shell.

Example:

$ expr 7 \* 5 / 3 # 7 times 5 = 35 divided by 3 = 11 11

In this article however, we will see other ways not so much known, but much simpler to use, more elaborate and more accurately (the bc as we see below has arbitrary precision, i.e. you can use a precision needed to calculate shipping a ship to a satellite of Saturn).

The bc use

A nifty way of doing calculations in Shell – usually used when the arithmetic expression is more complex (as in scientific computing), or when we need to work with decimals – is to use the calculator instruction UNIX/LINUX. The bc. View as:

Example:

$ echo "(2 + 3) * 5" | bc # Parentheses used to give precedence 25

To work with real numbers (not necessarily integers), specify the precision (number of decimal) with scale option bc command. So let's look at the penultimate example:

$ echo "scale=2; 7*5/3" | bc 11.66

Other examples:

$ echo "scale=3; 33.333*3" | bc 99.999 $ num=5 $ echo "scale=2; ((3 + 2) * $num + 4) / 3" | bc 9.66

Obviously all the above examples, in the case of Linux, could (and should) be written using Here Strings. See the latest as would:

$ bc <<< "scale=3; 33.333*3" 99.999 $ num=5 $ bc <<< "scale=2; ((3 + 2) * $num + 4) / 3" 9.66

Once appeared on the Shell script list (excellent by the way) on Yahoo (http://br.groups.yahoo.com/group/shell-script/) a guy with the following question: "I have a file whose fields are separated by <TAB> and the third of them have numbers. How do I calculate the sum of all the numbers in this column of the file?"

I sent the following reply:

$ echo $(cut -f3 num | tr '\n' +)0 | bc 20.1

Let's go by parts to understand it better. First let's see how the file was made ​​for testing:

$ cat num a b 3.2 a z 4.5 w e 9.6 q w 2.8

As you can see, is within the standard problem where I have as third field real numbers. Let's see what would the first part of the command line, where I transform the characters <ENTER> (new-line) on a plus sign (+):

$ cut -f3 num | tr '\n' + 3.2+4.5+9.6+2.8+

If I would send that way to the bc, it would return me an error because of that plus sign (+) released at the end of the text. My solution was to put a zero at the end, because adding zero does not change the result. We'll see then how it fits:

$ echo $(cut -f3 num | tr '\n' +)0 3.2+4.5+9.6+2.8+0

Okay, the problem is solved, but shell always has a little way of writing less code yet. See this:

$ cut -f3 num | paste -sd+ 3.2+4.5+9.6+2.8

I.e., the cut command cut the third column and sends the numbers for a paste, which -s option transform columns into rows and the -d+ defines the plus sign (+) as delimiter. Made it, just send it all to the bc proceed the sum with the real.

$ cut -f3 num | paste -sd+ | bc 20.1

This is what is usually called one-liner, i.e. codes that would be complicated in other languages ​​(usually would need to create counters and make a reading loop adding the third field to the counter) and Shell are written in a single line.

There are also people who call this method KISS, which is the acronym for Keep It Simple Stupid. smile

But the potential use of this calculator does not end there, there are several facilities afforded by it. Look at this example:

$ echo "obase=16; 11579594" | bc B0B0CA? $ echo "ibase=16; B0B0CA?" | bc # B, zero, B, zero, C, e A 11579594

In these examples we have seen how to make changes of base of numbering with using bc. At first we make explicit the base of output (obase) as 16 (hexadecimal) and second, we said that the base of input (ibase) was 10 (decimal).

Other ways to work with integers

Another very cool way to do calculations is to use the notation $((arithmetic exp)). It is good to be aware, however, the fact that this syntax will not be universalized. The Bourne Shell (sh), for example, does not recognize it.

Example:

Using the same example that we have used:

$ echo $(((2+3)*5)) # Parentheses from inside prioritized the 2+3 25

Now just look at this craziness:

$ three=3 $ echo $(((2+three)*5)) # Variable three not preceded by $ 25 $ echo $(((2+$three)*5)) # Variable three not preceded by $ 25

Huh! It is not the dollar sign ($) precedent that features a variable? Yes, but in all UNIX flavors tested, under bash or ksh, both forms of construction produce a good arithmetic.

Pay attention in this sequence:

$ unset i # $i died! $ echo $((i++)) 0 $ echo $i 1 $ echo $((++i)) 2 $ echo $i 2

Note that although the variable not be set because it was made ​​a unset it, none of the commands accused error, because, as we are using arithmetic constructions, whenever a variable does not exist, is initialized to zero (0).

Note that i++ produced zero (0). This is because this type of construction is called post-increment, i.e. firstly the command is executed and only then the variable is incremented. In the case of ++i, a pre-increment was taken: firstly increased and then only after the command was executed.

Are also valid:

$ echo $((i+=3)) 5 $ echo $i 5 $ echo $((i*=3)) 15 $ echo $i 15 $ echo $((i%=2)) 1 $ echo $i 1

These three operations would be the same as:

    i=$((i+3))
    i=$((i*3))
    i=$((i%2))

And this would be true for all arithmetic operators which produce a summary in the following table:

Arithmetic Expansion
||   OR logical
  Expression     Result  
id++ id--   post-increment and post-decrement variable
++id -–id   pre-increment and pre-decrement variable
**   exponentiation
* / %   multiplication, division, remainder of division
+ -   addition, subtraction
<= >= < >   comparison
== !=   equality, inequality
&&   And logical

But the height of this form of construction with double parentheses is as follows:

$ echo $var 50 $ var=$((var>40 ? var-40 : var+40)) $ echo $var 10 $ var=$((var>40 ? var-40 : var+40)) $ echo $var 50

This type of construction should be read as follows: If the variable var is greater than 40 (var>40), then (?) do var equals var less 40 (var-40), if not (:) do var equals var more 40 (var+40). What i meant is that the characters point of interrogation (?) and colon (:) play the role of "then" and "else", thus serving to mount a conditional arithmetic operation.

Similarly we use the expression $((...)) to do arithmetic operations, we could also use the intrinsic (built-in) let or construction type $[...].

The operators are the same for these three types of construction, which varies somewhat is the conditional arithmetic operation with the use of let. Let's see how it would be:

$ echo $var 50 $ let var='var>40 ? var-40 : var+40' $ echo $var 10 $ let var='var>40 ? var-40 : var+40' $ echo $var 50

Baseando

Se você quiser trabalhar com bases diferentes da decimal, basta usar o formato:

    base#numero

Onde base é um número decimal entre 2 e 64 representando o sistema de numeração, e numero é um número no sistema numérico definido por base. Se base# for omitida, então 10 é assumida como default. Os algarismos maiores que 9 são representados por letras minúsculas, maiúsculas, @ e _, nesta ordem.

Se base for menor ou igual a 36, maiúsculas ou minúsculas podem ser usadas indiferentemente para definir algarismos maiores que 9 (não está mal escrito, os algarismos do sistema hexadecimal, por exemplo, variam entre 0 (zero) e F). Vejamos como isso funciona:

$ echo $[2#11] 3 $ echo $((16#a)) 10 $ echo $((16#A)) 10 $ echo $((2#11 + 16#a)) 13 $ echo $[64#a] 10 $ echo $[64#A] 36 $ echo $((64#@)) 62 $ echo $((64#_)) 63

Nestes exemplos usei as notações $((...)) e $[...] indistintamente, para demonstrar que ambas funcionam.

Funciona também uma mudança automática para a base decimal, desde que você esteja usando a convenção numérica do C, isto é, em 0xNN, o NN será tratado como um hexadecimal e em 0NN, o NN será visto como um octal. Veja o exemplo:

Exemplo

$ echo $((10)) # decimal 10 $ echo $((010)) # octal 8 $ echo $((0x10)) # hexadecimal 16 $ echo $((10+010+0x10)) # Decimal + octal + hexadecimal 64

Ah, já ia me esquecendo! As expressões aritméticas com os formatos $((...)), $[...] e com o comando let usam os mesmos operadores usados na instrução expr, além dos operadores unários (++, --, +=, *=, ...) e condicionais que acabamos de ver.

Testes usando expressões regulares

No Papo de Botequim 004, nós falamos tudo sobre comandos condicionais, mas faltou um que não existia àquela época. Neste mesmo Papo de Botequim, na seção E tome de test nós chegamos a falar de uma construção do tipo:

    [[ Expressao ]] && cmd

Onde o comando cmd será executado caso a expressão condicional Expressao seja verdadeira. Disse ainda que Expressao poderia ser estipulada de acordo com as regras de Geração de Nome de Arquivos (File Name Generation). A partir do bash versão 3, foi incorporado a esta forma de teste um operador representado por =~, cuja finalidade é fazer comparações com Expressões Regulares.

Exemplo:

$ echo $BASH_VERSION # Conferindo se a versão do Bash é igual ou superior a 3.0.0 3.2.17(15)-release $ Cargo=Senador $ [[ $Cargo =~ ^(Governa|Sena|Verea)dora?$ ]] && echo É político É político $ Cargo=Senadora $ [[ $Cargo =~ ^(Governa|Sena|Verea)dora?$ ]] && echo É político É político $ Cargo=Diretor $ [[ $Cargo =~ ^(Governa|Sena|Verea)dora?$ ]] && echo É político $

Vamos dar uma esmiuçada na Expressão Regular ^(Governa|Sena|Verea)dora?$: ela casa com tudo que começa (^) por Governa, ou (|) Sena, ou (|) Verea, seguido de dor e seguido de um a opcional (?). O cifrão ($) serve para marcar o fim. Em outras palavras esta Expressão Regular casa com Governador, Senador, Vereador, Governadora, Senadora e Vereadora.

Colorindo a tela

Como você já havia visto no Papo de Botequim 007, o comando tput serve para fazer quase tudo referente a formatação de tela, mas o que não foi dito é que com ele também pode-se usar cores de frente (dos caracteres) e de fundo. Existem também outras formas de fazer o mesmo, acho porém, esta que veremos agora, mais intuitiva (ou menos “desintuitiva”). A tabela a seguir mostra os comandos para especificarmos os padrões de cores de frente (foreground) ou de fundo (background):

Obtendo cores com o comando tput
tput setab n Especifica n como a cor de fundo (background)
  Comando     Efeito  
tput setaf n Especifica n como a cor de frente (foreground)

Bem, agora você já sabe como especificar o par de cores, mas ainda não sabe as cores. A tabela a seguir mostra os valores que o n (da tabela anterior) deve assumir para cada cor:

Valores das cores com o comando tput
7 Cinza claro
  Valor     Cor  
0 Preto
1 Vermelho
2 Verde
3 Marrom
4 Azul
5 Púrpura
6 Ciano

Neste ponto você já pode começar a brincar com as cores.

- Mas peraí, ainda são muito poucas!

- É, tem toda razão... O problema é que ainda não lhe disse que se você colocar o terminal em modo de ênfase (tput bold), estas cores geram outras oito. Vamos montar então a tabela definitiva de cores:

Valores das cores com o comando tput
7 Cinza claro Branco
  Valor     Cor     Cor após tput bold  
0 Preto Cinza escuro
1 Vermelho Vermelho claro
2 Verde Verde claro
3 Marron Amarelo
4 Azul Azul Brilhante
5 Púrpura Rosa
6 Ciano Ciano claro

Exemplo

Como exemplo, vejamos um script que mudará a cor de sua tela de acordo com sua preferência.

$ cat mudacor.sh #!/bin/bash tput sgr0 clear

# Carregando as 8 cores básicas para um vetor Cores=(Preto Vermelho Verde Marrom Azul Púrpura Ciano "Cinza claro")

# Listando o menu de cores echo " Opc Cor = ===" # A linha a seguir significa: para i começando de 1; #+ enquanto i menor ou igual ao tamanho do vetor Cores; #+ incremente o valor de i de 1 em 1 for ((i=1; i<=${#Cores[@]}; i++)) { printf "%02d %s\n" $i "${Cores[i-1]}" }

CL= until [[ $CL == 0[1-8] || $CL == [1-8] ]] do read -p " Escolha a cor da letra: " CL done

# Para quem tem bash a partir da versao 3.2 #+ o test do until acima poderia ser feito #+ usando-se Expressoes Regulares. Veja como: #+ until [[ $CL =~ 0?[1-8] ]] #+ do #+ read -p " #+ Escolha a cor da letra: " CL #+ done

CF= until [[ $CF == 0[1-8] || $CF == [1-8] ]] do read -p " Escolha a cor de fundo: " CF done

let CL-- ; let CF-- # Porque as cores variam de zero a sete tput setaf $CL tput setab $CF clear

Ganhando o jogo com mais coringas

Estava eu lendo meus e-mails quando recebo um do Tiago enviado para a lista de Shell Script (já falei da lista e do Tiago no Rotatório Peczenyj). A seguir o conteúdo do e-mail:

Não sei se é conhecimento de todos mas o shell possui, alem do globbing normal (a expansão *, ? e [a-z] de nomes de arquivos e diretórios), um globbing extendido.

Acho que, em alguns casos, podera ser BEM util, eliminando um pipe para um grep por exemplo.

São eles:

    ?(padrao)
Casa zero ou uma ocorrência de um determinado padrao
    *(padrao)
Casa zero ou mais ocorrências de um determinado padrao
    +(padrao)
Casa uma ou mais ocorrências de um determinado padrao
    @(padrao)
Casa com exatamente uma ocorrência de um determinado padrao
    !(padrao)
Casa com qualquer coisa, exceto com padrao

Para poder utilizá-lo precisa executar o shopt conforme o exemplo abaixo:

$ shopt -s extglob $ ls file filename filenamename fileutils $ ls file?(name) file filename $ ls file*(name) file filename filenamename $ ls file+(name) filename filenamename $ ls file@(name) filename $ ls file!(name) # divertido esse file filenamename fileutils $ ls file+(name|utils) filename filenamename fileutils $ ls file@(name|utils) # "lembra" um {name,utils} filename fileutils

Usando o awk para pesquisar por equivalência

Aí vai mais uma que o Tiago mandou para a lista de Shell Script do Yahoo (já falei da lista e do Tiago no Rotatório Peczenyj e no Ganhando o jogo com mais coringa)

Quem ja não passou por isso: Procurar uma palavra, porém uma letra acentuada, ou não, atrapalhou a busca?

Não descobri como fazer o grep ou sed aceitarem algo semelhante, mas o gawk aceita classes de equivalência!

Melhor explicar com um exemplo, onde vou listar o número da linha e a ocorrência casada:

$ cat dados éco eco èco êco ëco eço $ awk '/^eco/{print NR,$1}' dados 2 eco $ awk '/^e[[=c=]]o/{print NR,$1}' dados 2 eco 6 eço $ awk '/^[[=e=]]co/{print NR,$1}' dados 1 éco 2 eco 3 èco 4 êco 5 ëco

Ou seja, usar [=X=] permite que a expressão encontre a letra X estando acentuada ou não (é sensivel à localização corrente!).

A sintaxe é parecida com a das classes POSIX, trocando os dois-pontos (:) antes e depois da classe por sinais de igual (=).

Achei curioso e deve servir para algum caso semelhante ao descrito.

find – Procurando arquivo por características

Se você está como o Mr. Magoo, procurando em vão um arquivo, use o comando find que serve para procurar arquivos não só pelo nome, como por diversas outras características. Sua sintaxe é a seguinte:

    find [caminho ...] expressão [ação]

Parâmetros:

caminho      Caminhos de diretório a partir do qual (porque ele é recursivo, sempre tentará entrar pelos subdiretórios "pendurados" neste) irá procurar pelos arquivos;
expressão   Define quais critérios de pesquisa. Pode ser uma combinação entre vários tipos de procura;
ação           Define que ação executar com os arquivos que atender aos critérios de pesquisa definidos por expressão.

Principais critérios de pesquisa

-name Procura arquivos que tenham o nome especificado. Aqui podem ser usados metacaracteres ou caracteres curingas, porém estes caracteres deverão estar entre aspas, apóstrofos ou imediatamente precedidos por uma contrabarra isso porque quem tem de expandir os coringas é o find. Se fosse o Shell que os expandisse, isto seria feito somente com relação ao diretório corrente, o que jogaria por terra a característica recursiva do find;
-user Procura arquivos que tenham usuário como dono;
-group Procura arquivos que tenham grupo como grupo dono;
-type c Procura por arquivos que tenham o tipo c, correspondente à letra do tipo do arquivo. Os tipos aceitos estão na tabela a seguir:
Valores de c na opção   acima Tipo de arquivo procurado
b Arquivo especial acessado a bloco
c Arquivo especial acessado a caractere
d Diretório
p Named pipe (FIFO)
f Arquivo normal
l Link simbólico
s Socket
-size ±n[unid] A opção -size procura por arquivos que usam mais (+n) de n unidades unid de espaço ou a menos (-n) de n unidades unid de espaço.
Valores de unid na opção   acima Valor
b Bloco de 512 bytes (valor default)
c Caracteres
k Kilobytes (1024 bytes)
w Palavras (2 bytes)
-atime ±d Procura por arquivos que foram acessados há mais (+d) de d dias ou a menos (-d) de d dias;
-ctime ±d Procura por arquivos cujo status mudou há mais (+d) de d dias ou a menos (-d) de d dias;
-mtime ±d Procura por arquivos cujos dados foram modificados há mais (+d) de d dias ou a menos (-d) de d dias;

Para usar mais de um critério de pesquisa, faça:
     expressão1 expressão2
ou
     expressão1 –a expressão2
para atender aos critérios especificados por expressão1 e expressão2;
     expressão1 –o expressão2
para atender aos critérios especificados por expressão1 ou expressão2.

Principais ações

-print Esta opção faz com que os arquivos encontrados sejam exibidos na tela. Esta é a opção default no Linux. Nos outros sabores Unix que conheço, se nenhuma ação for especificada, ocorrerá um erro;
-exec cmd {} \; Executa o comando cmd. O escopo de comando é considerado encerrado quando um ponto-e-vírgula (;) é encontrado. A cadeia {} é substituída pelo nome de cada arquivo que satisfaz ao critério de pesquisa e a linha assim formada é executada. Assim como foi dito para a opção –name, o ponto-e-vírgula (;) deve ser precedido por uma contrabarra (\), ou deve estar entre aspas ou apóstrofos;
-ok cmd {} \; O mesmo que o anterior porém pergunta se pode executar a instrução cmd sobre cada arquivo que atende ao critério de pesquisa;
-printf formato  A opção -printf permite que se escolha os campos que serão listados e formata a saída de acordo com o especificado em formato.

Exemplos:

Para listar na tela (-print) todos os arquivos, a partir do diretório corrente, terminados por .sh, faça:

$ find . -name \*.sh Ação não especificada –print é default ./undelete.sh ./ntod.sh estes quatro primeiros arquivos foram ./dton.sh encontrados no diretório corrente. ./graph.sh ./tstsh/cotafs.sh ./tstsh/data.sh Estes quatro foram encontrados no ./tstsh/velha.sh diretório tstsh, sob o diretório corrente ./tstsh/charascii.sh

Preciso abrir espaço em um determinado file system com muita urgência, então vou remover arquivos com mais de um megabyte e cujo último acesso foi há mais de 60 dias. Para isso, vou para este file system e faço:

$ find . –type f –size +1000000c –atime +60 –exec rm {} \;

Repare que no exemplo acima usei três critérios de pesquisa, a saber:

-type f Todos os arquivos regulares (normais)
-size +1000000c   Tamanho maior do que 1000000 de caracteres (+1000000c)
-atime +60 Último acesso há mais de 60 (+60) dias.

Repare ainda que entre estes três critérios foi usado o conector e, isto é, arquivos regulares e maiores que 1MByte e sem acesso há mais de 60 dias.

Para listar todos os arquivos do disco terminados por .sh ou .txt, faria:

$ find / -name \*.sh –o –name \*.txt –print

Neste exemplo devemos salientar além das contrabarras (\) antes dos asteriscos (*), o uso do –o para uma ou outra extensão e que o diretório inicial era o raiz (/); assim sendo, esta pesquisa deu-se no disco inteiro (o que freqüentemente é bastante demorado).

Com o printf é possível formatar a saída do comando find e especificar os dados desejados. A formatação do printf é muito semelhante à do mesmo comando na linguagem C e interpreta caracteres de formatação precedidos por um símbolo de percentual (%). Vejamos seus efeitos sobre a formatação:

Caractere Significado
%U Número do usuário (UID) do dono do arquivo
%f Nome do arquivo (caminho completo não aparece)
%F Indica a qual tipo de file system o arquivo pertence
%g Grupo ao qual o arquivo pertence
%G Grupo ao qual o arquivo pertence (GID- Numérico)
%h Caminho completo do arquivo (tudo menos o nome)
%i Número do inode do arquivo (em decimal)
%m Permissão do arquivo (em octal)
%p Nome do arquivo
%s Tamanho do arquivo
%u Nome de usuário (username) do dono do arquivo

Também é possível formatar datas e horas obedecendo às tabelas a seguir:

Caractere Significado
%a Data do último acesso
%c Data de criação
%t Data de alteração

Os três caracteres anteriores produzem uma data semelhante ao do comando date.

Veja um exemplo:

$ find . -name ".b*" -printf '%t %p\n' Mon Nov 29 11:18:51 2004 ./.bash_logout Tue Nov 1 09:44:16 2005 ./.bash_profile Tue Nov 1 09:45:28 2005 ./.bashrc Fri Dec 23 20:32:31 2005 ./.bash_history

Nesse exemplo, o %p foi o responsável por colocar os nomes dos arquivos. Caso fosse omitido, somente as datas seriam listadas. Observe ainda que ao final foi colocado um /n. Sem ele não haveria salto de linha e a listagem anterior seria uma grande tripa.

Essas datas também podem ser formatadas, para isso basta passar as letras da tabela anterior para maiúsculas (%A, %C e %T) e usar um dos formatadores das duas tabelas a seguir:

Tabela de formatação de tempo
Z  Fuso horário (na Cidade Maravilhosa BRST)
  Caractere     Significado  
H  Hora (00..23)
I  Hora (01..12)
k  Hora (0..23)
l  Hora (1..12)
M  Minuto (00..59)
p  AM or PM
r  Horário de 12 horas (hh:mm:ss) seguido de AM ou PM
S  Segundos (00 ... 61)
T  Horário de 24-horas (hh:mm:ss)

Tabela de formatação de datas
Y  Ano com 4 dígitos
  Caractere     Significado  
a  Dia da semana abreviado (Dom...Sab)
A  Dia da semana por extenso (Domingo...Sábado)
b  Nome do mês abreviado (Jan...Dez)
B  Dia do mês por extenso (Janeiro...Dezembro)
c  Data e hora completa (Fri Dec 23 15:21:41 2005)
d  Dia do mês (01...31)
D  Data no formato mm/dd/aa
h  Idêntico a b
j  Dia seqüencial do ano (001…366)
m  Mês (01...12)
U  Semana seqüencial do ano. Domingo como 1º dia da semana (00...53)
w  Dia seqüencial da semana (0..6)
W  Semana seqüencial do ano. Segunda-feira como 1º dia da semana (00...53)
x  Representação da data no formato do país (definido por $LC_ALL)
y  Ano com 2 dígitos (00...99)

Para melhorar a situação, vejamos uns exemplos; porém, vejamos primeiro quais são os arquivos do diretório corrente que começam por .b:

$ ls -la .b* -rw------- 1 d276707 ssup 21419 Dec 26 17:35 .bash_history -rw-r--r-- 1 d276707 ssup 24 Nov 29 2004 .bash_logout -rw-r--r-- 1 d276707 ssup 194 Nov 1 09:44 .bash_profile -rw-r--r-- 1 d276707 ssup 142 Nov 1 09:45 .bashrc

Para listar esses arquivos em ordem de tamanho, podemos fazer:

$ find . -name ".b*" -printf '%s\t%p\n' | sort -n 24 ./.bash_logout 142 ./.bashrc 194 ./.bash_profile 21419 ./.bash_history

No exemplo que acabamos de ver, o \t foi substituído por um na saída de forma a tornar a listagem mais legível. Para listar os mesmos arquivos classificados por data e hora da última alteração:

$ find . -name ".b*" -printf '%TY-%Tm-%Td %TH:%TM:%TS %p\n' | sort 2004-11-29 11:18:51 ./.bash_logout 2005-11-01 09:44:16 ./.bash_profile 2005-11-01 09:45:28 ./.bashrc 2005-12-26 17:35:13 ./.bash_history

Algumas implementações do Bash 4.0

Aqui neste tópico lançarei somente o que é inteiramente novo a partir do Bash 4.0. O que já existia, mas que foi aprimorado a partir desta versão do Bash (como as expansões de parâmetro), está sendo publicado na seção correspondente.

Coprocessos

A partir da versão 4.0, o Bash incorporou o comando coproc. Este novo intrínseco (builtin) permite dois processos assíncronos se comunicarem e interagirem. Como cita Chet Ramey no Bash FAQ, ver. 4.01:

"Há uma nova palavra reservada, coproc, que especifica um coprocesso: um comando assíncrono que é executado com 2 pipes conectados ao Shell criador. coproc pode receber nome. Os descritores dos arquivos de entrada e saída e o PID do coprocesso estão disponíveis para o Shell criador em variáveis com nomes específicos do coproc."

George Dimitriu explica:

"O coproc é uma facilidade usada na substituição de processos que agora está publicamente disponível."

A comprovação do que disse Dimitriu não é complicada, quer ver? Veja a substituição de processos a seguir:

$ cat <(echo xxx; sleep 3; echo yyy; sleep 3)

Viu?! O cat não esperou pela conclusão dos comandos entre parênteses, mas foi executado no fim de cada um deles. Isso aconteceu porque estabeleceu-se um pipe temporário/dinâmico e os comandos que estavam sendo executados, mandavam para ele as suas saídas, que por sua vez as mandava para a entrada do cat.

Isso significa que os comandos desta substituição de processos rodaram paralelos, sincronizando somente nas saídas dos echo com a entrada do cat.

A sintaxe de um coprocesso é:

   coproc [nome] cmd redirecionamentos

Isso criará um coprocesso chamado nome. Se nome for informado, cmd deverá ser um comando composto. Caso contrário (no caso de nome não ser informado), cmd poderá ser um comando simples ou composto.

Quando um coproc é executado, ele cria um vetor com o mesmo nome nome no Shell criador. Sua saída padrão é ligada via um pipe a um descritor de arquivo associado à variável ${nome[0]} à entrada padrão do Shell pai (lembra que a entrada padrão de um processo é sempre associada por default ao descritor zero?). Da mesma forma, a entrada do coproc é ligada à saída padrão do script, via pipe, a um descritor de arquivos chamado ${nome[1]}. Assim, simplificando, vemos que o script mandará dados para o coproc pela variável ${nome[0]}, e receberá sua saída em ${nome[1]}. Note que estes pipes serão criados antes dos redirecionamentos especificados pelo comando, já que eles serão as entradas e saídas do coprocesso.

A partir daqui, vou detalhar rapidamente uns estudos que fiz. Isso contém um pouco de divagações e muita teoria. Se você pular para depois desses ls's, não perderá nada, mas se acompanhar, pode ser bom para a compreensão do mecanismo do coproc.

Após colocar um coproc rodando, se ele está associado a um descritor de arquivo, vamos ver o que tem ativo no diretório correspondente:

$ ls -l /dev/fd lrwxrwxrwx 1 root root 13 2010-01-06 09:31 /dev/fd -> /proc/self/fd

Hummm, é um link para o /proc/self/fd... O que será que tem lá?

$ ls -l /proc/self/fd total 0 lrwx------ 1 julio julio 64 2010-01-06 16:03 0 -> /dev/pts/0 lrwx------ 1 julio julio 64 2010-01-06 16:03 1 -> /dev/pts/0 lrwx------ 1 julio julio 64 2010-01-06 16:03 2 -> /dev/pts/0 lr-x------ 1 julio julio 64 2010-01-06 16:03 3 -> /proc/3127/fd

Epa, que o 0, 1 e 2 apontavam para /dev/pts/0 eu já sabia, pois são a entrada padrão, saída padrão e saída de erros padrão apontando para o pseudo terminal corrente, mas quem será esse maldito device 3? Vejamos:

$ ls -l /proc/$$/fd # $$ É o PID do Shell corrente total 0 lr-x------ 1 julio julio 64 2010-01-06 09:31 0 -> /dev/pts/0 lrwx------ 1 julio julio 64 2010-01-06 09:31 1 -> /dev/pts/0 lrwx------ 1 julio julio 64 2010-01-06 09:31 2 -> /dev/pts/0 lrwx------ 1 julio julio 64 2010-01-06 16:07 255 -> /dev/pts/0 l-wx------ 1 julio julio 64 2010-01-06 16:07 54 -> pipe:[168521] l-wx------ 1 julio julio 64 2010-01-06 16:07 56 -> pipe:[124461] l-wx------ 1 julio julio 64 2010-01-06 16:07 58 -> pipe:[122927] lr-x------ 1 julio julio 64 2010-01-06 16:07 59 -> pipe:[168520] l-wx------ 1 julio julio 64 2010-01-06 16:07 60 -> pipe:[121302] lr-x------ 1 julio julio 64 2010-01-06 16:07 61 -> pipe:[124460] lr-x------ 1 julio julio 64 2010-01-06 16:07 62 -> pipe:[122926] lr-x------ 1 julio julio 64 2010-01-06 16:07 63 -> pipe:[121301]

Epa, aí estão os links apontando para os pipes. Esse monte de arquivo de pipe que foi listado, deve ser porque estava testando exaustivamente essa nova facilidade do Bash.

Para terminar esta teoria chata, falta dizer que o PID do Shell gerado para interpretar o coproc pode ser obtido na variável $nome_PID e o comando wait pode ser usado para esperar pelo fim do coprocesso. O código de retorno do coprocesso ($?) é o mesmo de cmd.

Exemplo:

Vamos começar com o mais simples: um exemplo sem nome e direto no prompt:

$ coproc while read Entra # coproc ativo > do > echo -=-=- $Entra -=-=- > done [2] 3030 $ echo Olá >&${COPROC[1]} # Manda Olá para a pipe da saída $ read -u ${COPROC[0]} Sai # Lê do pipe da entrada $ echo $Sai -=-=- Olá -=-=- $ kill $COPROC_PID # Isso não pode ser esquecido...

Como você viu, o vetor COPROC, está associado a dois pipes; o ${COPROC[1]} que contém o endereço do pipe de saída, e por isso a saída do echo esta redirecionada para ele e o ${COPROC[0]} que contém o endereço do pipe de entrada, e por isso usamos a opção -u do read que lê dados a partir de um descritor de arquivo definido, ao invés da entrada padrão.

Como o coprocesso utilizava a sintaxe sem nome, o padrão do nome do vetor é COPROC.

Só mais uma teoriazinha chata:

$ echo ${COPROC[@]} # Lista todos os elementos do vetor 59 54

Como você viu ${COPROC[0]} estava usando o pipe apontado por /proc/$$/fd/59 e ${COPROC[1]} usava /proc/$$/fd/54. Agora chega de teoria mesmo! Vamos agora usar nome neste mesmo exemplo, para ver que pouca coisa muda:

$ coproc teste { > while read Entra > do > echo -=-=- $Entra -=-=- > done > } [6] 3192 $ echo Olá >&${teste[1]} $ read -u ${teste[0]} Sai $ echo $Sai -=-=- Olá -=-=- $ kill $teste_PID

Nesse momento, é bom mostrar uma coisa interessante: Quais são os processos em execução?

$ ps # Somente no Bash em execução PID TTY TIME CMD 1900 pts/0 00:00:01 bash 2882 pts/0 00:00:00 ps

Vamos executar 2 coprocessos simultâneos:

$ coproc nome1 { # Coprocesso nome1 > while read x > do > echo $x > done; } [1] 2883 $ coproc nome2 { # Coprocesso nome2 > while read y > do > echo $y > done; } bash: aviso: execute_coproc: coproc [2883:nome1] still exists [2] 2884

Xiiii! Acho que deu zebra! Mas será que deu mesmo? Repare que além do PID 2883 de nome1, ele também me devolveu o PID 2884, que deve ser de nome2. Vamos ver o que está acontecendo:

$ ps PID TTY TIME CMD 1900 pts/0 00:00:01 bash Esse já existia 2883 pts/0 00:00:00 bash Esse está executando nome1 2884 pts/0 00:00:00 bash Esse está executando nome2 2885 pts/0 00:00:00 ps

Parece que foi só um aviso, pois os dois PIDs informados quando iniciamos os dois coprocessos, estão ativos. Então vamos testar esses 2 caras:

$ echo xxxxxxxxx >&${nome1[1]} # Mandando cadeia para nome1 $ echo yyyyyyyyy >&${nome2[1]} # Mandando cadeia para nome2 $ read -u ${nome1[0]} Recebe $ echo $Recebe xxxxxxxxx $ read -u ${nome2[0]} Recebe $ echo $Recebe yyyyyyyyy $ kill $nome1_PID $ kill $nome2_PID

Vetores associativos

A partir do Bash 4.0, passou a existir o vetor associativo. Chama-se vetor associativo, aqueles cujos índices são alfabéticos. As regras que valem para os vetores inteiros, valem também para os associativos, porém antes de valorar estes últimos, é obrigatório declará-los.

Exemplo:

$ declare -A Animais # Obrigatório para vetor associativo $ Animais[cavalo]=doméstico $ Animais[zebra]=selvagem $ Animais[gato]=doméstico $ Animais[tigre]=selvagem

Pinguim com placa de atenção É impossível gerar todos os elementos de uma só vez, como nos vetores inteiros. Assim sendo, não funciona a sintaxe:
Animais=([cavalo]=doméstico [zebra]=selvagem  [gato]=doméstico [tigre]=selvagem)

$ echo ${Animais[@]} doméstico selvagem doméstico selvagem $ echo ${!Animais[@]} gato zebra cavalo tigre

Repare que os valores não são ordenados, ficam armazenados na ordem que são criados, diferentemente dos vetores inteiros que ficam em ordem numérica.

Supondo que esse vetor tivesse centenas de elementos, para listar separadamente os domésticos dos selvagens, poderíamos fazer um script assim:

$ cat animal.sh #!/bin/bash # Separa animais selvagens e domésticos declare -A Animais Animais[cavalo]=doméstico # Criando vetor para teste Animais[zebra]=selvagem # Criando vetor para teste Animais[gato]=doméstico # Criando vetor para teste Animais[tigre]=selvagem # Criando vetor para teste Animais[urso pardo]=selvagem # Criando vetor para teste for Animal in "${!Animais[@]}" # Percorrendo vetor pelo índice do if [[ "${Animais[$Animal]}" == selvagem ]] then Sel=("${Sel[@]}" "$Animal") # Gerando vetor p/ selvagens else Dom=("${Dom[@]}" "$Animal") # Gerando vetor p/ domésticos fi done # Operador condicional, usado para descobrir qual #+ vetor tem mais elementos. Veja detalhes na seção #+ O interpretador aritmético do Shell Maior=$[${#Dom[@]}>${#Sel[@]}?${#Dom[@]}:${#Sel[@]}] clear tput bold; printf "%-15s%-15s\n" Domésticos Selvagens; tput sgr0 for ((i=0; i<$Maior; i++)) { tput cup $[1+i] 0; echo ${Dom[i]} tput cup $[1+i] 14; echo ${Sel[i]} }

Gostaria de chamar a sua atenção para um detalhe: neste script me referi a um elemento de vetor associativo empregando ${Animais[$Animal]} ao passo que me referi a um elemento de um vetor inteiro usando ${Sel[i]}. Ou seja, quando usamos uma variável como índice de um vetor inteiro, não precisamos prefixá-la com um cifrão ($), ao passo que no vetor associativo, o cifrão ($) é obrigatório.

Lendo um arquivo para um vetor

Ainda falando do Bash 4.0, eis que ele surge com uma outra novidade: o comando intrínseco (builtin) mapfile, cuja finalidade é jogar um arquivo de texto inteiro para dentro de um vetor, sem loop ou substituição de comando.

    - EPA! Isso deve ser muito rápido!

    - E é. Faça os teste e comprove!

Exemplo:

$ cat frutas abacate maçã morango pera tangerina uva $ mapfile vet < frutas # Mandando frutas para vetor vet $ echo ${vet[@]} # Listando todos elementos de vet abacate maçã morango pera tangerina uva

Obteríamos resultado idêntico se fizéssemos:

$ vet=($(cat frutas))

Porém isso seria mais lento porque a substituição de comando é executada em um subshell. Uma outra forma de fazer isso que logo vem à cabeça é ler o arquivo com a opção -a do comando read. Vamos ver como seria o comportamento disso:

$ read -a vet < frutas $ echo ${vet[@]} abacate

Como deu para perceber, foi lido somente o primeiro registro de frutas.

Caixa baixa para alta e vice versa

Usando expansão de parâmetro

  • ${parâmetro^}
  • ${parâmetro,}
Essas expansões de parâmetros foram introduzidas a partir do Bash 4.0 e modificam a caixa das letras do texto que está sendo expandido. Quando usamos circunflexo (^), a expansão é feita para maiúsculas e quando usamos vírgula (,), a expansão é feita para minúsculas.

Exemplo:

$ Nome="botelho" $ echo ${Nome^} Botelho $ echo ${Nome^^} BOTELHO $ Nome="botelho carvalho" $ echo ${Nome^} Botelho carvalho # É pena que não fique Botelho Carvalho...

Um fragmento de script que pode facilitar a sua vida:

read -p "Deseja continuar (s/n)? "
[[ ${REPLY^} == N ]] && exit

Esta forma evita testarmos se a resposta dada foi um N (maiúsculo) ou um n (minúsculo).

Usando declaratives

Podemos fazer algo parecido, porém de outra maneira. Agora, para termos somente maiúsculas em uma variável também podemos declará-la usando a opção -u ( de uppercase = maiúscula). Veja:

$ declare -u Maiusc

Uma vez assim declarada, veja este exemplo:

$ read -p "Tecle algo: " Maiusc # A variável Maiusc receberá o que for teclado Tecle algo: converte para maiusculas $ echo $Maiusc CONVERTE PARA MAIUSCULAS

O inverso disso seria usarmos a opção -l (de lowercase = minúscula). Veja:

$ declare -l Minusc $ read -p "Tecle algo: " Minusc # A variável Minusc receberá o que for teclado Tecle algo: CONVERTE PARA MINUSCULAS $ echo $Minusc converte para minusculas

Tudo que foi dito sobre estas conversões, só é valido após o declare ter sido feito. Repare:

$ var="xxxx" # Vou atribuir antes de declarar $ declare -u var $ echo $var xxxx # Nada mudou, continua minúscula $ var="xxxx" # Atribuindo após declaração $ echo $var XXXX # Agora funcionou...

Novas implementações no comando case

O bash 4.0 introduziu duas novas facilidades no comando case. A partir desta versão, existem mais dois terminadores de bloco além do ;;, que são: ;;& - Quando um bloco de comandos for encerrado com este terminador, o programa não sairá do case, mas testará os próximos padrões; ;& - Neste caso, o próximo bloco será executado, sem sequer testar o seu padrão.

Exemplo:

Veja este fragmento de código adaptado de http://tldp.org/LDP/abs/html/bashver4.html:

case "$1" in
    [[:print:]] )  echo $1 é um caractere imprimível;;&
    # O terminador ;;& testará o próximo padrão
    [[:alnum:]] )  echo $1 é um carac. alfa/numérico;;&
    [[:alpha:]] )  echo $1 é um carac. alfabético   ;;&
    [[:lower:]] )  echo $1 é uma letra minúscula    ;;&
    [[:digit:]] )  echo $1 é um caractere numérico  ;&
    # O terminador ;& executará o próximo bloco...
    %%%@@@@@    )  echo "************************"  ;;
#   ^^^^^^^^  ... mesmo com um padrão maluco.
esac

A execução deste código passando 3 como parâmetro, resultaria:

3 é um caractere imprimível 
3 é um carac. alfa/numérico 
3 é um caractere numérico
********************************

Passando m:

m é um caractere imprimível 
m é um carac. alfa/numérico 
m é um carac. alfabético
m é uma letra minúscula

Passando / :

/ é um caractere imprimível

Expansão de chaves

O Bash 4.0 incorporou duas novas formas de fazer expansão de chaves:

  • Sequência numérica com preenchimento de zeros à esquerda;
  • Possibilidade de usarmos um incremento (passo) em uma sequência numérica.

Exemplos:

$ echo {0010..0019} # Preenchendo com 2 zeros à esquerda 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 $ echo {05..15} # Preenchendo com zeros à esquerda 05 06 07 08 09 10 11 12 13 14 15 $ echo {-5..19..3} # Incrementando de 3 em 3 (Passo 3) -5 -2 1 4 7 10 13 16 19 $ echo {000..100..10} # Preenchendo com zeros e passo 10 000 010 020 030 040 050 060 070 080 090 100

Qualquer dúvida ou falta de companhia para um chope ou até para falar mal dos políticos é só mandar um e-mail para mim.

Valeu!

 \ No newline at end of file

Revision 1617 Nov 2017 - DediGalihWisnumurti05

Line: 1 to 1
 
META TOPICPARENT name="WebHome"
Changed:
<
<

Snacks

Shell in delicious small pieces


>
>
Dari hari ke hari tugas seorang web marketer adalah meningkatkan popularitas situsnya dengan cara memasang strategi content marketing yang tepat. Aksi yang dilakukan termasuk menyebarkannya lewat social media, registrasi milis, jual beli online, ataupun toko fisik di lokasi. Semua usaha yang dilakukan untuk merubah pengunjung website menjadi pelanggan.
 
Changed:
<
<
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.
>
>
tips Pertama yaitu melalui Search engine optimization (SEO) harus Anda mulai sejak sedini mungkin, hal ini karena seo adalah salah satu investasi jangka panjang. Anda tidak tahu sampai kapan perusahaan anda memiliki budget untuk menjalankan iklan berbayar atau google adwords. perencanaan seo bisa anda mulai sejak proses pembuatan website bisnis sehingga web usaha anda bisa dengan mudah di optimasi nantinya jika sudah seo frindly sedari awal. Bila perlu kerjasama dengan para pemilik layanan Pembuatan Website yang bisa anda percayai dan bagus dalam sisi teknikal dan optimasi dengan benar.
 
Changed:
<
<

Under construction forever


This page, despite being in the scope of the Pub Talk, was never published in Linux Magazine. It is about articles I have written for other media, helpful tips that I read over the internet apart (and in this case with the appropriate credits), contributions of personal of Software Livre wonderful and always ready to help and the unmissable Shell Script List


>
>
Tips kedua agar content marketing Anda sukses adalah menulis isi situs untuk pengunjung Anda, bukan untuk mesin pencari keywords. Saat ini banyak situs bermunculan berisi artikel yang apabila Anda baca penuh dengan berbagai keywords namun kalimatnya tidak berstruktur sehingga tidak mudah untuk dimengerti. Artikel tersebut adalah artikel yang dibuat agar mudah mendongkrak ranking di mesin pencari.
 
Changed:
<
<

Passing parameters with xargs

>
>
Pastikan untuk menyebarkan unggahan Anda ke social media, karena peranan social media telah terbukti membantu pembaca menemukan unggahan Anda. Untuk beberapa orang menyerap informasi lebih mudah dilakukan secara visual. Minta seorang desainer professional infographic untuk mengerjakan content Anda, Infographic merupakan salah satu alternatif terefektif untuk menyampaikan informasi daripada membuatkan satu artikel berisi teks penuh.
 
Changed:
<
<
Has a command whose primary function is to build lists of parameters and pass it to execute other programs or instructions. This command is the xargs and should be used as follows:
>
>
Setelah Anda melakukan cara-cara untuk menarik pengunjung, sangat penting untuk memiliki sistem yang dapat memonitor seberapa efektif usaha yang telah Anda lakukan. Apakah menyebarkan lewat social media lebih efektif daripada infographic, atau sebaliknya.
 
Changed:
<
<
    xargs [command [initial argument]]

The xargs combines the initial argument with the arguments received from standard input, in order to execute the specified command one or more times.

Example:

We will search in all files bellow a given directory a character chain using the find command with the -type f option to search only the normal files, ignoring directories, special files, links, etc., and we make it more generic receiving the name of the inittial directory and the chain to be searched as parameters. To do this:

$ cat grepr # # Grep recursive # Search the character chain defined in $2 from $1 directory # find $1 -type f -print|xargs grep -l "$2"

In executing this script we seek, from the directory defined in the $1 variable, all files that contained the chain defined in the $2 variable.

Exactly the same thing could be done if the line of the program were the following:

    find $1 -type f -exec grep -l "$2" {} \;

The first process has two big disadvantages over the previous:

  • The first is quite visible: the running time of this method is much higher than that, because grep will be made in each file which is passed by find, one-to-one, whereas with xargs, will be past all, or at worst, the most part possible, of the list of files generated by find;

  • Depending on the amount of files found that cater to find, we can win that famous and fateful error message Too many arguments indicating an overflow of the execution stack of the grep. As stated previously, if we use the xargs he will send to grep the highest amount of possible parameters, enough not to cause this error, and if necessary perform the grep more than once.

Pinguim com placa de atenção (em inglês) Hey guys Linux that uses the colorful ls as door dyeing: in the following examples involving this instruction, you should use the option --color=none, if not there are high chances of the results don't occur as expected.

We now consider an example that is more or less the reverse of this we have just seen. This time, let's make a script to remove all files in the current directory, belonging to a particular user.

The first idea that comes up is, as in the previous case, use a command find, as follows:

    find . -user guy -exec rm -f {} \;

Would be almost certain the problem is that this way you not only remove the files from the guy in the current directory, but also all other subdirectories "hanging" in this. Let us see how:

    ls -l | grep " guy " | cut -c55- | xargs rm

Thus, the grep selected files that containing the chain guy in current directory listed by ls -l. The command cut only caught the name of the file, passing them for removal by rm using the xargs command as a bridge.

The xargs is also an excellent tool for creating one-liners (scripts only one line). See more of this to list all owners of files (including their links) "hanging" in the directory /bin and its subdirectories.

$ find /bin -type f -follow | xargs ls -al | tr -s ' ' | cut -f3 -d' ' | sort -u

Often /bin is a link (if I'm not mistaken, Solaris is) and -follows option forces the find following the link. The xargs command feeds the ls -al and the following command sequence is to get only the 3rd field (owner) and sort it returning only once each owner (option -u of the sort command, which equivalent to the uniq command).

Xargs options

You can use xargs options to build extremely powerful commands.

-i option

To illustrate this and begin to understand the main options this Instruction suppose we have to remove all the files with extension .txt in the current directory and display their names on the screen. See what we can do:

$ find . -type f -name "*.txt" | xargs -i bash -c "echo removing {}; rm {}"

The i option of xargs change braces ({}) by the string is receiving by the pipe (|). So in this case the braces ({}) will be replaced by the names of the files they satisfy the find command.

-n option

Look the fun we going to do with xargs:

$ ls | xargs echo > arq.ls $ cat arq.ls arq.ls arq1 arq2 arq3 $ cat arq.ls | xargs -n1 arq.ls arq1 arq2 arq3

When we send the output of ls to the file using xargs, we prove what was said previously, i.e., xargs sends all that is possible (enough not generate a stack overflow) at one time. Then we use a -n 1 option to list one at a time. Just to make sure look at the example below, where we list two on each row:

$ cat arq.ls | xargs -n 2 arq.ls arq1 arq2 arq3

But the row above could (and should) be written without the use pipe (|), as follows:

$ xargs -n 2 < arq.ls

-p option

Another cool of xargs option is the -p, is used to the system ask if you really want to execute the command. Let us say that in a directory you have files with extension .bug and .ok, the .bug are with problems that after corrected will be saved as .ok. Gives a look at the list in this directory:

$ ls dir arq1.bug arq1.ok arq2.bug arq2.ok ... arq9.bug arq9.ok

To compare the good with the bad files, do:

$ ls | xargs -p -n2 diff -c diff -c arq1.bug arq1.ok ?...y .... diff -c arq9.bug arq9.ok ?...y

-t option

Finally, the xargs also have the -t option where will show the instructions that set up before running them. I really like this option to help debug command that was mounted.

Resume

So we can sum up the command according to the following table:

-t   Displays the command line mounted before executing it  
  Option     Action
-i   Replaces the key pair ({}) by chains received  
-nNum   Send the maximum parameters received, up to a maximum of Nun for the command to be executed  
-lNum   Send the maximum rows received, up to a maximum of Nun for the command to be executed  
-p   Displays the command line mounted and asks if you want to run it  

Here Strings

First a programmer with an inferiority complex created the input redirection and represented it with a less than sign (<) to represent their feelings. Then another feeling worse, created the here document representing it by two less than signs (<<) why his sorrow was higher. The third thought, "these two do not know what to feel down"... Then created the here strings represented by three less than signs (<<<).

Jokes aside, the here strings is very useful and do not know why, it is a perfect stranger. In literature there is very little on the subject, we note that the here strings is often cited as a variant of here document, theory with which I disagree because its applicability is quite different from that. Its syntax is simple:

    $ command <<< $chain

Where chain is expanded and feeds the primary input (stdin) of command.

As always, we go straight to the examples of two most common uses for you to draw your own conclusions.

  • Use #1. Replacing the notorious construction echo "chain" | command, which forces a fork, creating a subshell and burdening the runtime.

Examples:

$ a="1 2 3" $ cut -f 2 -d ' ' <<< $a # Normally is done: echo $a | cut -f 2 -d ' ' 2 $ echo $NameArq My Documents # Arrrghhh! $ tr "A-Z " "a-z_" <<< $NomeArq # Replacing the echo $NomeArq | tr "A-Z " "a-z_" my_documents $ bc <<<"3 * 2" 6 $ bc <<<"scale = 4; 22 / 7" 3.1428

To show the improvement in performance, we will make a loop 500 times using the example given for the tr command: See now this sequence of commands with time measures:

$ time for ((i=1; i<= 500; i++)); { tr "A-Z " "a-z_" <<< $NameArq >/dev/null; } real 0m3.508s user 0m2.400s sys 0m1.012s $ time for ((i=1; i<= 500; i++)); { echo $NameArq | tr "A-Z " "a-z_" >/dev/null; } real 0m4.144s user 0m2.684s sys 0m1.392s

See now this sequence of commands with time measures:

$ time for ((i=1;i<=100;i++)); { who | cat > /dev/null; } real 0m1.435s user 0m1.000s sys 0m0.380s $ time for ((i=1;i<=100;i++)); { cat <(who) > /dev/null; } real 0m1.552s user 0m1.052s sys 0m0.448s $ time for ((i=1;i<=100;i++)); { cat <<< $(who) > /dev/null; } real 0m1.514s user 0m1.056s sys 0m0.412s

Observing this box you will see that in the first we used the conventional way, in the second we use a temporary named pipe to run a substitution process and in the third use here strings. You will also notice that unlike the previous example, here the use of here strings was not the fastest. But note well that this last case the command who is running on a subshell and that encumbered the process as a whole.

Let us see a quick way to insert a row as a header file:

$ cat num 1 2 3 4 5 6 7 8 9 10 $ cat - num <<< "Odd Even" Odd Even 1 2 3 4 5 6 7 8 9 10

  • Use #2. Another cool way to use here strings is connecting with a read command, not losing sight of what we learned about IFS (see here, in the explanation of the for command). The cat command with -vet options shows <ENTER> as $, the <TAB> as ^I and other control characters with the notation ^L where L is any letter. Let us look at the contents of a variable and then we read each of your fields:

Examples:

$ echo "$Line" Leonardo Mello (21)3313-1329 $ cat -vet <<< "$Line" Leonardo Mello^I(21)3313-1329$ # The tabs are white and <TAB> (^I) $ read Nom SNom Tel <<< "$Line" $ echo "${Nom}_$S{Nom}_$Tel" # Let's see if it read each of the fields Leonardo_Mello_(21)3313-1329 # Was read because the tabs fit with IFS

We can also read directly into a vector (array) see:

$ echo $Fruits Pear:Grape:Apple $ IFS=: $ echo $Fruits Pear Grape Apple # Without the quotes the shell shows the IFS as blank $ echo "$Fruits" Pear:Grape:Apple # Ahhh, it worked!! $ read -a aFruits <<< "$Fruits" # The -a option of the read command, read to a vector $ for i in 0 1 2 > do > echo ${aFruits[$i]} # Printing each element of the vector > done Pear Grape Apple

Peczenyj Rotational

I was, as I do every day, giving a read in emails in the "List Shell Script" when I saw a "discovery" totally unusual of Tiago Barcellos Peczenyj.

When I decided to create this collection of tips, remembered it and asked him to forward me that email again. The following is the email he sent me, I just enter the last example and took abbreviations.

Julio, I found a way to Shell create combinations making rotation with the indicated elements. We can generate all binaries 0000-1111 as follows:

$ A={0,1} $ eval echo $A$A$A$A 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111

A practical application that I see is to combine different values ​​without having to use the chain loops or seq

$ A={`seq -s , -f "_%g" 3`} $ eval echo -e $A$A$A |tr ' _' '\n ' | grep -vE '.+?(\b[0-9]+\b).+?\1' 1 2 3 1 3 2 2 1 3 2 3 1 3 1 2 3 2 1

In this case I combined the numbers 1-3 eliminating repetitions with grep. I used a tr 'bad' to better handle data, jumping line.

The grep is simple as you can see, I see if a certain part of the combination (. + (.+?(\b[0-9]+\b).+?=) exists in another part (\1), if there is I don't leave print because of the option v so

    1 1 2
    1 2 1
    1 1 1
will not print.

Now here is my example: one-liner below will generate all possible permissions (octal) for file arq (the example was stopped because there are 512 possible combinations of permissions).

$ A={`seq -s , 0 7`} $ eval echo -e $A$A$A | tr ' ' '\n' | xargs -i bash -c "chmod {} arq; ls -l arq" ---------- 1 julio julio 100 2006-11-27 11:50 arq ---------x 1 julio julio 100 2006-11-27 11:50 arq --------w- 1 julio julio 100 2006-11-27 11:50 arq --------wx 1 julio julio 100 2006-11-27 11:50 arq -------r-- 1 julio julio 100 2006-11-27 11:50 arq -------r-x 1 julio julio 100 2006-11-27 11:50 arq -------rw- 1 julio julio 100 2006-11-27 11:50 arq -------rwx 1 julio julio 100 2006-11-27 11:50 arq . . . . . . . . . . . . . . . . . . -rwxrwxrw- 1 julio julio 100 2006-11-27 11:50 arq -rwxrwxrwx 1 julio julio 100 2006-11-27 11:50 arq

Let's see this example step-by-step to understand it:

$ A={`seq -s , 0 7`} $ echo $A {0,1,2,3,4,5,6,7} $ eval echo -e $A$A$A 000 001 002 003 004 005 006 007 010 ... ... 767 770 771 772 773 774 775 776 777 $ eval echo -e $A$A$A | tr ' ' '\n' # The tr will change each space for a <ENTER> 000 001 002 003 . . . 774 775 776 777

Following the xargs ( click to xargs tips executes the bash -c command (serving to run a command line) which in turn executes chmod and ls -l to show that the permissions are changed.

Shell Arithmetic

Formerly we wore the expr command to do arithmetic operations and a lot of people still use, it is compatible with any flavor Shell.

Example:

$ expr 7 \* 5 / 3 # 7 times 5 = 35 divided by 3 = 11 11

In this article however, we will see other ways not so much known, but much simpler to use, more elaborate and more accurately (the bc as we see below has arbitrary precision, i.e. you can use a precision needed to calculate shipping a ship to a satellite of Saturn).

The bc use

A nifty way of doing calculations in Shell – usually used when the arithmetic expression is more complex (as in scientific computing), or when we need to work with decimals – is to use the calculator instruction UNIX/LINUX. The bc. View as:

Example:

$ echo "(2 + 3) * 5" | bc # Parentheses used to give precedence 25

To work with real numbers (not necessarily integers), specify the precision (number of decimal) with scale option bc command. So let's look at the penultimate example:

$ echo "scale=2; 7*5/3" | bc 11.66

Other examples:

$ echo "scale=3; 33.333*3" | bc 99.999 $ num=5 $ echo "scale=2; ((3 + 2) * $num + 4) / 3" | bc 9.66

Obviously all the above examples, in the case of Linux, could (and should) be written using Here Strings. See the latest as would:

$ bc <<< "scale=3; 33.333*3" 99.999 $ num=5 $ bc <<< "scale=2; ((3 + 2) * $num + 4) / 3" 9.66

Once appeared on the Shell script list (excellent by the way) on Yahoo (http://br.groups.yahoo.com/group/shell-script/) a guy with the following question: "I have a file whose fields are separated by <TAB> and the third of them have numbers. How do I calculate the sum of all the numbers in this column of the file?"

I sent the following reply:

$ echo $(cut -f3 num | tr '\n' +)0 | bc 20.1

Let's go by parts to understand it better. First let's see how the file was made ​​for testing:

$ cat num a b 3.2 a z 4.5 w e 9.6 q w 2.8

As you can see, is within the standard problem where I have as third field real numbers. Let's see what would the first part of the command line, where I transform the characters <ENTER> (new-line) on a plus sign (+):

$ cut -f3 num | tr '\n' + 3.2+4.5+9.6+2.8+

If I would send that way to the bc, it would return me an error because of that plus sign (+) released at the end of the text. My solution was to put a zero at the end, because adding zero does not change the result. We'll see then how it fits:

$ echo $(cut -f3 num | tr '\n' +)0 3.2+4.5+9.6+2.8+0

Okay, the problem is solved, but shell always has a little way of writing less code yet. See this:

$ cut -f3 num | paste -sd+ 3.2+4.5+9.6+2.8

I.e., the cut command cut the third column and sends the numbers for a paste, which -s option transform columns into rows and the -d+ defines the plus sign (+) as delimiter. Made it, just send it all to the bc proceed the sum with the real.

$ cut -f3 num | paste -sd+ | bc 20.1

This is what is usually called one-liner, i.e. codes that would be complicated in other languages ​​(usually would need to create counters and make a reading loop adding the third field to the counter) and Shell are written in a single line.

There are also people who call this method KISS, which is the acronym for Keep It Simple Stupid. smile

But the potential use of this calculator does not end there, there are several facilities afforded by it. Look at this example:

$ echo "obase=16; 11579594" | bc B0B0CA? $ echo "ibase=16; B0B0CA?" | bc # B, zero, B, zero, C, e A 11579594

In these examples we have seen how to make changes of base of numbering with using bc. At first we make explicit the base of output (obase) as 16 (hexadecimal) and second, we said that the base of input (ibase) was 10 (decimal).

Other ways to work with integers

Another very cool way to do calculations is to use the notation $((arithmetic exp)). It is good to be aware, however, the fact that this syntax will not be universalized. The Bourne Shell (sh), for example, does not recognize it.

Example:

Using the same example that we have used:

$ echo $(((2+3)*5)) # Parentheses from inside prioritized the 2+3 25

Now just look at this craziness:

$ three=3 $ echo $(((2+three)*5)) # Variable three not preceded by $ 25 $ echo $(((2+$three)*5)) # Variable three not preceded by $ 25

Huh! It is not the dollar sign ($) precedent that features a variable? Yes, but in all UNIX flavors tested, under bash or ksh, both forms of construction produce a good arithmetic.

Pay attention in this sequence:

$ unset i # $i died! $ echo $((i++)) 0 $ echo $i 1 $ echo $((++i)) 2 $ echo $i 2

Note that although the variable not be set because it was made ​​a unset it, none of the commands accused error, because, as we are using arithmetic constructions, whenever a variable does not exist, is initialized to zero (0).

Note that i++ produced zero (0). This is because this type of construction is called post-increment, i.e. firstly the command is executed and only then the variable is incremented. In the case of ++i, a pre-increment was taken: firstly increased and then only after the command was executed.

Are also valid:

$ echo $((i+=3)) 5 $ echo $i 5 $ echo $((i*=3)) 15 $ echo $i 15 $ echo $((i%=2)) 1 $ echo $i 1

These three operations would be the same as:

    i=$((i+3))
    i=$((i*3))
    i=$((i%2))

And this would be true for all arithmetic operators which produce a summary in the following table:

Arithmetic Expansion
||   OR logical
  Expression     Result  
id++ id--   post-increment and post-decrement variable
++id -–id   pre-increment and pre-decrement variable
**   exponentiation
* / %   multiplication, division, remainder of division
+ -   addition, subtraction
<= >= < >   comparison
== !=   equality, inequality
&&   And logical

But the height of this form of construction with double parentheses is as follows:

$ echo $var 50 $ var=$((var>40 ? var-40 : var+40)) $ echo $var 10 $ var=$((var>40 ? var-40 : var+40)) $ echo $var 50

This type of construction should be read as follows: If the variable var is greater than 40 (var>40), then (?) do var equals var less 40 (var-40), if not (:) do var equals var more 40 (var+40). What i meant is that the characters point of interrogation (?) and colon (:) play the role of "then" and "else", thus serving to mount a conditional arithmetic operation.

Similarly we use the expression $((...)) to do arithmetic operations, we could also use the intrinsic (built-in) let or construction type $[...].

The operators are the same for these three types of construction, which varies somewhat is the conditional arithmetic operation with the use of let. Let's see how it would be:

$ echo $var 50 $ let var='var>40 ? var-40 : var+40' $ echo $var 10 $ let var='var>40 ? var-40 : var+40' $ echo $var 50

Baseando

Se você quiser trabalhar com bases diferentes da decimal, basta usar o formato:

    base#numero

Onde base é um número decimal entre 2 e 64 representando o sistema de numeração, e numero é um número no sistema numérico definido por base. Se base# for omitida, então 10 é assumida como default. Os algarismos maiores que 9 são representados por letras minúsculas, maiúsculas, @ e _, nesta ordem.

Se base for menor ou igual a 36, maiúsculas ou minúsculas podem ser usadas indiferentemente para definir algarismos maiores que 9 (não está mal escrito, os algarismos do sistema hexadecimal, por exemplo, variam entre 0 (zero) e F). Vejamos como isso funciona:

$ echo $[2#11] 3 $ echo $((16#a)) 10 $ echo $((16#A)) 10 $ echo $((2#11 + 16#a)) 13 $ echo $[64#a] 10 $ echo $[64#A] 36 $ echo $((64#@)) 62 $ echo $((64#_)) 63

Nestes exemplos usei as notações $((...)) e $[...] indistintamente, para demonstrar que ambas funcionam.

Funciona também uma mudança automática para a base decimal, desde que você esteja usando a convenção numérica do C, isto é, em 0xNN, o NN será tratado como um hexadecimal e em 0NN, o NN será visto como um octal. Veja o exemplo:

Exemplo

$ echo $((10)) # decimal 10 $ echo $((010)) # octal 8 $ echo $((0x10)) # hexadecimal 16 $ echo $((10+010+0x10)) # Decimal + octal + hexadecimal 64

Ah, já ia me esquecendo! As expressões aritméticas com os formatos $((...)), $[...] e com o comando let usam os mesmos operadores usados na instrução expr, além dos operadores unários (++, --, +=, *=, ...) e condicionais que acabamos de ver.

Testes usando expressões regulares

No Papo de Botequim 004, nós falamos tudo sobre comandos condicionais, mas faltou um que não existia àquela época. Neste mesmo Papo de Botequim, na seção E tome de test nós chegamos a falar de uma construção do tipo:

    [[ Expressao ]] && cmd

Onde o comando cmd será executado caso a expressão condicional Expressao seja verdadeira. Disse ainda que Expressao poderia ser estipulada de acordo com as regras de Geração de Nome de Arquivos (File Name Generation). A partir do bash versão 3, foi incorporado a esta forma de teste um operador representado por =~, cuja finalidade é fazer comparações com Expressões Regulares.

Exemplo:

$ echo $BASH_VERSION # Conferindo se a versão do Bash é igual ou superior a 3.0.0 3.2.17(15)-release $ Cargo=Senador $ [[ $Cargo =~ ^(Governa|Sena|Verea)dora?$ ]] && echo É político É político $ Cargo=Senadora $ [[ $Cargo =~ ^(Governa|Sena|Verea)dora?$ ]] && echo É político É político $ Cargo=Diretor $ [[ $Cargo =~ ^(Governa|Sena|Verea)dora?$ ]] && echo É político $

Vamos dar uma esmiuçada na Expressão Regular ^(Governa|Sena|Verea)dora?$: ela casa com tudo que começa (^) por Governa, ou (|) Sena, ou (|) Verea, seguido de dor e seguido de um a opcional (?). O cifrão ($) serve para marcar o fim. Em outras palavras esta Expressão Regular casa com Governador, Senador, Vereador, Governadora, Senadora e Vereadora.

Colorindo a tela

Como você já havia visto no Papo de Botequim 007, o comando tput serve para fazer quase tudo referente a formatação de tela, mas o que não foi dito é que com ele também pode-se usar cores de frente (dos caracteres) e de fundo. Existem também outras formas de fazer o mesmo, acho porém, esta que veremos agora, mais intuitiva (ou menos “desintuitiva”). A tabela a seguir mostra os comandos para especificarmos os padrões de cores de frente (foreground) ou de fundo (background):

Obtendo cores com o comando tput
tput setab n Especifica n como a cor de fundo (background)
  Comando     Efeito  
tput setaf n Especifica n como a cor de frente (foreground)

Bem, agora você já sabe como especificar o par de cores, mas ainda não sabe as cores. A tabela a seguir mostra os valores que o n (da tabela anterior) deve assumir para cada cor:

Valores das cores com o comando tput
7 Cinza claro
  Valor     Cor  
0 Preto
1 Vermelho
2 Verde
3 Marrom
4 Azul
5 Púrpura
6 Ciano

Neste ponto você já pode começar a brincar com as cores.

- Mas peraí, ainda são muito poucas!

- É, tem toda razão... O problema é que ainda não lhe disse que se você colocar o terminal em modo de ênfase (tput bold), estas cores geram outras oito. Vamos montar então a tabela definitiva de cores:

Valores das cores com o comando tput
7 Cinza claro Branco
  Valor     Cor     Cor após tput bold  
0 Preto Cinza escuro
1 Vermelho Vermelho claro
2 Verde Verde claro
3 Marron Amarelo
4 Azul Azul Brilhante
5 Púrpura Rosa
6 Ciano Ciano claro

Exemplo

Como exemplo, vejamos um script que mudará a cor de sua tela de acordo com sua preferência.

$ cat mudacor.sh #!/bin/bash tput sgr0 clear

# Carregando as 8 cores básicas para um vetor Cores=(Preto Vermelho Verde Marrom Azul Púrpura Ciano "Cinza claro")

# Listando o menu de cores echo " Opc Cor = ===" # A linha a seguir significa: para i começando de 1; #+ enquanto i menor ou igual ao tamanho do vetor Cores; #+ incremente o valor de i de 1 em 1 for ((i=1; i<=${#Cores[@]}; i++)) { printf "%02d %s\n" $i "${Cores[i-1]}" }

CL= until [[ $CL == 0[1-8] || $CL == [1-8] ]] do read -p " Escolha a cor da letra: " CL done

# Para quem tem bash a partir da versao 3.2 #+ o test do until acima poderia ser feito #+ usando-se Expressoes Regulares. Veja como: #+ until [[ $CL =~ 0?[1-8] ]] #+ do #+ read -p " #+ Escolha a cor da letra: " CL #+ done

CF= until [[ $CF == 0[1-8] || $CF == [1-8] ]] do read -p " Escolha a cor de fundo: " CF done

let CL-- ; let CF-- # Porque as cores variam de zero a sete tput setaf $CL tput setab $CF clear

Ganhando o jogo com mais coringas

Estava eu lendo meus e-mails quando recebo um do Tiago enviado para a lista de Shell Script (já falei da lista e do Tiago no Rotatório Peczenyj). A seguir o conteúdo do e-mail:

Não sei se é conhecimento de todos mas o shell possui, alem do globbing normal (a expansão *, ? e [a-z] de nomes de arquivos e diretórios), um globbing extendido.

Acho que, em alguns casos, podera ser BEM util, eliminando um pipe para um grep por exemplo.

São eles:

    ?(padrao)
Casa zero ou uma ocorrência de um determinado padrao
    *(padrao)
Casa zero ou mais ocorrências de um determinado padrao
    +(padrao)
Casa uma ou mais ocorrências de um determinado padrao
    @(padrao)
Casa com exatamente uma ocorrência de um determinado padrao
    !(padrao)
Casa com qualquer coisa, exceto com padrao

Para poder utilizá-lo precisa executar o shopt conforme o exemplo abaixo:

$ shopt -s extglob $ ls file filename filenamename fileutils $ ls file?(name) file filename $ ls file*(name) file filename filenamename $ ls file+(name) filename filenamename $ ls file@(name) filename $ ls file!(name) # divertido esse file filenamename fileutils $ ls file+(name|utils) filename filenamename fileutils $ ls file@(name|utils) # "lembra" um {name,utils} filename fileutils

Usando o awk para pesquisar por equivalência

Aí vai mais uma que o Tiago mandou para a lista de Shell Script do Yahoo (já falei da lista e do Tiago no Rotatório Peczenyj e no Ganhando o jogo com mais coringa)

Quem ja não passou por isso: Procurar uma palavra, porém uma letra acentuada, ou não, atrapalhou a busca?

Não descobri como fazer o grep ou sed aceitarem algo semelhante, mas o gawk aceita classes de equivalência!

Melhor explicar com um exemplo, onde vou listar o número da linha e a ocorrência casada:

$ cat dados éco eco èco êco ëco eço $ awk '/^eco/{print NR,$1}' dados 2 eco $ awk '/^e[[=c=]]o/{print NR,$1}' dados 2 eco 6 eço $ awk '/^[[=e=]]co/{print NR,$1}' dados 1 éco 2 eco 3 èco 4 êco 5 ëco

Ou seja, usar [=X=] permite que a expressão encontre a letra X estando acentuada ou não (é sensivel à localização corrente!).

A sintaxe é parecida com a das classes POSIX, trocando os dois-pontos (:) antes e depois da classe por sinais de igual (=).

Achei curioso e deve servir para algum caso semelhante ao descrito.

find – Procurando arquivo por características

Se você está como o Mr. Magoo, procurando em vão um arquivo, use o comando find que serve para procurar arquivos não só pelo nome, como por diversas outras características. Sua sintaxe é a seguinte:

    find [caminho ...] expressão [ação]

Parâmetros:

caminho      Caminhos de diretório a partir do qual (porque ele é recursivo, sempre tentará entrar pelos subdiretórios "pendurados" neste) irá procurar pelos arquivos;
expressão   Define quais critérios de pesquisa. Pode ser uma combinação entre vários tipos de procura;
ação           Define que ação executar com os arquivos que atender aos critérios de pesquisa definidos por expressão.

Principais critérios de pesquisa

-name Procura arquivos que tenham o nome especificado. Aqui podem ser usados metacaracteres ou caracteres curingas, porém estes caracteres deverão estar entre aspas, apóstrofos ou imediatamente precedidos por uma contrabarra isso porque quem tem de expandir os coringas é o find. Se fosse o Shell que os expandisse, isto seria feito somente com relação ao diretório corrente, o que jogaria por terra a característica recursiva do find;
-user Procura arquivos que tenham usuário como dono;
-group Procura arquivos que tenham grupo como grupo dono;
-type c Procura por arquivos que tenham o tipo c, correspondente à letra do tipo do arquivo. Os tipos aceitos estão na tabela a seguir:
Valores de c na opção   acima Tipo de arquivo procurado
b Arquivo especial acessado a bloco
c Arquivo especial acessado a caractere
d Diretório
p Named pipe (FIFO)
f Arquivo normal
l Link simbólico
s Socket
-size ±n[unid] A opção -size procura por arquivos que usam mais (+n) de n unidades unid de espaço ou a menos (-n) de n unidades unid de espaço.
Valores de unid na opção   acima Valor
b Bloco de 512 bytes (valor default)
c Caracteres
k Kilobytes (1024 bytes)
w Palavras (2 bytes)
-atime ±d Procura por arquivos que foram acessados há mais (+d) de d dias ou a menos (-d) de d dias;
-ctime ±d Procura por arquivos cujo status mudou há mais (+d) de d dias ou a menos (-d) de d dias;
-mtime ±d Procura por arquivos cujos dados foram modificados há mais (+d) de d dias ou a menos (-d) de d dias;

Para usar mais de um critério de pesquisa, faça:
     expressão1 expressão2
ou
     expressão1 –a expressão2
para atender aos critérios especificados por expressão1 e expressão2;
     expressão1 –o expressão2
para atender aos critérios especificados por expressão1 ou expressão2.

Principais ações

-print Esta opção faz com que os arquivos encontrados sejam exibidos na tela. Esta é a opção default no Linux. Nos outros sabores Unix que conheço, se nenhuma ação for especificada, ocorrerá um erro;
-exec cmd {} \; Executa o comando cmd. O escopo de comando é considerado encerrado quando um ponto-e-vírgula (;) é encontrado. A cadeia {} é substituída pelo nome de cada arquivo que satisfaz ao critério de pesquisa e a linha assim formada é executada. Assim como foi dito para a opção –name, o ponto-e-vírgula (;) deve ser precedido por uma contrabarra (\), ou deve estar entre aspas ou apóstrofos;
-ok cmd {} \; O mesmo que o anterior porém pergunta se pode executar a instrução cmd sobre cada arquivo que atende ao critério de pesquisa;
-printf formato  A opção -printf permite que se escolha os campos que serão listados e formata a saída de acordo com o especificado em formato.

Exemplos:

Para listar na tela (-print) todos os arquivos, a partir do diretório corrente, terminados por .sh, faça:

$ find . -name \*.sh Ação não especificada –print é default ./undelete.sh ./ntod.sh estes quatro primeiros arquivos foram ./dton.sh encontrados no diretório corrente. ./graph.sh ./tstsh/cotafs.sh ./tstsh/data.sh Estes quatro foram encontrados no ./tstsh/velha.sh diretório tstsh, sob o diretório corrente ./tstsh/charascii.sh

Preciso abrir espaço em um determinado file system com muita urgência, então vou remover arquivos com mais de um megabyte e cujo último acesso foi há mais de 60 dias. Para isso, vou para este file system e faço:

$ find . –type f –size +1000000c –atime +60 –exec rm {} \;

Repare que no exemplo acima usei três critérios de pesquisa, a saber:

-type f Todos os arquivos regulares (normais)
-size +1000000c   Tamanho maior do que 1000000 de caracteres (+1000000c)
-atime +60 Último acesso há mais de 60 (+60) dias.

Repare ainda que entre estes três critérios foi usado o conector e, isto é, arquivos regulares e maiores que 1MByte e sem acesso há mais de 60 dias.

Para listar todos os arquivos do disco terminados por .sh ou .txt, faria:

$ find / -name \*.sh –o –name \*.txt –print

Neste exemplo devemos salientar além das contrabarras (\) antes dos asteriscos (*), o uso do –o para uma ou outra extensão e que o diretório inicial era o raiz (/); assim sendo, esta pesquisa deu-se no disco inteiro (o que freqüentemente é bastante demorado).

Com o printf é possível formatar a saída do comando find e especificar os dados desejados. A formatação do printf é muito semelhante à do mesmo comando na linguagem C e interpreta caracteres de formatação precedidos por um símbolo de percentual (%). Vejamos seus efeitos sobre a formatação:

Caractere Significado
%U Número do usuário (UID) do dono do arquivo
%f Nome do arquivo (caminho completo não aparece)
%F Indica a qual tipo de file system o arquivo pertence
%g Grupo ao qual o arquivo pertence
%G Grupo ao qual o arquivo pertence (GID- Numérico)
%h Caminho completo do arquivo (tudo menos o nome)
%i Número do inode do arquivo (em decimal)
%m Permissão do arquivo (em octal)
%p Nome do arquivo
%s Tamanho do arquivo
%u Nome de usuário (username) do dono do arquivo

Também é possível formatar datas e horas obedecendo às tabelas a seguir:

Caractere Significado
%a Data do último acesso
%c Data de criação
%t Data de alteração

Os três caracteres anteriores produzem uma data semelhante ao do comando date.

Veja um exemplo:

$ find . -name ".b*" -printf '%t %p\n' Mon Nov 29 11:18:51 2004 ./.bash_logout Tue Nov 1 09:44:16 2005 ./.bash_profile Tue Nov 1 09:45:28 2005 ./.bashrc Fri Dec 23 20:32:31 2005 ./.bash_history

Nesse exemplo, o %p foi o responsável por colocar os nomes dos arquivos. Caso fosse omitido, somente as datas seriam listadas. Observe ainda que ao final foi colocado um /n. Sem ele não haveria salto de linha e a listagem anterior seria uma grande tripa.

Essas datas também podem ser formatadas, para isso basta passar as letras da tabela anterior para maiúsculas (%A, %C e %T) e usar um dos formatadores das duas tabelas a seguir:

Tabela de formatação de tempo
Z  Fuso horário (na Cidade Maravilhosa BRST)
  Caractere     Significado  
H  Hora (00..23)
I  Hora (01..12)
k  Hora (0..23)
l  Hora (1..12)
M  Minuto (00..59)
p  AM or PM
r  Horário de 12 horas (hh:mm:ss) seguido de AM ou PM
S  Segundos (00 ... 61)
T  Horário de 24-horas (hh:mm:ss)

Tabela de formatação de datas
Y  Ano com 4 dígitos
  Caractere     Significado  
a  Dia da semana abreviado (Dom...Sab)
A  Dia da semana por extenso (Domingo...Sábado)
b  Nome do mês abreviado (Jan...Dez)
B  Dia do mês por extenso (Janeiro...Dezembro)
c  Data e hora completa (Fri Dec 23 15:21:41 2005)
d  Dia do mês (01...31)
D  Data no formato mm/dd/aa
h  Idêntico a b
j  Dia seqüencial do ano (001…366)
m  Mês (01...12)
U  Semana seqüencial do ano. Domingo como 1º dia da semana (00...53)
w  Dia seqüencial da semana (0..6)
W  Semana seqüencial do ano. Segunda-feira como 1º dia da semana (00...53)
x  Representação da data no formato do país (definido por $LC_ALL)
y  Ano com 2 dígitos (00...99)

Para melhorar a situação, vejamos uns exemplos; porém, vejamos primeiro quais são os arquivos do diretório corrente que começam por .b:

$ ls -la .b* -rw------- 1 d276707 ssup 21419 Dec 26 17:35 .bash_history -rw-r--r-- 1 d276707 ssup 24 Nov 29 2004 .bash_logout -rw-r--r-- 1 d276707 ssup 194 Nov 1 09:44 .bash_profile -rw-r--r-- 1 d276707 ssup 142 Nov 1 09:45 .bashrc

Para listar esses arquivos em ordem de tamanho, podemos fazer:

$ find . -name ".b*" -printf '%s\t%p\n' | sort -n 24 ./.bash_logout 142 ./.bashrc 194 ./.bash_profile 21419 ./.bash_history

No exemplo que acabamos de ver, o \t foi substituído por um na saída de forma a tornar a listagem mais legível. Para listar os mesmos arquivos classificados por data e hora da última alteração:

$ find . -name ".b*" -printf '%TY-%Tm-%Td %TH:%TM:%TS %p\n' | sort 2004-11-29 11:18:51 ./.bash_logout 2005-11-01 09:44:16 ./.bash_profile 2005-11-01 09:45:28 ./.bashrc 2005-12-26 17:35:13 ./.bash_history

Algumas implementações do Bash 4.0

Aqui neste tópico lançarei somente o que é inteiramente novo a partir do Bash 4.0. O que já existia, mas que foi aprimorado a partir desta versão do Bash (como as expansões de parâmetro), está sendo publicado na seção correspondente.

Coprocessos

A partir da versão 4.0, o Bash incorporou o comando coproc. Este novo intrínseco (builtin) permite dois processos assíncronos se comunicarem e interagirem. Como cita Chet Ramey no Bash FAQ, ver. 4.01:

"Há uma nova palavra reservada, coproc, que especifica um coprocesso: um comando assíncrono que é executado com 2 pipes conectados ao Shell criador. coproc pode receber nome. Os descritores dos arquivos de entrada e saída e o PID do coprocesso estão disponíveis para o Shell criador em variáveis com nomes específicos do coproc."

George Dimitriu explica:

"O coproc é uma facilidade usada na substituição de processos que agora está publicamente disponível."

A comprovação do que disse Dimitriu não é complicada, quer ver? Veja a substituição de processos a seguir:

$ cat <(echo xxx; sleep 3; echo yyy; sleep 3)

Viu?! O cat não esperou pela conclusão dos comandos entre parênteses, mas foi executado no fim de cada um deles. Isso aconteceu porque estabeleceu-se um pipe temporário/dinâmico e os comandos que estavam sendo executados, mandavam para ele as suas saídas, que por sua vez as mandava para a entrada do cat.

Isso significa que os comandos desta substituição de processos rodaram paralelos, sincronizando somente nas saídas dos echo com a entrada do cat.

A sintaxe de um coprocesso é:

   coproc [nome] cmd redirecionamentos

Isso criará um coprocesso chamado nome. Se nome for informado, cmd deverá ser um comando composto. Caso contrário (no caso de nome não ser informado), cmd poderá ser um comando simples ou composto.

Quando um coproc é executado, ele cria um vetor com o mesmo nome nome no Shell criador. Sua saída padrão é ligada via um pipe a um descritor de arquivo associado à variável ${nome[0]} à entrada padrão do Shell pai (lembra que a entrada padrão de um processo é sempre associada por default ao descritor zero?). Da mesma forma, a entrada do coproc é ligada à saída padrão do script, via pipe, a um descritor de arquivos chamado ${nome[1]}. Assim, simplificando, vemos que o script mandará dados para o coproc pela variável ${nome[0]}, e receberá sua saída em ${nome[1]}. Note que estes pipes serão criados antes dos redirecionamentos especificados pelo comando, já que eles serão as entradas e saídas do coprocesso.

A partir daqui, vou detalhar rapidamente uns estudos que fiz. Isso contém um pouco de divagações e muita teoria. Se você pular para depois desses ls's, não perderá nada, mas se acompanhar, pode ser bom para a compreensão do mecanismo do coproc.

Após colocar um coproc rodando, se ele está associado a um descritor de arquivo, vamos ver o que tem ativo no diretório correspondente:

$ ls -l /dev/fd lrwxrwxrwx 1 root root 13 2010-01-06 09:31 /dev/fd -> /proc/self/fd

Hummm, é um link para o /proc/self/fd... O que será que tem lá?

$ ls -l /proc/self/fd total 0 lrwx------ 1 julio julio 64 2010-01-06 16:03 0 -> /dev/pts/0 lrwx------ 1 julio julio 64 2010-01-06 16:03 1 -> /dev/pts/0 lrwx------ 1 julio julio 64 2010-01-06 16:03 2 -> /dev/pts/0 lr-x------ 1 julio julio 64 2010-01-06 16:03 3 -> /proc/3127/fd

Epa, que o 0, 1 e 2 apontavam para /dev/pts/0 eu já sabia, pois são a entrada padrão, saída padrão e saída de erros padrão apontando para o pseudo terminal corrente, mas quem será esse maldito device 3? Vejamos:

$ ls -l /proc/$$/fd # $$ É o PID do Shell corrente total 0 lr-x------ 1 julio julio 64 2010-01-06 09:31 0 -> /dev/pts/0 lrwx------ 1 julio julio 64 2010-01-06 09:31 1 -> /dev/pts/0 lrwx------ 1 julio julio 64 2010-01-06 09:31 2 -> /dev/pts/0 lrwx------ 1 julio julio 64 2010-01-06 16:07 255 -> /dev/pts/0 l-wx------ 1 julio julio 64 2010-01-06 16:07 54 -> pipe:[168521] l-wx------ 1 julio julio 64 2010-01-06 16:07 56 -> pipe:[124461] l-wx------ 1 julio julio 64 2010-01-06 16:07 58 -> pipe:[122927] lr-x------ 1 julio julio 64 2010-01-06 16:07 59 -> pipe:[168520] l-wx------ 1 julio julio 64 2010-01-06 16:07 60 -> pipe:[121302] lr-x------ 1 julio julio 64 2010-01-06 16:07 61 -> pipe:[124460] lr-x------ 1 julio julio 64 2010-01-06 16:07 62 -> pipe:[122926] lr-x------ 1 julio julio 64 2010-01-06 16:07 63 -> pipe:[121301]

Epa, aí estão os links apontando para os pipes. Esse monte de arquivo de pipe que foi listado, deve ser porque estava testando exaustivamente essa nova facilidade do Bash.

Para terminar esta teoria chata, falta dizer que o PID do Shell gerado para interpretar o coproc pode ser obtido na variável $nome_PID e o comando wait pode ser usado para esperar pelo fim do coprocesso. O código de retorno do coprocesso ($?) é o mesmo de cmd.

Exemplo:

Vamos começar com o mais simples: um exemplo sem nome e direto no prompt:

$ coproc while read Entra # coproc ativo > do > echo -=-=- $Entra -=-=- > done [2] 3030 $ echo Olá >&${COPROC[1]} # Manda Olá para a pipe da saída $ read -u ${COPROC[0]} Sai # Lê do pipe da entrada $ echo $Sai -=-=- Olá -=-=- $ kill $COPROC_PID # Isso não pode ser esquecido...

Como você viu, o vetor COPROC, está associado a dois pipes; o ${COPROC[1]} que contém o endereço do pipe de saída, e por isso a saída do echo esta redirecionada para ele e o ${COPROC[0]} que contém o endereço do pipe de entrada, e por isso usamos a opção -u do read que lê dados a partir de um descritor de arquivo definido, ao invés da entrada padrão.

Como o coprocesso utilizava a sintaxe sem nome, o padrão do nome do vetor é COPROC.

Só mais uma teoriazinha chata:

$ echo ${COPROC[@]} # Lista todos os elementos do vetor 59 54

Como você viu ${COPROC[0]} estava usando o pipe apontado por /proc/$$/fd/59 e ${COPROC[1]} usava /proc/$$/fd/54. Agora chega de teoria mesmo! Vamos agora usar nome neste mesmo exemplo, para ver que pouca coisa muda:

$ coproc teste { > while read Entra > do > echo -=-=- $Entra -=-=- > done > } [6] 3192 $ echo Olá >&${teste[1]} $ read -u ${teste[0]} Sai $ echo $Sai -=-=- Olá -=-=- $ kill $teste_PID

Nesse momento, é bom mostrar uma coisa interessante: Quais são os processos em execução?

$ ps # Somente no Bash em execução PID TTY TIME CMD 1900 pts/0 00:00:01 bash 2882 pts/0 00:00:00 ps

Vamos executar 2 coprocessos simultâneos:

$ coproc nome1 { # Coprocesso nome1 > while read x > do > echo $x > done; } [1] 2883 $ coproc nome2 { # Coprocesso nome2 > while read y > do > echo $y > done; } bash: aviso: execute_coproc: coproc [2883:nome1] still exists [2] 2884

Xiiii! Acho que deu zebra! Mas será que deu mesmo? Repare que além do PID 2883 de nome1, ele também me devolveu o PID 2884, que deve ser de nome2. Vamos ver o que está acontecendo:

$ ps PID TTY TIME CMD 1900 pts/0 00:00:01 bash Esse já existia 2883 pts/0 00:00:00 bash Esse está executando nome1 2884 pts/0 00:00:00 bash Esse está executando nome2 2885 pts/0 00:00:00 ps

Parece que foi só um aviso, pois os dois PIDs informados quando iniciamos os dois coprocessos, estão ativos. Então vamos testar esses 2 caras:

$ echo xxxxxxxxx >&${nome1[1]} # Mandando cadeia para nome1 $ echo yyyyyyyyy >&${nome2[1]} # Mandando cadeia para nome2 $ read -u ${nome1[0]} Recebe $ echo $Recebe xxxxxxxxx $ read -u ${nome2[0]} Recebe $ echo $Recebe yyyyyyyyy $ kill $nome1_PID $ kill $nome2_PID

Vetores associativos

A partir do Bash 4.0, passou a existir o vetor associativo. Chama-se vetor associativo, aqueles cujos índices são alfabéticos. As regras que valem para os vetores inteiros, valem também para os associativos, porém antes de valorar estes últimos, é obrigatório declará-los.

Exemplo:

$ declare -A Animais # Obrigatório para vetor associativo $ Animais[cavalo]=doméstico $ Animais[zebra]=selvagem $ Animais[gato]=doméstico $ Animais[tigre]=selvagem

Pinguim com placa de atenção É impossível gerar todos os elementos de uma só vez, como nos vetores inteiros. Assim sendo, não funciona a sintaxe:
Animais=([cavalo]=doméstico [zebra]=selvagem  [gato]=doméstico [tigre]=selvagem)

$ echo ${Animais[@]} doméstico selvagem doméstico selvagem $ echo ${!Animais[@]} gato zebra cavalo tigre

Repare que os valores não são ordenados, ficam armazenados na ordem que são criados, diferentemente dos vetores inteiros que ficam em ordem numérica.

Supondo que esse vetor tivesse centenas de elementos, para listar separadamente os domésticos dos selvagens, poderíamos fazer um script assim:

$ cat animal.sh #!/bin/bash # Separa animais selvagens e domésticos declare -A Animais Animais[cavalo]=doméstico # Criando vetor para teste Animais[zebra]=selvagem # Criando vetor para teste Animais[gato]=doméstico # Criando vetor para teste Animais[tigre]=selvagem # Criando vetor para teste Animais[urso pardo]=selvagem # Criando vetor para teste for Animal in "${!Animais[@]}" # Percorrendo vetor pelo índice do if [[ "${Animais[$Animal]}" == selvagem ]] then Sel=("${Sel[@]}" "$Animal") # Gerando vetor p/ selvagens else Dom=("${Dom[@]}" "$Animal") # Gerando vetor p/ domésticos fi done # Operador condicional, usado para descobrir qual #+ vetor tem mais elementos. Veja detalhes na seção #+ O interpretador aritmético do Shell Maior=$[${#Dom[@]}>${#Sel[@]}?${#Dom[@]}:${#Sel[@]}] clear tput bold; printf "%-15s%-15s\n" Domésticos Selvagens; tput sgr0 for ((i=0; i<$Maior; i++)) { tput cup $[1+i] 0; echo ${Dom[i]} tput cup $[1+i] 14; echo ${Sel[i]} }

Gostaria de chamar a sua atenção para um detalhe: neste script me referi a um elemento de vetor associativo empregando ${Animais[$Animal]} ao passo que me referi a um elemento de um vetor inteiro usando ${Sel[i]}. Ou seja, quando usamos uma variável como índice de um vetor inteiro, não precisamos prefixá-la com um cifrão ($), ao passo que no vetor associativo, o cifrão ($) é obrigatório.

Lendo um arquivo para um vetor

Ainda falando do Bash 4.0, eis que ele surge com uma outra novidade: o comando intrínseco (builtin) mapfile, cuja finalidade é jogar um arquivo de texto inteiro para dentro de um vetor, sem loop ou substituição de comando.

    - EPA! Isso deve ser muito rápido!

    - E é. Faça os teste e comprove!

Exemplo:

$ cat frutas abacate maçã morango pera tangerina uva $ mapfile vet < frutas # Mandando frutas para vetor vet $ echo ${vet[@]} # Listando todos elementos de vet abacate maçã morango pera tangerina uva

Obteríamos resultado idêntico se fizéssemos:

$ vet=($(cat frutas))

Porém isso seria mais lento porque a substituição de comando é executada em um subshell. Uma outra forma de fazer isso que logo vem à cabeça é ler o arquivo com a opção -a do comando read. Vamos ver como seria o comportamento disso:

$ read -a vet < frutas $ echo ${vet[@]} abacate

Como deu para perceber, foi lido somente o primeiro registro de frutas.

Caixa baixa para alta e vice versa

Usando expansão de parâmetro

  • ${parâmetro^}
  • ${parâmetro,}
Essas expansões de parâmetros foram introduzidas a partir do Bash 4.0 e modificam a caixa das letras do texto que está sendo expandido. Quando usamos circunflexo (^), a expansão é feita para maiúsculas e quando usamos vírgula (,), a expansão é feita para minúsculas.

Exemplo:

$ Nome="botelho" $ echo ${Nome^} Botelho $ echo ${Nome^^} BOTELHO $ Nome="botelho carvalho" $ echo ${Nome^} Botelho carvalho # É pena que não fique Botelho Carvalho...

Um fragmento de script que pode facilitar a sua vida:

read -p "Deseja continuar (s/n)? "
[[ ${REPLY^} == N ]] && exit

Esta forma evita testarmos se a resposta dada foi um N (maiúsculo) ou um n (minúsculo).

Usando declaratives

Podemos fazer algo parecido, porém de outra maneira. Agora, para termos somente maiúsculas em uma variável também podemos declará-la usando a opção -u ( de uppercase = maiúscula). Veja:

$ declare -u Maiusc

Uma vez assim declarada, veja este exemplo:

$ read -p "Tecle algo: " Maiusc # A variável Maiusc receberá o que for teclado Tecle algo: converte para maiusculas $ echo $Maiusc CONVERTE PARA MAIUSCULAS

O inverso disso seria usarmos a opção -l (de lowercase = minúscula). Veja:

$ declare -l Minusc $ read -p "Tecle algo: " Minusc # A variável Minusc receberá o que for teclado Tecle algo: CONVERTE PARA MINUSCULAS $ echo $Minusc converte para minusculas

Tudo que foi dito sobre estas conversões, só é valido após o declare ter sido feito. Repare:

$ var="xxxx" # Vou atribuir antes de declarar $ declare -u var $ echo $var xxxx # Nada mudou, continua minúscula $ var="xxxx" # Atribuindo após declaração $ echo $var XXXX # Agora funcionou...

Novas implementações no comando case

O bash 4.0 introduziu duas novas facilidades no comando case. A partir desta versão, existem mais dois terminadores de bloco além do ;;, que são: ;;& - Quando um bloco de comandos for encerrado com este terminador, o programa não sairá do case, mas testará os próximos padrões; ;& - Neste caso, o próximo bloco será executado, sem sequer testar o seu padrão.

Exemplo:

Veja este fragmento de código adaptado de http://tldp.org/LDP/abs/html/bashver4.html:

case "$1" in
    [[:print:]] )  echo $1 é um caractere imprimível;;&
    # O terminador ;;& testará o próximo padrão
    [[:alnum:]] )  echo $1 é um carac. alfa/numérico;;&
    [[:alpha:]] )  echo $1 é um carac. alfabético   ;;&
    [[:lower:]] )  echo $1 é uma letra minúscula    ;;&
    [[:digit:]] )  echo $1 é um caractere numérico  ;&
    # O terminador ;& executará o próximo bloco...
    %%%@@@@@    )  echo "************************"  ;;
#   ^^^^^^^^  ... mesmo com um padrão maluco.
esac

A execução deste código passando 3 como parâmetro, resultaria:

3 é um caractere imprimível 
3 é um carac. alfa/numérico 
3 é um caractere numérico
********************************

Passando m:

m é um caractere imprimível 
m é um carac. alfa/numérico 
m é um carac. alfabético
m é uma letra minúscula

Passando / :

/ é um caractere imprimível

Expansão de chaves

O Bash 4.0 incorporou duas novas formas de fazer expansão de chaves:

  • Sequência numérica com preenchimento de zeros à esquerda;
  • Possibilidade de usarmos um incremento (passo) em uma sequência numérica.

Exemplos:

$ echo {0010..0019} # Preenchendo com 2 zeros à esquerda 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 $ echo {05..15} # Preenchendo com zeros à esquerda 05 06 07 08 09 10 11 12 13 14 15 $ echo {-5..19..3} # Incrementando de 3 em 3 (Passo 3) -5 -2 1 4 7 10 13 16 19 $ echo {000..100..10} # Preenchendo com zeros e passo 10 000 010 020 030 040 050 060 070 080 090 100

Qualquer dúvida ou falta de companhia para um chope ou até para falar mal dos políticos é só mandar um e-mail para mim.

Valeu!

>
>
Tips terakhir adalah menjaga konsistensi Anda untuk memberikan update pada pengunjung agar situs Anda tidak hanya untuk sekali kunjung. Seo berhubungan erat dengan konten, semakin unik dan buka copy paste maka kemungkinan landing page bisnis anda bisa mudah naik ke halaman pertama. tentunya link building juga dibutuhkan, tidak perlu secara masif, yang penting backlink target Anda baik, memiliki DA PA tinggi dan lebih baik lagi jika satu niche atau tema web yang sama. Selain seo, anda bisa kombinasikan dengan channel digital marketing lainnya seperti sosial media, email marketing, iklan berbayar atau ppc sosmed. Jasa SEO saat ini sangat banyak, jadi anda tidak perlu takut jika memang tidak memiliki skill digital marketing atau bisa hire tim yang handal di online marketing.
 \ No newline at end of file

Revision 1505 Jun 2014 - Main.AngelaFerreira

Line: 1 to 1
 
META TOPICPARENT name="WebHome"

Snacks

Shell in delicious small pieces

Line: 515 to 515
 2
Changed:
<
<
Repare que apesar da variável não estar definida, pois foi feito um unset nela, nenhum dos comandos acusou erro, porque, como estamos usando construções aritméticas, sempre que uma variável não existe, é inicializada com zero (0).
>
>
Note that although the variable not be set because it was made ​​a unset it, none of the commands accused error, because, as we are using arithmetic constructions, whenever a variable does not exist, is initialized to zero (0).
 
Changed:
<
<
Repare que o i++ produziu zero (0). Isto ocorre porque este tipo de construção chama-se pós-incrementação, isto é, primeiramente o comando é executado e só então a variável é incrementada. No caso do ++i, foi feita uma pré-incrementação: primeiro incrementou e somente após o comando foi executado.
>
>
Note that i++ produced zero (0). This is because this type of construction is called post-increment, i.e. firstly the command is executed and only then the variable is incremented. In the case of ++i, a pre-increment was taken: firstly increased and then only after the command was executed.
 
Changed:
<
<
Também são válidos:
>
>
Are also valid:
 
$ echo $((i+=3))
Line: 536 to 536
 1
Changed:
<
<
Estas três operações seriam o mesmo que:
>
>
These three operations would be the same as:
 
    i=$((i+3))
Line: 544 to 544
  i=$((i%2))
Changed:
<
<
E isto seria válido para todos os operadores aritméticos o que em resumo produziria a tabela a seguir:
>
>
And this would be true for all arithmetic operators which produce a summary in the following table:
 
Changed:
<
<
Expansão Aritmética
||   OU lógico
  Expressão     Resultado  
id++ id--   pós-incremento e pós-decremento de variáveis
++id -–id   pré-incremento e pré-decremento de variáveis
**   exponenciação
* / %   multiplicação, divisão, resto da divisão
+ -   adição, subtração
<= >= < >   comparação
== !=   igualdade, desigualdade
&&   E lógico
>
>
Arithmetic Expansion
||   OR logical
  Expression     Result  
id++ id--   post-increment and post-decrement variable
++id -–id   pre-increment and pre-decrement variable
**   exponentiation
* / %   multiplication, division, remainder of division
+ -   addition, subtraction
<= >= < >   comparison
== !=   equality, inequality
&&   And logical
 
Changed:
<
<
Mas o auge desta forma de construção com duplo parênteses é o seguinte:
>
>
But the height of this form of construction with double parentheses is as follows:
 
$ echo $var
Line: 574 to 574
 50
Changed:
<
<
Este tipo de construção deve ser lido da seguinte forma: caso a variável var seja maior que 40 (var>40), então (?) faça var igual a var menos 40 (var-40), senão (:) faça var igual a var mais 40 (var+40). O que quis dizer é que os caracteres ponto-de-interrogação (?) e dois-pontos (:) fazem o papel de "então" e "senão", servindo desta forma para montar uma operação aritmética condicional.
>
>
This type of construction should be read as follows: If the variable var is greater than 40 (var>40), then (?) do var equals var less 40 (var-40), if not (:) do var equals var more 40 (var+40). What i meant is that the characters point of interrogation (?) and colon (:) play the role of "then" and "else", thus serving to mount a conditional arithmetic operation.
 
Changed:
<
<
Da mesma forma que usamos a expressão $((...)) para fazer operações aritméticas, também poderíamos usar a intrínseca (built-in) let ou construção do tipo $[...].
>
>
Similarly we use the expression $((...)) to do arithmetic operations, we could also use the intrinsic (built-in) let or construction type $[...].
 
Changed:
<
<
Os operadores são os mesmos para estas três formas de construção, o que varia um pouco é a operação aritmética condicional com o uso do let. Vejamos como seria:
>
>
The operators are the same for these three types of construction, which varies somewhat is the conditional arithmetic operation with the use of let. Let's see how it would be:
 
$ echo $var

Revision 1405 Jun 2014 - Main.AngelaFerreira

Line: 1 to 1
 
META TOPICPARENT name="WebHome"

Snacks

Shell in delicious small pieces

Line: 461 to 461
 20.1
Changed:
<
<
Isso é o que se costuma chamar one-liner, isto é, códigos que seriam complicados em outras linguagens (normalmente seria necessário criar contadores e fazer um loop de leitura somando o terceiro campo ao contador) e em Shell são escritos em uma única linha.
>
>
This is what is usually called one-liner, i.e. codes that would be complicated in other languages ​​(usually would need to create counters and make a reading loop adding the third field to the counter) and Shell are written in a single line.
 
Changed:
<
<
Há também gente que chama isso de método KISS, que é o acrônimo de Keep It Simple Stupid. smile
>
>
There are also people who call this method KISS, which is the acronym for Keep It Simple Stupid. smile
 
Changed:
<
<
Mas o potencial de uso desta calculadora não se encerra aí, existem diversas facilidades por ela propiciadas. Veja só este exemplo:
>
>
But the potential use of this calculator does not end there, there are several facilities afforded by it. Look at this example:
 
$ echo "obase=16; 11579594" | bc
Line: 474 to 474
 11579594
Changed:
<
<
Nestes exemplos vimos como fazer mudanças de base de numeração com o uso do bc. Na primeira explicitamos a base de saída (obase) como 16 (hexadecimal) e na segunda, dissemos que a base da entrada (ibase) era 10 (decimal).
>
>
In these examples we have seen how to make changes of base of numbering with using bc. At first we make explicit the base of output (obase) as 16 (hexadecimal) and second, we said that the base of input (ibase) was 10 (decimal).
 
Changed:
<
<

Outras formas de trabalhar com inteiros

>
>

Other ways to work with integers

 
Changed:
<
<
Outra forma muito legal de fazer cálculos é usar a notação $((exp aritmética)). É bom ficar atento, porém, ao fato desta sintaxe não ser universalizada. O Bourne Shell (sh), por exemplo, não a reconhece.
>
>
Another very cool way to do calculations is to use the notation $((arithmetic exp)). It is good to be aware, however, the fact that this syntax will not be universalized. The Bourne Shell (sh), for example, does not recognize it.
 
Changed:
<
<
Exemplo:
>
>
Example:
 
Changed:
<
<
Usando o mesmo exemplo que já havíamos usado:
>
>
Using the same example that we have used:
 
Changed:
<
<
$ echo $(((2+3)*5)) # Os parênteses mais internos priorizaram o 2+3
>
>
$ echo $(((2+3)*5)) # Parentheses from inside prioritized the 2+3
 25
Changed:
<
<
Agora olha só esta maluquice:
>
>
Now just look at this craziness:
 
Changed:
<
<
$ tres=3 $ echo $(((2+tres)*5)) # Variável tres não precedida pelo $
>
>
$ three=3 $ echo $(((2+three)*5)) # Variable three not preceded by $
 25
Changed:
<
<
$ echo $(((2+$tres)*5)) # Variável tres precedida pelo $
>
>
$ echo $(((2+$three)*5)) # Variable three not preceded by $
 25
Changed:
<
<
Ué!! Não é o cifrão ($) precedente que caracteriza uma variável? Sim, porém em todos os sabores UNIX que testei, sob bash ou ksh, ambas as formas de construção produzem uma boa aritmética.
>
>
Huh! It is not the dollar sign (= $ =) precedent that features a variable? Yes, but in all UNIX flavors tested, under bash or ksh, both forms of construction produce a good arithmetic.
 
Changed:
<
<
Preste a atenção nesta seqüência:
>
>
Pay attention in this sequence:
 
Changed:
<
<
$ unset i # $i mooorreu!
>
>
$ unset i # $i died!
 $ echo $((i++)) 0 $ echo $i

Revision 1305 Jun 2014 - Main.AngelaFerreira

Line: 1 to 1
 
META TOPICPARENT name="WebHome"

Snacks

Shell in delicious small pieces

Line: 364 to 364
 777
Changed:
<
<
A seguir o xargs (clique para dicas do xargs) executa o comando bash -c (que serve para executar uma linha de comandos) que por sua vez executa o chmod e o ls -l para mostrar que as permissões estão sendo alteradas.
>
>
Following the xargs ( click to xargs tips executes the bash -c command (serving to run a command line) which in turn executes chmod and ls -l to show that the permissions are changed.
 
Changed:
<
<

Aritmética em Shell

>
>

Shell Arithmetic

 
Changed:
<
<
Antigamente usávamos o comando expr para fazer operações aritméticas e muita gente ainda usa, pois é compatível com qualquer sabor Shell.
>
>
Formerly we wore the expr command to do arithmetic operations and a lot of people still use, it is compatible with any flavor Shell.
 
Changed:
<
<
Exemplo:
>
>
Example:
 
Changed:
<
<
$ expr 7 \* 5 / 3 # 7 vezes 5 = 35 dividido por 3 = 11
>
>
$ expr 7 \* 5 / 3 # 7 times 5 = 35 divided by 3 = 11
 11
Changed:
<
<
Neste artigo porém, vamos ver outras formas não tanto conhecidas, porém mais simples de usar, mais elaboradas e com precisão maior (o bc que veremos a seguir tem precisão arbitrária, isto é, vc pode usar uma precisão necessária ao cálculo de enviar uma nave a um satélite de Saturno).
>
>
In this article however, we will see other ways not so much known, but much simpler to use, more elaborate and more accurately (the bc as we see below has arbitrary precision, i.e. you can use a precision needed to calculate shipping a ship to a satellite of Saturn).
 
Changed:
<
<

O uso do bc

Uma forma bacana de fazer cálculos em Shell – usada normalmente quando a expressão aritmética é mais complexa (como no cálculo científico), ou quando é necessário trabalharmos com casas decimais – é usar a instrução calculadora do UNIX/LINUX. O bc. Veja como:
>
>

The bc use

A nifty way of doing calculations in Shell – usually used when the arithmetic expression is more complex (as in scientific computing), or when we need to work with decimals – is to use the calculator instruction UNIX/LINUX. The bc. View as:
 
Changed:
<
<
Exemplo:
>
>
Example:
 
Changed:
<
<
$ echo "(2 + 3) * 5" | bc # Parênteses usados para dar precedência
>
>
$ echo "(2 + 3) * 5" | bc # Parentheses used to give precedence
 25
Changed:
<
<
Para trabalhar com números reais (números não necessariamente inteiros), especifique a precisão (quantidade de decimais) com a opção scale do comando bc. Assim vejamos o penúltimo exemplo:
>
>
To work with real numbers (not necessarily integers), specify the precision (number of decimal) with scale option bc command. So let's look at the penultimate example:
 
$ echo "scale=2; 7*5/3" | bc 11.66
Changed:
<
<
Outros exemplos:
>
>
Other examples:
 
$ echo "scale=3; 33.333*3" | bc
Line: 404 to 404
 9.66
Changed:
<
<
Obviamente todos os exemplos acima no caso de linux, poderiam (e deveriam) ser escritos usando Here Strings. Veja os últimos como ficariam:
>
>
Obviously all the above examples, in the case of Linux, could (and should) be written using Here Strings. See the latest as would:
 
$ bc <<< "scale=3; 33.333*3"
Line: 414 to 414
 9.66
Changed:
<
<
Uma vez apareceu na lista (excelente por sinal) de Shell script no Yahoo (http://br.groups.yahoo.com/group/shell-script/) um cara com a seguinte dúvida: "eu tenho um arquivo cujos campos estão separados por <TAB> e o terceiro deles possui números. Como posso calcular a soma de todos os números desta coluna do arquivo?"
>
>
Once appeared on the Shell script list (excellent by the way) on Yahoo (http://br.groups.yahoo.com/group/shell-script/) a guy with the following question: "I have a file whose fields are separated by <TAB> and the third of them have numbers. How do I calculate the sum of all the numbers in this column of the file?"
 
Changed:
<
<
Mandei a seguinte resposta:
>
>
I sent the following reply:
 
$ echo $(cut -f3 num | tr '\n' +)0 | bc 20.1
Changed:
<
<
Vamos por partes para entender melhor e primeiramente vamos ver como era o arquivo que fiz para teste:
>
>
Let's go by parts to understand it better. First let's see how the file was made ​​for testing:
 
$ cat num
Line: 433 to 433
 q w 2.8
Changed:
<
<
Como pode-se ver, está dentro do padrão do problema, onde eu tenho como terceiro campo números reais. Vamos ver o que faria a primeira parte da linha de comandos, onde eu transformo os caracteres <ENTER> (new-line) em um sinal de mais (+):
>
>
As you can see, is within the standard problem where I have as third field real numbers. Let's see what would the first part of the command line, where I transform the characters <ENTER> (new-line) on a plus sign (+):
 
$ cut -f3 num | tr '\n' + 3.2+4.5+9.6+2.8+
Changed:
<
<
Se eu mandasse desse jeito para o bc, ele me devolveria um erro por causa daquele sinal de mais (+) solto no final do texto. A minha saída foi colocar um zero no final, pois somando zero o resultado não se alterará. Vamos ver então como ficou:
>
>
If I would send that way to the bc, it would return me an error because of that plus sign (+) released at the end of the text. My solution was to put a zero at the end, because adding zero does not change the result. We'll see then how it fits:
 
$ echo $(cut -f3 num | tr '\n' +)0 3.2+4.5+9.6+2.8+0
Changed:
<
<
Tudo bem, o problema está resolvido, mas em shell sempre tem um jeitinho de se escrever um código menor ainda. Veja isso:
>
>
Okay, the problem is solved, but shell always has a little way of writing less code yet. See this:
 
$ cut -f3 num | paste -sd+ 3.2+4.5+9.6+2.8
Changed:
<
<
Ou seja, o cut corta a terceira coluna e manda os números para um paste, cuja opção -s transforma colunas em linhas e o -d+, define o sinal de mais (+) como delimitador. Feito isso, é só mandar isso tudo para o bc proceder à soma com os reais.
>
>
I.e., the cut command cut the third column and sends the numbers for a paste, which -s option transform columns into rows and the -d+ defines the plus sign (+) as delimiter. Made it, just send it all to the bc proceed the sum with the real.
 
$ cut -f3 num | paste -sd+ | bc
Line: 1489 to 1489
 
Deleted:
<
<
Vou aproveitar também para mandar o meu jabá: diga para os amigos que quem estiver afim de fazer um curso porreta de programação em Shell que mande um e-mail para a nossa gerencia de treinamento para informar-se.
 Qualquer dúvida ou falta de companhia para um chope ou até para falar mal dos políticos é só mandar um e-mail para mim.

Valeu!

Revision 1204 Jun 2014 - Main.AngelaFerreira

Line: 1 to 1
 
META TOPICPARENT name="WebHome"

Snacks

Shell in delicious small pieces

Line: 91 to 91
  xargs -i bash -c "echo removing {}; rm {}"
Changed:
<
<
The i option of xargs change braces ({}) by the chain is receiving by the pipe (|). So in this case the braces ({}) will be replaced by the names of the files they satisfy the find command.
>
>
The i option of xargs change braces ({}) by the string is receiving by the pipe (|). So in this case the braces ({}) will be replaced by the names of the files they satisfy the find command.
 

-n option

Line: 108 to 108
  arq3
Changed:
<
<
When we send the output of ls to the file using xargs, we prove what was said previously, ie, xargs sends all that is possible (enough not generate a stack overflow) at one time. Then we use a -n 1 option to list one at a time. Just to make sure look at the example below, where we list two on each row:
>
>
When we send the output of ls to the file using xargs, we prove what was said previously, i.e., xargs sends all that is possible (enough not generate a stack overflow) at one time. Then we use a -n 1 option to list one at a time. Just to make sure look at the example below, where we list two on each row:
 
$ cat arq.ls | xargs -n 2
Line: 148 to 148
 

-t option

Changed:
<
<
Para finalizar, o xargs também tem a opção -t, onde vai mostrando as instruções que montou antes de executá-las. Gosto muito desta opção para ajudar a depurar o comando que foi montado.
>
>
Finally, the xargs also have the -t option where will show the instructions that set up before running them. I really like this option to help debug command that was mounted.
 

Resume

Line: 197 to 197
 3.1428
Changed:
<
<
To show the improvement in performance, we will make a loop 500 times using the example given for the command = tr =:
>
>
To show the improvement in performance, we will make a loop 500 times using the example given for the tr command:
 See now this sequence of commands with time measures:

Revision 1112 May 2014 - JulioNeves

Line: 1 to 1
 
META TOPICPARENT name="WebHome"

Snacks

Shell in delicious small pieces

Line: 347 to 347
 Let's see this example step-by-step to understand it:

Added:
>
>
$ A={`seq -s , 0 7`}
 $ echo $A {0,1,2,3,4,5,6,7} $ eval echo -e $A$A$A 000 001 002 003 004 005 006 007 010 ... ... 767 770 771 772 773 774 775 776 777
Changed:
<
<
$ eval echo -e $A$A$A | tr ' ' '\n' # O tr trocará cada espaco em branco por um <ENTER>
>
>
$ eval echo -e $A$A$A | tr ' ' '\n' # The tr will change each space for a <ENTER>
 000 001 002

Revision 1006 May 2014 - JulioNeves

Line: 1 to 1
 
META TOPICPARENT name="WebHome"

Snacks

Shell in delicious small pieces

Line: 367 to 367
 

Aritmética em Shell

Changed:
<
<
Antigamente usávamos o comando expr para fazer operações aritméticas e muita gente ainda usa, pois é compatível com quaquer ambiente.
>
>
Antigamente usávamos o comando expr para fazer operações aritméticas e muita gente ainda usa, pois é compatível com qualquer sabor Shell.
  Exemplo:
Line: 375 to 375
 11
Changed:
<
<
Neste artigo porém, vamos ver outras formas não tanto conhecidas, porém mais simples de usar, mais elaboradas e com precisão maior.
>
>
Neste artigo porém, vamos ver outras formas não tanto conhecidas, porém mais simples de usar, mais elaboradas e com precisão maior (o bc que veremos a seguir tem precisão arbitrária, isto é, vc pode usar uma precisão necessária ao cálculo de enviar uma nave a um satélite de Saturno).
 

O uso do bc

Changed:
<
<
Uma forma bacana de fazer cálculos em Shell – usada normalmente quando a expressão aritmética é mais complexa, ou quando é necessário trabalharmos com casas decimais – é usar a instrução calculadora do UNIX/LINUX. O bc. Veja como:
>
>
Uma forma bacana de fazer cálculos em Shell – usada normalmente quando a expressão aritmética é mais complexa (como no cálculo científico), ou quando é necessário trabalharmos com casas decimais – é usar a instrução calculadora do UNIX/LINUX. O bc. Veja como:
  Exemplo:

Revision 905 May 2014 - JulioNeves

Line: 1 to 1
 
META TOPICPARENT name="WebHome"

Snacks

Shell in delicious small pieces

Line: 363 to 363
 777
Changed:
<
<
A seguir o xargs (clique para dicas do xargs) executa o comando bash -c (que serve para executar uma linha de comandos) que por sua vez executa o chmod e o ls -l para mostrar que as permissões estão sendo alteradas.
>
>
A seguir o xargs (clique para dicas do xargs) executa o comando bash -c (que serve para executar uma linha de comandos) que por sua vez executa o chmod e o ls -l para mostrar que as permissões estão sendo alteradas.
 

Aritmética em Shell

Revision 803 May 2014 - Main.AngelaFerreira

Line: 1 to 1
 
META TOPICPARENT name="WebHome"

Snacks

Shell in delicious small pieces

Line: 287 to 287
 Apple
Changed:
<
<

Rotatório Peczenyj

>
>

Peczenyj Rotational

 
Changed:
<
<
Estava, como faço todo dia, dando um lida nos e-mails da "Lista de Shell Script" , quando vi uma "descoberta" totalmente inusitada do Tiago Barcellos Peczenyj.
>
>
I was, as I do every day, giving a read in emails in the "List Shell Script" when I saw a "discovery" totally unusual of Tiago Barcellos Peczenyj.
 
Changed:
<
<
Quando resolvi montar esta coletânea de dicas, me lembrei disso e pedi-lhe para me encaminhar aquele e-mail novamente. O texto a a seguir é o e-mail que ele me mandou, só inseri o último exemplo e tirei as abreviaturas.
>
>
When I decided to create this collection of tips, remembered it and asked him to forward me that email again. The following is the email he sent me, I just enter the last example and took abbreviations.
 
Changed:
<
<
Julio descobri uma forma para o Shell criar combinações fazendo rotação com os elementos estipulados. Podemos gerar todos os binários de 0000 a 1111 da seguinte forma:
>
>
Julio, I found a way to Shell create combinations making rotation with the indicated elements. We can generate all binaries 0000-1111 as follows:
 
$ A={0,1}
Line: 303 to 303
 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111
Changed:
<
<
Uma aplicação pratica que vejo é para combinar valores diferentes sem ter que encadear loops nem usar o seq
>
>
A practical application that I see is to combine different values ​​without having to use the chain loops or seq
 
$ A={`seq -s , -f "_%g" 3`}
Line: 316 to 316
  3 2 1
Changed:
<
<
Neste caso eu combinei os números de 1 a 3 eliminando repetições com o grep. Usei um tr 'podre' para melhor tratar os dados, saltando linha.
>
>
In this case I combined the numbers 1-3 eliminating repetitions with grep. I used a tr 'bad' to better handle data, jumping line.
 
Changed:
<
<
O grep é simples como você pode notar, eu vejo se uma determinada parte da combinação (.+?(\b[0-9]+\b).+?) existe em outra parte (\1), se existe eu não deixo imprimir por causa da opção -v, assim
>
>
The grep is simple as you can see, I see if a certain part of the combination (. + (.+?(\b[0-9]+\b).+?=) exists in another part (\1), if there is I don't leave print because of the option v so
 
    1 1 2
    1 2 1
    1 1 1
Changed:
<
<
não serão impressos.
>
>
will not print.
 
Changed:
<
<
Agora vai o meu exemplo: o one-liner a seguir gerará todas as permissões possíveis (em octal) para o arquivo arq (o exemplo foi interrompido porque existem 512 combinações de permissões possíveis).
>
>
Now here is my example: one-liner below will generate all possible permissions (octal) for file arq (the example was stopped because there are 512 possible combinations of permissions).
 
$ A={`seq -s , 0 7`}
Line: 344 to 344
 -rwxrwxrwx 1 julio julio 100 2006-11-27 11:50 arq
Changed:
<
<
Vamos ver este exemplo passo-a-passo para entendê-lo:
>
>
Let's see this example step-by-step to understand it:
 
$ echo $A

Revision 703 May 2014 - Main.AngelaFerreira

Line: 1 to 1
 
META TOPICPARENT name="WebHome"

Snacks

Shell in delicious small pieces

Line: 258 to 258
 Examples:

Changed:
<
<
$ echo "$Linha"
>
>
$ echo "$Line"
 Leonardo Mello (21)3313-1329
Changed:
<
<
$ cat -vet <<< "$Linha" Leonardo Mello^I(21)3313-1329$ # Os separadores sao branco e <TAB> (^I) $ read Nom SNom Tel <<< "$Linha" $ echo "${Nom}_$S{Nom}_$Tel" # Vamos ver se ele leu cada um dos campos Leonardo_Mello_(21)3313-1329 # Leu porque os separadores casavam com o IFS
>
>
$ cat -vet <<< "$Line" Leonardo Mello^I(21)3313-1329$ # The tabs are white and <TAB> (^I) $ read Nom SNom Tel <<< "$Line" $ echo "${Nom}_$S{Nom}_$Tel" # Let's see if it read each of the fields Leonardo_Mello_(21)3313-1329 # Was read because the tabs fit with IFS
 
Changed:
<
<
Também podemos ler direto para um vetor (array) veja:
>
>
We can also read directly into a vector (array) see:
 
Changed:
<
<
$ echo $Frutas Pera:Uva:Maçã
>
>
$ echo $Fruits Pear:Grape:Apple
 $ IFS=:
Changed:
<
<
$ echo $Frutas Pera Uva Maçã # Sem as aspas o shell mostra o IFS como branco $ echo "$Frutas" Pera:Uva:Maçã # Ahhh, agora sim! $ read -a aFrutas <<< "$Frutas" # A opção -a do read, lê para um vetor
>
>
$ echo $Fruits Pear Grape Apple # Without the quotes the shell shows the IFS as blank $ echo "$Fruits" Pear:Grape:Apple # Ahhh, it worked!! $ read -a aFruits <<< "$Fruits" # The -a option of the read command, read to a vector
 $ for i in 0 1 2 > do
Changed:
<
<
> echo ${aFrutas[$i]} # Imprimindo cada elemento do vetor
>
>
> echo ${aFruits[$i]} # Printing each element of the vector
 > done
Changed:
<
<
Pera Uva Maçã
>
>
Pear Grape Apple
 

Rotatório Peczenyj

Revision 601 May 2014 - Main.AngelaFerreira

Line: 1 to 1
 
META TOPICPARENT name="WebHome"

Snacks

Shell in delicious small pieces

Line: 253 to 253
 9 10
Changed:
<
<
  • Uso #2. Outra forma legal de usar o here strings é casando-o com um comando read, não perdendo de vista o que aprendemos sobre IFS (veja aqui, na explicação do comando for). O comando cat com as opções -vet mostra o <ENTER> como $, o <TAB> como ^I e os outros caracteres de controle com a notação ^L onde L é uma letra qualquer. Vejamos então o conteúdo de uma variável e depois vamos ler cada um de seus campos:
>
>
  • Use #2. Another cool way to use here strings is connecting with a read command, not losing sight of what we learned about IFS (see here, in the explanation of the for command). The cat command with -vet options shows <ENTER> as $, the <TAB> as ^I and other control characters with the notation ^L where L is any letter. Let us look at the contents of a variable and then we read each of your fields:
 
Changed:
<
<
Exemplos:
>
>
Examples:
 
$ echo "$Linha"

Revision 530 Apr 2014 - Main.AngelaFerreira

Line: 1 to 1
 
META TOPICPARENT name="WebHome"

Snacks

Shell in delicious small pieces

Line: 91 to 91
  xargs -i bash -c "echo removing {}; rm {}"
Changed:
<
<
The i option of xargs change key pairs ({}) by the chain is receiving by the pipe (|). So in this case the keys ({}) will be replaced by the names of the files they satisfy the find command.
>
>
The i option of xargs change braces ({}) by the chain is receiving by the pipe (|). So in this case the braces ({}) will be replaced by the names of the files they satisfy the find command.
 

-n option

Line: 166 to 166
 

Here Strings

Changed:
<
<
Primeiro um programador com complexo de inferioridade criou o redirecionamento de entrada e representou-o com um sinal de menor (<) para representar seus sentimento. Em seguida, outro sentindo-se pior ainda, criou o here document representando-o por dois sinais de menor (<<) porque sua fossa era maior. O terceiro, pensou: "estes dois não sabem o que é estar por baixo"... Então criou o here strings representado por três sinais de menor (<<<).
>
>
First a programmer with an inferiority complex created the input redirection and represented it with a less than sign (<) to represent their feelings. Then another feeling worse, created the here document representing it by two less than signs (<<) why his sorrow was higher. The third thought, "these two do not know what to feel down"... Then created the here strings represented by three less than signs (<<<).
 
Changed:
<
<
Brincadeiras a parte, o here strings é utilíssimo e, não sei porque, é um perfeito desconhecido. Na pouquíssima literatura que há sobre o tema, nota-se que o here strings é freqüentemente citado como uma variante do here document, teoria com a qual discordo pois sua aplicabilidade é totalmente diferente daquela. Sua sintaxe é simples:
>
>
Jokes aside, the here strings is very useful and do not know why, it is a perfect stranger. In literature there is very little on the subject, we note that the here strings is often cited as a variant of here document, theory with which I disagree because its applicability is quite different from that. Its syntax is simple:
 
Changed:
<
<
$ comando <<< $cadeia
>
>
$ command <<< $chain
 
Changed:
<
<
Onde cadeia é expandida e alimenta a entrada primária (stdin) de comando.
>
>
Where chain is expanded and feeds the primary input (stdin) of command.
 
Changed:
<
<
Como sempre, vamos direto aos exemplos dos dois usos mais comuns para que vocês próprios tirem suas conclusões.
>
>
As always, we go straight to the examples of two most common uses for you to draw your own conclusions.
 
Changed:
<
<
  • Uso #1. Substituindo a famigerada construção echo "cadeia" | comando, que força um fork, criando um subshell e onerando o tempo de execução.
>
>
  • Use #1. Replacing the notorious construction echo "chain" | command, which forces a fork, creating a subshell and burdening the runtime.
  Examples:

$ a="1 2 3"
Changed:
<
<
$ cut -f 2 -d ' ' <<< $a # Normalmente faz-se: echo $a | cut -f 2 -d ' '
>
>
$ cut -f 2 -d ' ' <<< $a # Normally is done: echo $a | cut -f 2 -d ' '
 2
Changed:
<
<
$ echo $NomeArq Meus Documentos # Arrrghhh! $ tr "A-Z " "a-z_" <<< $NomeArq # Substituindo o echo $NomeArq | tr "A-Z " "a-z_" meus_documentos
>
>
$ echo $NameArq My Documents # Arrrghhh! $ tr "A-Z " "a-z_" <<< $NomeArq # Replacing the echo $NomeArq | tr "A-Z " "a-z_" my_documents
 $ bc <<<"3 * 2" 6 $ bc <<<"scale = 4; 22 / 7" 3.1428
Changed:
<
<
Para mostrar a melhoria no desempenho, vamos fazer um loop de 500 vezes usando o exemplo dados para o comando tr: Veja agora esta seqüência de comandos com medidas de tempo:
>
>
To show the improvement in performance, we will make a loop 500 times using the example given for the command = tr =: See now this sequence of commands with time measures:
 
Changed:
<
<
$ time for ((i=1; i<= 500; i++)); { tr "A-Z " "a-z_" <<< $NomeArq >/dev/null; }
>
>
$ time for ((i=1; i<= 500; i++)); { tr "A-Z " "a-z_" <<< $NameArq >/dev/null; }
  real 0m3.508s user 0m2.400s sys 0m1.012s
Changed:
<
<
$ time for ((i=1; i<= 500; i++)); { echo $NomeArq | tr "A-Z " "a-z_" >/dev/null; }
>
>
$ time for ((i=1; i<= 500; i++)); { echo $NameArq | tr "A-Z " "a-z_" >/dev/null; }
  real 0m4.144s user 0m2.684s sys 0m1.392s
Changed:
<
<
Veja agora esta seqüência de comandos com medidas de tempo:
>
>
See now this sequence of commands with time measures:
 
$ time for ((i=1;i<=100;i++)); { who | cat > /dev/null; }
Line: 233 to 233
 sys 0m0.412s
Changed:
<
<
Observando este quadro você verá que no primeiro usamos a forma convencional, no segundo usamos um named pipe temporário para executar uma substituição de processos e no terceiro usamos here strings. Notará também que ao contrário do exemplo anterior, aqui o uso de here strings não foi o mais veloz. Mas repare bem que neste último caso o comando who está sendo executado em um subshell e isso onerou o processo como um todo.
>
>
Observing this box you will see that in the first we used the conventional way, in the second we use a temporary named pipe to run a substitution process and in the third use here strings. You will also notice that unlike the previous example, here the use of here strings was not the fastest. But note well that this last case the command who is running on a subshell and that encumbered the process as a whole.
 
Changed:
<
<
Vejamos uma forma rápida de inserir uma linha como cabeçalho de um arquivo:
>
>
Let us see a quick way to insert a row as a header file:
 
$ cat num
Line: 244 to 244
 5 6 7 8 9 10
Changed:
<
<
$ cat - num <<< "Impares Pares" Impares Pares
>
>
$ cat - num <<< "Odd Even" Odd Even
 1 2 3 4 5 6

Revision 430 Apr 2014 - Main.AngelaFerreira

Line: 1 to 1
 
META TOPICPARENT name="WebHome"

Snacks

Shell in delicious small pieces

Line: 124 to 124
 

-p option

Changed:
<
<
Outra opção legal do xargs é a -p, na qual o sistema pergunta se você realmente deseja executar o comando. Digamos que em um diretório você tenha arquivos com a extensão .bug e .ok, os .bug estão com problemas que após corrigidos são salvos como .ok. Dá uma olhadinha na listagem deste diretório:
>
>
Another cool of xargs option is the -p, is used to the system ask if you really want to execute the command. Let us say that in a directory you have files with extension .bug and .ok, the .bug are with problems that after corrected will be saved as .ok. Gives a look at the list in this directory:
 
$ ls dir
Line: 137 to 137
 arq9.ok
Changed:
<
<
Para comparar os arquivos bons com os defeituosos, fazemos:
>
>
To compare the good with the bad files, do:
 
$ ls | xargs -p -n2 diff -c
Line: 146 to 146
 diff -c arq9.bug arq9.ok ?...y
Changed:
<
<

Opção -t

>
>

-t option

  Para finalizar, o xargs também tem a opção -t, onde vai mostrando as instruções que montou antes de executá-las. Gosto muito desta opção para ajudar a depurar o comando que foi montado.
Changed:
<
<

Resumo

>
>

Resume

 
Changed:
<
<
Então podemos resumir o comando de acordo com a tabela a seguir:
>
>
So we can sum up the command according to the following table:
 
Changed:
<
<
-t   Mostra a linha de comando montada antes de executá-la  
  Opção     Ação
-i   Substitui o par de chaves ({}) pelas cadeias recebidas  
-nNum   Manda o máximo de parâmetros recebidos, até o máximo de Num para o comando a ser executado  
-lNum   Manda o máximo de linhas recebidas, até o máximo de Num para o comando a ser executado  
-p   Mostra a linha de comando montada e pergunta se deseja executá-la  
>
>
-t   Displays the command line mounted before executing it  
  Option     Action
-i   Replaces the key pair ({}) by chains received  
-nNum   Send the maximum parameters received, up to a maximum of Nun for the command to be executed  
-lNum   Send the maximum rows received, up to a maximum of Nun for the command to be executed  
-p   Displays the command line mounted and asks if you want to run it  
 

Here Strings

Line: 181 to 181
 
  • Uso #1. Substituindo a famigerada construção echo "cadeia" | comando, que força um fork, criando um subshell e onerando o tempo de execução.
Changed:
<
<
Exemplos:
>
>
Examples:
 
$ a="1 2 3"

Revision 330 Apr 2014 - Main.AngelaFerreira

Line: 1 to 1
 
META TOPICPARENT name="WebHome"

Snacks

Shell in delicious small pieces

Line: 95 to 95
 

-n option

Changed:
<
<
Olha só a brincadeira que vamos fazer com o xargs:
>
>
Look the fun we going to do with xargs:
 
$ ls | xargs echo > arq.ls
Line: 108 to 108
  arq3
Changed:
<
<
Quando mandamos a saída do ls para o arquivo usando o xargs, comprovamos o que foi dito anteriormente, isto é, o xargs manda tudo que é possível (o suficiente para não gerar um estouro de pilha) de uma só vez. Em seguida, usamos a opção -n 1 para listar um por vez. Só para dar certeza veja o exemplo a seguir, quando listaremos dois em cada linha:
>
>
When we send the output of ls to the file using xargs, we prove what was said previously, ie, xargs sends all that is possible (enough not generate a stack overflow) at one time. Then we use a -n 1 option to list one at a time. Just to make sure look at the example below, where we list two on each row:
 
$ cat arq.ls | xargs -n 2
Line: 116 to 116
 arq2 arq3
Changed:
<
<
Mas a linha acima poderia (e deveria) ser escrita sem o uso de pipe (|), da seguinte forma:
>
>
But the row above could (and should) be written without the use pipe (|), as follows:
 
$ xargs -n 2 < arq.ls
Changed:
<
<

Opção -p

>
>

-p option

  Outra opção legal do xargs é a -p, na qual o sistema pergunta se você realmente deseja executar o comando. Digamos que em um diretório você tenha arquivos com a extensão .bug e .ok, os .bug estão com problemas que após corrigidos são salvos como .ok. Dá uma olhadinha na listagem deste diretório:

Revision 230 Apr 2014 - Main.AngelaFerreira

Line: 1 to 1
 
META TOPICPARENT name="WebHome"
Changed:
<
<

Tira Gosto

Shell em pedaços pequenos e gostosos

>
>

Snacks

Shell in delicious small pieces

 
Changed:
<
<

Em construção para sempre

>
>
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.

Under construction forever

 
Changed:
<
<
Esta página, apesar de estar no escopo do Papo de Botequim, nunca foi publicada na Linux Magazine. Trata-se de artigos que escrevi para outras mídias, dicas úteis que li pela internet afora (e neste caso com os devidos créditos), contribuições deste pessoal do Software Livre, maravilhoso e sempre pronto a ajudar e da imperdível Lista de Shell Script
>
>
This page, despite being in the scope of the Pub Talk, was never published in Linux Magazine. It is about articles I have written for other media, helpful tips that I read over the internet apart (and in this case with the appropriate credits), contributions of personal of Software Livre wonderful and always ready to help and the unmissable Shell Script List
 


Changed:
<
<

Passando parâmetros com xargs

>
>

Passing parameters with xargs

 
Changed:
<
<
Existe um comando, cuja função primordial é construir listas de parâmetros e passá-la para a execução de outros programas ou instruções. Este comando é o xargs e deve ser usado da seguinte maneira:
>
>
Has a command whose primary function is to build lists of parameters and pass it to execute other programs or instructions. This command is the xargs and should be used as follows:
 
Changed:
<
<
xargs [comando [argumento inicial]]
>
>
xargs [command [initial argument]]
 
Changed:
<
<
O xargs combina o argumento inicial com os argumentos recebidos da entrada padrão, de forma a executar o comando especificado uma ou mais vezes.
>
>
The xargs combines the initial argument with the arguments received from standard input, in order to execute the specified command one or more times.
 
Changed:
<
<
Exemplo:
>
>
Example:
 
Changed:
<
<
Vamos procurar em todos os arquivos abaixo de um determinado diretório uma cadeia de caracteres usando o comando find com a opção -type f para pesquisar somente os arquivos normais, desprezando diretórios, arquivos especiais, arquivos de ligações, etc, e vamos torná-la mais genérica recebendo o nome do diretório inicial e a cadeia a ser pesquisada como parâmetros. Para isso fazemos:
>
>
We will search in all files bellow a given directory a character chain using the find command with the -type f option to search only the normal files, ignoring directories, special files, links, etc., and we make it more generic receiving the name of the inittial directory and the chain to be searched as parameters. To do this:
 
$ cat grepr #
Changed:
<
<
# Grep recursivo # Pesquisa a cadeia de caracteres definida em $2 a partir do diretorio $1
>
>
# Grep recursive # Search the character chain defined in $2 from $1 directory
 # find $1 -type f -print|xargs grep -l "$2"
Changed:
<
<
Na execução deste script procuramos, a partir do diretório definido na variável $1, todos os arquivos que continham a cadeia definida na variável $2.
>
>
In executing this script we seek, from the directory defined in the $1 variable, all files that contained the chain defined in the $2 variable.
 
Changed:
<
<
Exatamente a mesma coisa poderia ser feito se a linha do programa fosse a seguinte:
>
>
Exactly the same thing could be done if the line of the program were the following:
 
    find $1 -type f -exec grep -l "$2" {} \;
Changed:
<
<
O primeiro processo tem duas grandes desvantagens sobre o anterior:
>
>
The first process has two big disadvantages over the previous:
 
Changed:
<
<
  • A primeira é bastante visível: o tempo de execução deste método é muito superior ao daquele, isso porque o grep será feito em cada arquivo que lhe for passado pelo find, um-a-um, ao passo que com o xargs, será passada toda, ou na pior das hipóteses, a maior parte possível, da lista de arquivos gerada pelo find;
>
>
  • The first is quite visible: the running time of this method is much higher than that, because grep will be made in each file which is passed by find, one-to-one, whereas with xargs, will be past all, or at worst, the most part possible, of the list of files generated by find;
 
Changed:
<
<
  • Dependendo da quantidade de arquivos encontrados que atendem ao find, poderemos ganhar aquela famosa e fatídica mensagem de erro Too many arguments indicando um estouro da pilha de execução do grep. Como foi dito no item anterior, se usarmos o xargs ele passará para o grep a maior quantidade de parâmetros possível, suficiente para não causar este erro, e caso necessário executará o grep mais de uma vez.
>
>
  • Depending on the amount of files found that cater to find, we can win that famous and fateful error message Too many arguments indicating an overflow of the execution stack of the grep. As stated previously, if we use the xargs he will send to grep the highest amount of possible parameters, enough not to cause this error, and if necessary perform the grep more than once.
 
Changed:
<
<
Pinguim com placa de atenção Aê pessoal do linux que usa o ls colorido que nem porta de tinturaria: nos exemplos a seguir que envolvem esta instrução, você devem usar a opção --color=none, senão existem grandes chances dos resultados não ocorrerem como o esperado.
>
>
Pinguim com placa de atenção (em inglês) Hey guys Linux that uses the colorful ls as door dyeing: in the following examples involving this instruction, you should use the option --color=none, if not there are high chances of the results don't occur as expected.
 
Changed:
<
<
Vamos agora analisar um exemplo que é mais ou menos o inverso deste que acabamos de ver. Desta vez, vamos fazer um script para remover todos os arquivos do diretório corrente, pertencentes a um determinado usuário.
>
>
We now consider an example that is more or less the reverse of this we have just seen. This time, let's make a script to remove all files in the current directory, belonging to a particular user.
 
Changed:
<
<
A primeira idéia que surge é, como no caso anterior, usar um comando find, da seguinte maneira:
>
>
The first idea that comes up is, as in the previous case, use a command find, as follows:
 
Changed:
<
<
find . -user cara -exec rm -f {} \;
>
>
find . -user guy -exec rm -f {} \;
 
Changed:
<
<
Quase estaria certo, o problema é que desta forma você removeria não só os arquivos do cara no diretório corrente, mas também de todos os outros subdiretórios "pendurados" neste. Vejamos então como fazer:
>
>
Would be almost certain the problem is that this way you not only remove the files from the guy in the current directory, but also all other subdirectories "hanging" in this. Let us see how:
 
Changed:
<
<
ls -l | grep " cara " | cut -c55- | xargs rm
>
>
ls -l | grep " guy " | cut -c55- | xargs rm
 
Changed:
<
<
Desta forma, o grep selecionou os arquivos que continham a cadeia cara no diretório corrente listado pelo ls -l. O comando cut pegou somente o nome dos arquivos, passando-os para a remoção pelo rm usando o comando xargs como ponte
>
>
Thus, the grep selected files that containing the chain guy in current directory listed by ls -l. The command cut only caught the name of the file, passing them for removal by rm using the xargs command as a bridge.
 
Changed:
<
<
O xargs é também uma excelente ferramenta de criação de one-liners (scripts de somente uma linha). Veja este para listar todos os donos de arquivos (inclusive seus links) "pendurados" no diretório /bin e seus subdiretórios.
>
>
The xargs is also an excellent tool for creating one-liners (scripts only one line). See more of this to list all owners of files (including their links) "hanging" in the directory /bin and its subdirectories.
 
$ find /bin -type f -follow | xargs ls -al | tr -s ' ' | cut -f3 -d' ' | sort -u
Changed:
<
<
Muitas vezes o /bin é um link (se não me engano, no Solaris o é) e a opção -follows obriga o find a seguir o link. O comando xargs alimenta o ls -al e a seqüência de comandos seguinte é para pegar somente o 3º campo (dono) e classificá-lo devolvendo somente uma vez cada dono (opção -u do comando sort, que equivale ao comando uniq).
>
>
Often /bin is a link (if I'm not mistaken, Solaris is) and -follows option forces the find following the link. The xargs command feeds the ls -al and the following command sequence is to get only the 3rd field (owner) and sort it returning only once each owner (option -u of the sort command, which equivalent to the uniq command).
 
Changed:
<
<

Opções do xargs

Você pode usar as opções do xargs para construir comandos extremamente poderosos.
>
>

Xargs options

You can use xargs options to build extremely powerful commands.
 
Changed:
<
<

Opção -i

>
>

-i option

 
Changed:
<
<
Para exemplificar isso e começar a entender as principais opções desta instrução, vamos supor que temos que remover todos as arquivos com extensão .txt sob o diretório corrente e apresentar os seus nomes na tela. Veja o que podemos fazer:
>
>
To illustrate this and begin to understand the main options this Instruction suppose we have to remove all the files with extension .txt in the current directory and display their names on the screen. See what we can do:
 
$ find . -type f -name "*.txt" |
Changed:
<
<
xargs -i bash -c "echo removendo {}; rm {}"
>
>
xargs -i bash -c "echo removing {}; rm {}"
 
Changed:
<
<
A opção -i do xargs troca pares de chaves ({}) pela cadeia que está recebendo pelo pipe (|). Então neste caso as chaves ({}) serão trocadas pelos nomes dos arquivos que satifaçam ao comando find.
>
>
The i option of xargs change key pairs ({}) by the chain is receiving by the pipe (|). So in this case the keys ({}) will be replaced by the names of the files they satisfy the find command.
 
Changed:
<
<

Opção -n

>
>

-n option

  Olha só a brincadeira que vamos fazer com o xargs:

Revision 129 Apr 2014 - Main.AngelaFerreira

Line: 1 to 1
Added:
>
>
META TOPICPARENT name="WebHome"

Tira Gosto

Shell em pedaços pequenos e gostosos


Em construção para sempre


Esta página, apesar de estar no escopo do Papo de Botequim, nunca foi publicada na Linux Magazine. Trata-se de artigos que escrevi para outras mídias, dicas úteis que li pela internet afora (e neste caso com os devidos créditos), contribuições deste pessoal do Software Livre, maravilhoso e sempre pronto a ajudar e da imperdível Lista de Shell Script

Passando parâmetros com xargs

Existe um comando, cuja função primordial é construir listas de parâmetros e passá-la para a execução de outros programas ou instruções. Este comando é o xargs e deve ser usado da seguinte maneira:

    xargs [comando [argumento inicial]]

O xargs combina o argumento inicial com os argumentos recebidos da entrada padrão, de forma a executar o comando especificado uma ou mais vezes.

Exemplo:

Vamos procurar em todos os arquivos abaixo de um determinado diretório uma cadeia de caracteres usando o comando find com a opção -type f para pesquisar somente os arquivos normais, desprezando diretórios, arquivos especiais, arquivos de ligações, etc, e vamos torná-la mais genérica recebendo o nome do diretório inicial e a cadeia a ser pesquisada como parâmetros. Para isso fazemos:

$ cat grepr # # Grep recursivo # Pesquisa a cadeia de caracteres definida em $2 a partir do diretorio $1 # find $1 -type f -print|xargs grep -l "$2"

Na execução deste script procuramos, a partir do diretório definido na variável $1, todos os arquivos que continham a cadeia definida na variável $2.

Exatamente a mesma coisa poderia ser feito se a linha do programa fosse a seguinte:

    find $1 -type f -exec grep -l "$2" {} \;

O primeiro processo tem duas grandes desvantagens sobre o anterior:

  • A primeira é bastante visível: o tempo de execução deste método é muito superior ao daquele, isso porque o grep será feito em cada arquivo que lhe for passado pelo find, um-a-um, ao passo que com o xargs, será passada toda, ou na pior das hipóteses, a maior parte possível, da lista de arquivos gerada pelo find;

  • Dependendo da quantidade de arquivos encontrados que atendem ao find, poderemos ganhar aquela famosa e fatídica mensagem de erro Too many arguments indicando um estouro da pilha de execução do grep. Como foi dito no item anterior, se usarmos o xargs ele passará para o grep a maior quantidade de parâmetros possível, suficiente para não causar este erro, e caso necessário executará o grep mais de uma vez.

Pinguim com placa de atenção Aê pessoal do linux que usa o ls colorido que nem porta de tinturaria: nos exemplos a seguir que envolvem esta instrução, você devem usar a opção --color=none, senão existem grandes chances dos resultados não ocorrerem como o esperado.

Vamos agora analisar um exemplo que é mais ou menos o inverso deste que acabamos de ver. Desta vez, vamos fazer um script para remover todos os arquivos do diretório corrente, pertencentes a um determinado usuário.

A primeira idéia que surge é, como no caso anterior, usar um comando find, da seguinte maneira:

    find . -user cara -exec rm -f {} \;

Quase estaria certo, o problema é que desta forma você removeria não só os arquivos do cara no diretório corrente, mas também de todos os outros subdiretórios "pendurados" neste. Vejamos então como fazer:

    ls -l | grep " cara " | cut -c55- | xargs rm

Desta forma, o grep selecionou os arquivos que continham a cadeia cara no diretório corrente listado pelo ls -l. O comando cut pegou somente o nome dos arquivos, passando-os para a remoção pelo rm usando o comando xargs como ponte

O xargs é também uma excelente ferramenta de criação de one-liners (scripts de somente uma linha). Veja este para listar todos os donos de arquivos (inclusive seus links) "pendurados" no diretório /bin e seus subdiretórios.

$ find /bin -type f -follow | xargs ls -al | tr -s ' ' | cut -f3 -d' ' | sort -u

Muitas vezes o /bin é um link (se não me engano, no Solaris o é) e a opção -follows obriga o find a seguir o link. O comando xargs alimenta o ls -al e a seqüência de comandos seguinte é para pegar somente o 3º campo (dono) e classificá-lo devolvendo somente uma vez cada dono (opção -u do comando sort, que equivale ao comando uniq).

Opções do xargs

Você pode usar as opções do xargs para construir comandos extremamente poderosos.

Opção -i

Para exemplificar isso e começar a entender as principais opções desta instrução, vamos supor que temos que remover todos as arquivos com extensão .txt sob o diretório corrente e apresentar os seus nomes na tela. Veja o que podemos fazer:

$ find . -type f -name "*.txt" | xargs -i bash -c "echo removendo {}; rm {}"

A opção -i do xargs troca pares de chaves ({}) pela cadeia que está recebendo pelo pipe (|). Então neste caso as chaves ({}) serão trocadas pelos nomes dos arquivos que satifaçam ao comando find.

Opção -n

Olha só a brincadeira que vamos fazer com o xargs:

$ ls | xargs echo > arq.ls $ cat arq.ls arq.ls arq1 arq2 arq3 $ cat arq.ls | xargs -n1 arq.ls arq1 arq2 arq3

Quando mandamos a saída do ls para o arquivo usando o xargs, comprovamos o que foi dito anteriormente, isto é, o xargs manda tudo que é possível (o suficiente para não gerar um estouro de pilha) de uma só vez. Em seguida, usamos a opção -n 1 para listar um por vez. Só para dar certeza veja o exemplo a seguir, quando listaremos dois em cada linha:

$ cat arq.ls | xargs -n 2 arq.ls arq1 arq2 arq3

Mas a linha acima poderia (e deveria) ser escrita sem o uso de pipe (|), da seguinte forma:

$ xargs -n 2 < arq.ls

Opção -p

Outra opção legal do xargs é a -p, na qual o sistema pergunta se você realmente deseja executar o comando. Digamos que em um diretório você tenha arquivos com a extensão .bug e .ok, os .bug estão com problemas que após corrigidos são salvos como .ok. Dá uma olhadinha na listagem deste diretório:

$ ls dir arq1.bug arq1.ok arq2.bug arq2.ok ... arq9.bug arq9.ok

Para comparar os arquivos bons com os defeituosos, fazemos:

$ ls | xargs -p -n2 diff -c diff -c arq1.bug arq1.ok ?...y .... diff -c arq9.bug arq9.ok ?...y

Opção -t

Para finalizar, o xargs também tem a opção -t, onde vai mostrando as instruções que montou antes de executá-las. Gosto muito desta opção para ajudar a depurar o comando que foi montado.

Resumo

Então podemos resumir o comando de acordo com a tabela a seguir:

-t   Mostra a linha de comando montada antes de executá-la  
  Opção     Ação
-i   Substitui o par de chaves ({}) pelas cadeias recebidas  
-nNum   Manda o máximo de parâmetros recebidos, até o máximo de Num para o comando a ser executado  
-lNum   Manda o máximo de linhas recebidas, até o máximo de Num para o comando a ser executado  
-p   Mostra a linha de comando montada e pergunta se deseja executá-la  

Here Strings

Primeiro um programador com complexo de inferioridade criou o redirecionamento de entrada e representou-o com um sinal de menor (<) para representar seus sentimento. Em seguida, outro sentindo-se pior ainda, criou o here document representando-o por dois sinais de menor (<<) porque sua fossa era maior. O terceiro, pensou: "estes dois não sabem o que é estar por baixo"... Então criou o here strings representado por três sinais de menor (<<<).

Brincadeiras a parte, o here strings é utilíssimo e, não sei porque, é um perfeito desconhecido. Na pouquíssima literatura que há sobre o tema, nota-se que o here strings é freqüentemente citado como uma variante do here document, teoria com a qual discordo pois sua aplicabilidade é totalmente diferente daquela. Sua sintaxe é simples:

    $ comando <<< $cadeia

Onde cadeia é expandida e alimenta a entrada primária (stdin) de comando.

Como sempre, vamos direto aos exemplos dos dois usos mais comuns para que vocês próprios tirem suas conclusões.

  • Uso #1. Substituindo a famigerada construção echo "cadeia" | comando, que força um fork, criando um subshell e onerando o tempo de execução.

Exemplos:

$ a="1 2 3" $ cut -f 2 -d ' ' <<< $a # Normalmente faz-se: echo $a | cut -f 2 -d ' ' 2 $ echo $NomeArq Meus Documentos # Arrrghhh! $ tr "A-Z " "a-z_" <<< $NomeArq # Substituindo o echo $NomeArq | tr "A-Z " "a-z_" meus_documentos $ bc <<<"3 * 2" 6 $ bc <<<"scale = 4; 22 / 7" 3.1428

Para mostrar a melhoria no desempenho, vamos fazer um loop de 500 vezes usando o exemplo dados para o comando tr: Veja agora esta seqüência de comandos com medidas de tempo:

$ time for ((i=1; i<= 500; i++)); { tr "A-Z " "a-z_" <<< $NomeArq >/dev/null; } real 0m3.508s user 0m2.400s sys 0m1.012s $ time for ((i=1; i<= 500; i++)); { echo $NomeArq | tr "A-Z " "a-z_" >/dev/null; } real 0m4.144s user 0m2.684s sys 0m1.392s

Veja agora esta seqüência de comandos com medidas de tempo:

$ time for ((i=1;i<=100;i++)); { who | cat > /dev/null; } real 0m1.435s user 0m1.000s sys 0m0.380s $ time for ((i=1;i<=100;i++)); { cat <(who) > /dev/null; } real 0m1.552s user 0m1.052s sys 0m0.448s $ time for ((i=1;i<=100;i++)); { cat <<< $(who) > /dev/null; } real 0m1.514s user 0m1.056s sys 0m0.412s

Observando este quadro você verá que no primeiro usamos a forma convencional, no segundo usamos um named pipe temporário para executar uma substituição de processos e no terceiro usamos here strings. Notará também que ao contrário do exemplo anterior, aqui o uso de here strings não foi o mais veloz. Mas repare bem que neste último caso o comando who está sendo executado em um subshell e isso onerou o processo como um todo.

Vejamos uma forma rápida de inserir uma linha como cabeçalho de um arquivo:

$ cat num 1 2 3 4 5 6 7 8 9 10 $ cat - num <<< "Impares Pares" Impares Pares 1 2 3 4 5 6 7 8 9 10

  • Uso #2. Outra forma legal de usar o here strings é casando-o com um comando read, não perdendo de vista o que aprendemos sobre IFS (veja aqui, na explicação do comando for). O comando cat com as opções -vet mostra o <ENTER> como $, o <TAB> como ^I e os outros caracteres de controle com a notação ^L onde L é uma letra qualquer. Vejamos então o conteúdo de uma variável e depois vamos ler cada um de seus campos:

Exemplos:

$ echo "$Linha" Leonardo Mello (21)3313-1329 $ cat -vet <<< "$Linha" Leonardo Mello^I(21)3313-1329$ # Os separadores sao branco e <TAB> (^I) $ read Nom SNom Tel <<< "$Linha" $ echo "${Nom}_$S{Nom}_$Tel" # Vamos ver se ele leu cada um dos campos Leonardo_Mello_(21)3313-1329 # Leu porque os separadores casavam com o IFS

Também podemos ler direto para um vetor (array) veja:

$ echo $Frutas Pera:Uva:Maçã $ IFS=: $ echo $Frutas Pera Uva Maçã # Sem as aspas o shell mostra o IFS como branco $ echo "$Frutas" Pera:Uva:Maçã # Ahhh, agora sim! $ read -a aFrutas <<< "$Frutas" # A opção -a do read, lê para um vetor $ for i in 0 1 2 > do > echo ${aFrutas[$i]} # Imprimindo cada elemento do vetor > done Pera Uva Maçã

Rotatório Peczenyj

Estava, como faço todo dia, dando um lida nos e-mails da "Lista de Shell Script" , quando vi uma "descoberta" totalmente inusitada do Tiago Barcellos Peczenyj.

Quando resolvi montar esta coletânea de dicas, me lembrei disso e pedi-lhe para me encaminhar aquele e-mail novamente. O texto a a seguir é o e-mail que ele me mandou, só inseri o último exemplo e tirei as abreviaturas.

Julio descobri uma forma para o Shell criar combinações fazendo rotação com os elementos estipulados. Podemos gerar todos os binários de 0000 a 1111 da seguinte forma:

$ A={0,1} $ eval echo $A$A$A$A 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111

Uma aplicação pratica que vejo é para combinar valores diferentes sem ter que encadear loops nem usar o seq

$ A={`seq -s , -f "_%g" 3`} $ eval echo -e $A$A$A |tr ' _' '\n ' | grep -vE '.+?(\b[0-9]+\b).+?\1' 1 2 3 1 3 2 2 1 3 2 3 1 3 1 2 3 2 1

Neste caso eu combinei os números de 1 a 3 eliminando repetições com o grep. Usei um tr 'podre' para melhor tratar os dados, saltando linha.

O grep é simples como você pode notar, eu vejo se uma determinada parte da combinação (.+?(\b[0-9]+\b).+?) existe em outra parte (\1), se existe eu não deixo imprimir por causa da opção -v, assim

    1 1 2
    1 2 1
    1 1 1
não serão impressos.

Agora vai o meu exemplo: o one-liner a seguir gerará todas as permissões possíveis (em octal) para o arquivo arq (o exemplo foi interrompido porque existem 512 combinações de permissões possíveis).

$ A={`seq -s , 0 7`} $ eval echo -e $A$A$A | tr ' ' '\n' | xargs -i bash -c "chmod {} arq; ls -l arq" ---------- 1 julio julio 100 2006-11-27 11:50 arq ---------x 1 julio julio 100 2006-11-27 11:50 arq --------w- 1 julio julio 100 2006-11-27 11:50 arq --------wx 1 julio julio 100 2006-11-27 11:50 arq -------r-- 1 julio julio 100 2006-11-27 11:50 arq -------r-x 1 julio julio 100 2006-11-27 11:50 arq -------rw- 1 julio julio 100 2006-11-27 11:50 arq -------rwx 1 julio julio 100 2006-11-27 11:50 arq . . . . . . . . . . . . . . . . . . -rwxrwxrw- 1 julio julio 100 2006-11-27 11:50 arq -rwxrwxrwx 1 julio julio 100 2006-11-27 11:50 arq

Vamos ver este exemplo passo-a-passo para entendê-lo:

$ echo $A {0,1,2,3,4,5,6,7} $ eval echo -e $A$A$A 000 001 002 003 004 005 006 007 010 ... ... 767 770 771 772 773 774 775 776 777 $ eval echo -e $A$A$A | tr ' ' '\n' # O tr trocará cada espaco em branco por um <ENTER> 000 001 002 003 . . . 774 775 776 777

A seguir o xargs (clique para dicas do xargs) executa o comando bash -c (que serve para executar uma linha de comandos) que por sua vez executa o chmod e o ls -l para mostrar que as permissões estão sendo alteradas.

Aritmética em Shell

Antigamente usávamos o comando expr para fazer operações aritméticas e muita gente ainda usa, pois é compatível com quaquer ambiente.

Exemplo:

$ expr 7 \* 5 / 3 # 7 vezes 5 = 35 dividido por 3 = 11 11

Neste artigo porém, vamos ver outras formas não tanto conhecidas, porém mais simples de usar, mais elaboradas e com precisão maior.

O uso do bc

Uma forma bacana de fazer cálculos em Shell – usada normalmente quando a expressão aritmética é mais complexa, ou quando é necessário trabalharmos com casas decimais – é usar a instrução calculadora do UNIX/LINUX. O bc. Veja como:

Exemplo:

$ echo "(2 + 3) * 5" | bc # Parênteses usados para dar precedência 25

Para trabalhar com números reais (números não necessariamente inteiros), especifique a precisão (quantidade de decimais) com a opção scale do comando bc. Assim vejamos o penúltimo exemplo:

$ echo "scale=2; 7*5/3" | bc 11.66

Outros exemplos:

$ echo "scale=3; 33.333*3" | bc 99.999 $ num=5 $ echo "scale=2; ((3 + 2) * $num + 4) / 3" | bc 9.66

Obviamente todos os exemplos acima no caso de linux, poderiam (e deveriam) ser escritos usando Here Strings. Veja os últimos como ficariam:

$ bc <<< "scale=3; 33.333*3" 99.999 $ num=5 $ bc <<< "scale=2; ((3 + 2) * $num + 4) / 3" 9.66

Uma vez apareceu na lista (excelente por sinal) de Shell script no Yahoo (http://br.groups.yahoo.com/group/shell-script/) um cara com a seguinte dúvida: "eu tenho um arquivo cujos campos estão separados por <TAB> e o terceiro deles possui números. Como posso calcular a soma de todos os números desta coluna do arquivo?"

Mandei a seguinte resposta:

$ echo $(cut -f3 num | tr '\n' +)0 | bc 20.1

Vamos por partes para entender melhor e primeiramente vamos ver como era o arquivo que fiz para teste:

$ cat num a b 3.2 a z 4.5 w e 9.6 q w 2.8

Como pode-se ver, está dentro do padrão do problema, onde eu tenho como terceiro campo números reais. Vamos ver o que faria a primeira parte da linha de comandos, onde eu transformo os caracteres <ENTER> (new-line) em um sinal de mais (+):

$ cut -f3 num | tr '\n' + 3.2+4.5+9.6+2.8+

Se eu mandasse desse jeito para o bc, ele me devolveria um erro por causa daquele sinal de mais (+) solto no final do texto. A minha saída foi colocar um zero no final, pois somando zero o resultado não se alterará. Vamos ver então como ficou:

$ echo $(cut -f3 num | tr '\n' +)0 3.2+4.5+9.6+2.8+0

Tudo bem, o problema está resolvido, mas em shell sempre tem um jeitinho de se escrever um código menor ainda. Veja isso:

$ cut -f3 num | paste -sd+ 3.2+4.5+9.6+2.8

Ou seja, o cut corta a terceira coluna e manda os números para um paste, cuja opção -s transforma colunas em linhas e o -d+, define o sinal de mais (+) como delimitador. Feito isso, é só mandar isso tudo para o bc proceder à soma com os reais.

$ cut -f3 num | paste -sd+ | bc 20.1

Isso é o que se costuma chamar one-liner, isto é, códigos que seriam complicados em outras linguagens (normalmente seria necessário criar contadores e fazer um loop de leitura somando o terceiro campo ao contador) e em Shell são escritos em uma única linha.

Há também gente que chama isso de método KISS, que é o acrônimo de Keep It Simple Stupid. smile

Mas o potencial de uso desta calculadora não se encerra aí, existem diversas facilidades por ela propiciadas. Veja só este exemplo:

$ echo "obase=16; 11579594" | bc B0B0CA? $ echo "ibase=16; B0B0CA?" | bc # B, zero, B, zero, C, e A 11579594

Nestes exemplos vimos como fazer mudanças de base de numeração com o uso do bc. Na primeira explicitamos a base de saída (obase) como 16 (hexadecimal) e na segunda, dissemos que a base da entrada (ibase) era 10 (decimal).

Outras formas de trabalhar com inteiros

Outra forma muito legal de fazer cálculos é usar a notação $((exp aritmética)). É bom ficar atento, porém, ao fato desta sintaxe não ser universalizada. O Bourne Shell (sh), por exemplo, não a reconhece.

Exemplo:

Usando o mesmo exemplo que já havíamos usado:

$ echo $(((2+3)*5)) # Os parênteses mais internos priorizaram o 2+3 25

Agora olha só esta maluquice:

$ tres=3 $ echo $(((2+tres)*5)) # Variável tres não precedida pelo $ 25 $ echo $(((2+$tres)*5)) # Variável tres precedida pelo $ 25

Ué!! Não é o cifrão ($) precedente que caracteriza uma variável? Sim, porém em todos os sabores UNIX que testei, sob bash ou ksh, ambas as formas de construção produzem uma boa aritmética.

Preste a atenção nesta seqüência:

$ unset i # $i mooorreu! $ echo $((i++)) 0 $ echo $i 1 $ echo $((++i)) 2 $ echo $i 2

Repare que apesar da variável não estar definida, pois foi feito um unset nela, nenhum dos comandos acusou erro, porque, como estamos usando construções aritméticas, sempre que uma variável não existe, é inicializada com zero (0).

Repare que o i++ produziu zero (0). Isto ocorre porque este tipo de construção chama-se pós-incrementação, isto é, primeiramente o comando é executado e só então a variável é incrementada. No caso do ++i, foi feita uma pré-incrementação: primeiro incrementou e somente após o comando foi executado.

Também são válidos:

$ echo $((i+=3)) 5 $ echo $i 5 $ echo $((i*=3)) 15 $ echo $i 15 $ echo $((i%=2)) 1 $ echo $i 1

Estas três operações seriam o mesmo que:

    i=$((i+3))
    i=$((i*3))
    i=$((i%2))

E isto seria válido para todos os operadores aritméticos o que em resumo produziria a tabela a seguir:

Expansão Aritmética
||   OU lógico
  Expressão     Resultado  
id++ id--   pós-incremento e pós-decremento de variáveis
++id -–id   pré-incremento e pré-decremento de variáveis
**   exponenciação
* / %   multiplicação, divisão, resto da divisão
+ -   adição, subtração
<= >= < >   comparação
== !=   igualdade, desigualdade
&&   E lógico

Mas o auge desta forma de construção com duplo parênteses é o seguinte:

$ echo $var 50 $ var=$((var>40 ? var-40 : var+40)) $ echo $var 10 $ var=$((var>40 ? var-40 : var+40)) $ echo $var 50

Este tipo de construção deve ser lido da seguinte forma: caso a variável var seja maior que 40 (var>40), então (?) faça var igual a var menos 40 (var-40), senão (:) faça var igual a var mais 40 (var+40). O que quis dizer é que os caracteres ponto-de-interrogação (?) e dois-pontos (:) fazem o papel de "então" e "senão", servindo desta forma para montar uma operação aritmética condicional.

Da mesma forma que usamos a expressão $((...)) para fazer operações aritméticas, também poderíamos usar a intrínseca (built-in) let ou construção do tipo $[...].

Os operadores são os mesmos para estas três formas de construção, o que varia um pouco é a operação aritmética condicional com o uso do let. Vejamos como seria:

$ echo $var 50 $ let var='var>40 ? var-40 : var+40' $ echo $var 10 $ let var='var>40 ? var-40 : var+40' $ echo $var 50

Baseando

Se você quiser trabalhar com bases diferentes da decimal, basta usar o formato:

    base#numero

Onde base é um número decimal entre 2 e 64 representando o sistema de numeração, e numero é um número no sistema numérico definido por base. Se base# for omitida, então 10 é assumida como default. Os algarismos maiores que 9 são representados por letras minúsculas, maiúsculas, @ e _, nesta ordem.

Se base for menor ou igual a 36, maiúsculas ou minúsculas podem ser usadas indiferentemente para definir algarismos maiores que 9 (não está mal escrito, os algarismos do sistema hexadecimal, por exemplo, variam entre 0 (zero) e F). Vejamos como isso funciona:

$ echo $[2#11] 3 $ echo $((16#a)) 10 $ echo $((16#A)) 10 $ echo $((2#11 + 16#a)) 13 $ echo $[64#a] 10 $ echo $[64#A] 36 $ echo $((64#@)) 62 $ echo $((64#_)) 63

Nestes exemplos usei as notações $((...)) e $[...] indistintamente, para demonstrar que ambas funcionam.

Funciona também uma mudança automática para a base decimal, desde que você esteja usando a convenção numérica do C, isto é, em 0xNN, o NN será tratado como um hexadecimal e em 0NN, o NN será visto como um octal. Veja o exemplo:

Exemplo

$ echo $((10)) # decimal 10 $ echo $((010)) # octal 8 $ echo $((0x10)) # hexadecimal 16 $ echo $((10+010+0x10)) # Decimal + octal + hexadecimal 64

Ah, já ia me esquecendo! As expressões aritméticas com os formatos $((...)), $[...] e com o comando let usam os mesmos operadores usados na instrução expr, além dos operadores unários (++, --, +=, *=, ...) e condicionais que acabamos de ver.

Testes usando expressões regulares

No Papo de Botequim 004, nós falamos tudo sobre comandos condicionais, mas faltou um que não existia àquela época. Neste mesmo Papo de Botequim, na seção E tome de test nós chegamos a falar de uma construção do tipo:

    [[ Expressao ]] && cmd

Onde o comando cmd será executado caso a expressão condicional Expressao seja verdadeira. Disse ainda que Expressao poderia ser estipulada de acordo com as regras de Geração de Nome de Arquivos (File Name Generation). A partir do bash versão 3, foi incorporado a esta forma de teste um operador representado por =~, cuja finalidade é fazer comparações com Expressões Regulares.

Exemplo:

$ echo $BASH_VERSION # Conferindo se a versão do Bash é igual ou superior a 3.0.0 3.2.17(15)-release $ Cargo=Senador $ [[ $Cargo =~ ^(Governa|Sena|Verea)dora?$ ]] && echo É político É político $ Cargo=Senadora $ [[ $Cargo =~ ^(Governa|Sena|Verea)dora?$ ]] && echo É político É político $ Cargo=Diretor $ [[ $Cargo =~ ^(Governa|Sena|Verea)dora?$ ]] && echo É político $

Vamos dar uma esmiuçada na Expressão Regular ^(Governa|Sena|Verea)dora?$: ela casa com tudo que começa (^) por Governa, ou (|) Sena, ou (|) Verea, seguido de dor e seguido de um a opcional (?). O cifrão ($) serve para marcar o fim. Em outras palavras esta Expressão Regular casa com Governador, Senador, Vereador, Governadora, Senadora e Vereadora.

Colorindo a tela

Como você já havia visto no Papo de Botequim 007, o comando tput serve para fazer quase tudo referente a formatação de tela, mas o que não foi dito é que com ele também pode-se usar cores de frente (dos caracteres) e de fundo. Existem também outras formas de fazer o mesmo, acho porém, esta que veremos agora, mais intuitiva (ou menos “desintuitiva”). A tabela a seguir mostra os comandos para especificarmos os padrões de cores de frente (foreground) ou de fundo (background):

Obtendo cores com o comando tput
tput setab n Especifica n como a cor de fundo (background)
  Comando     Efeito  
tput setaf n Especifica n como a cor de frente (foreground)

Bem, agora você já sabe como especificar o par de cores, mas ainda não sabe as cores. A tabela a seguir mostra os valores que o n (da tabela anterior) deve assumir para cada cor:

Valores das cores com o comando tput
7 Cinza claro
  Valor     Cor  
0 Preto
1 Vermelho
2 Verde
3 Marrom
4 Azul
5 Púrpura
6 Ciano

Neste ponto você já pode começar a brincar com as cores.

- Mas peraí, ainda são muito poucas!

- É, tem toda razão... O problema é que ainda não lhe disse que se você colocar o terminal em modo de ênfase (tput bold), estas cores geram outras oito. Vamos montar então a tabela definitiva de cores:

Valores das cores com o comando tput
7 Cinza claro Branco
  Valor     Cor     Cor após tput bold  
0 Preto Cinza escuro
1 Vermelho Vermelho claro
2 Verde Verde claro
3 Marron Amarelo
4 Azul Azul Brilhante
5 Púrpura Rosa
6 Ciano Ciano claro

Exemplo

Como exemplo, vejamos um script que mudará a cor de sua tela de acordo com sua preferência.

$ cat mudacor.sh #!/bin/bash tput sgr0 clear

# Carregando as 8 cores básicas para um vetor Cores=(Preto Vermelho Verde Marrom Azul Púrpura Ciano "Cinza claro")

# Listando o menu de cores echo " Opc Cor = ===" # A linha a seguir significa: para i começando de 1; #+ enquanto i menor ou igual ao tamanho do vetor Cores; #+ incremente o valor de i de 1 em 1 for ((i=1; i<=${#Cores[@]}; i++)) { printf "%02d %s\n" $i "${Cores[i-1]}" }

CL= until [[ $CL == 0[1-8] || $CL == [1-8] ]] do read -p " Escolha a cor da letra: " CL done

# Para quem tem bash a partir da versao 3.2 #+ o test do until acima poderia ser feito #+ usando-se Expressoes Regulares. Veja como: #+ until [[ $CL =~ 0?[1-8] ]] #+ do #+ read -p " #+ Escolha a cor da letra: " CL #+ done

CF= until [[ $CF == 0[1-8] || $CF == [1-8] ]] do read -p " Escolha a cor de fundo: " CF done

let CL-- ; let CF-- # Porque as cores variam de zero a sete tput setaf $CL tput setab $CF clear

Ganhando o jogo com mais coringas

Estava eu lendo meus e-mails quando recebo um do Tiago enviado para a lista de Shell Script (já falei da lista e do Tiago no Rotatório Peczenyj). A seguir o conteúdo do e-mail:

Não sei se é conhecimento de todos mas o shell possui, alem do globbing normal (a expansão *, ? e [a-z] de nomes de arquivos e diretórios), um globbing extendido.

Acho que, em alguns casos, podera ser BEM util, eliminando um pipe para um grep por exemplo.

São eles:

    ?(padrao)
Casa zero ou uma ocorrência de um determinado padrao
    *(padrao)
Casa zero ou mais ocorrências de um determinado padrao
    +(padrao)
Casa uma ou mais ocorrências de um determinado padrao
    @(padrao)
Casa com exatamente uma ocorrência de um determinado padrao
    !(padrao)
Casa com qualquer coisa, exceto com padrao

Para poder utilizá-lo precisa executar o shopt conforme o exemplo abaixo:

$ shopt -s extglob $ ls file filename filenamename fileutils $ ls file?(name) file filename $ ls file*(name) file filename filenamename $ ls file+(name) filename filenamename $ ls file@(name) filename $ ls file!(name) # divertido esse file filenamename fileutils $ ls file+(name|utils) filename filenamename fileutils $ ls file@(name|utils) # "lembra" um {name,utils} filename fileutils

Usando o awk para pesquisar por equivalência

Aí vai mais uma que o Tiago mandou para a lista de Shell Script do Yahoo (já falei da lista e do Tiago no Rotatório Peczenyj e no Ganhando o jogo com mais coringa)

Quem ja não passou por isso: Procurar uma palavra, porém uma letra acentuada, ou não, atrapalhou a busca?

Não descobri como fazer o grep ou sed aceitarem algo semelhante, mas o gawk aceita classes de equivalência!

Melhor explicar com um exemplo, onde vou listar o número da linha e a ocorrência casada:

$ cat dados éco eco èco êco ëco eço $ awk '/^eco/{print NR,$1}' dados 2 eco $ awk '/^e[[=c=]]o/{print NR,$1}' dados 2 eco 6 eço $ awk '/^[[=e=]]co/{print NR,$1}' dados 1 éco 2 eco 3 èco 4 êco 5 ëco

Ou seja, usar [=X=] permite que a expressão encontre a letra X estando acentuada ou não (é sensivel à localização corrente!).

A sintaxe é parecida com a das classes POSIX, trocando os dois-pontos (:) antes e depois da classe por sinais de igual (=).

Achei curioso e deve servir para algum caso semelhante ao descrito.

find – Procurando arquivo por características

Se você está como o Mr. Magoo, procurando em vão um arquivo, use o comando find que serve para procurar arquivos não só pelo nome, como por diversas outras características. Sua sintaxe é a seguinte:

    find [caminho ...] expressão [ação]

Parâmetros:

caminho      Caminhos de diretório a partir do qual (porque ele é recursivo, sempre tentará entrar pelos subdiretórios "pendurados" neste) irá procurar pelos arquivos;
expressão   Define quais critérios de pesquisa. Pode ser uma combinação entre vários tipos de procura;
ação           Define que ação executar com os arquivos que atender aos critérios de pesquisa definidos por expressão.

Principais critérios de pesquisa

-name Procura arquivos que tenham o nome especificado. Aqui podem ser usados metacaracteres ou caracteres curingas, porém estes caracteres deverão estar entre aspas, apóstrofos ou imediatamente precedidos por uma contrabarra isso porque quem tem de expandir os coringas é o find. Se fosse o Shell que os expandisse, isto seria feito somente com relação ao diretório corrente, o que jogaria por terra a característica recursiva do find;
-user Procura arquivos que tenham usuário como dono;
-group Procura arquivos que tenham grupo como grupo dono;
-type c Procura por arquivos que tenham o tipo c, correspondente à letra do tipo do arquivo. Os tipos aceitos estão na tabela a seguir:
Valores de c na opção   acima Tipo de arquivo procurado
b Arquivo especial acessado a bloco
c Arquivo especial acessado a caractere
d Diretório
p Named pipe (FIFO)
f Arquivo normal
l Link simbólico
s Socket
-size ±n[unid] A opção -size procura por arquivos que usam mais (+n) de n unidades unid de espaço ou a menos (-n) de n unidades unid de espaço.
Valores de unid na opção   acima Valor
b Bloco de 512 bytes (valor default)
c Caracteres
k Kilobytes (1024 bytes)
w Palavras (2 bytes)
-atime ±d Procura por arquivos que foram acessados há mais (+d) de d dias ou a menos (-d) de d dias;
-ctime ±d Procura por arquivos cujo status mudou há mais (+d) de d dias ou a menos (-d) de d dias;
-mtime ±d Procura por arquivos cujos dados foram modificados há mais (+d) de d dias ou a menos (-d) de d dias;

Para usar mais de um critério de pesquisa, faça:
     expressão1 expressão2
ou
     expressão1 –a expressão2
para atender aos critérios especificados por expressão1 e expressão2;
     expressão1 –o expressão2
para atender aos critérios especificados por expressão1 ou expressão2.

Principais ações

-print Esta opção faz com que os arquivos encontrados sejam exibidos na tela. Esta é a opção default no Linux. Nos outros sabores Unix que conheço, se nenhuma ação for especificada, ocorrerá um erro;
-exec cmd {} \; Executa o comando cmd. O escopo de comando é considerado encerrado quando um ponto-e-vírgula (;) é encontrado. A cadeia {} é substituída pelo nome de cada arquivo que satisfaz ao critério de pesquisa e a linha assim formada é executada. Assim como foi dito para a opção –name, o ponto-e-vírgula (;) deve ser precedido por uma contrabarra (\), ou deve estar entre aspas ou apóstrofos;
-ok cmd {} \; O mesmo que o anterior porém pergunta se pode executar a instrução cmd sobre cada arquivo que atende ao critério de pesquisa;
-printf formato  A opção -printf permite que se escolha os campos que serão listados e formata a saída de acordo com o especificado em formato.

Exemplos:

Para listar na tela (-print) todos os arquivos, a partir do diretório corrente, terminados por .sh, faça:

$ find . -name \*.sh Ação não especificada –print é default ./undelete.sh ./ntod.sh estes quatro primeiros arquivos foram ./dton.sh encontrados no diretório corrente. ./graph.sh ./tstsh/cotafs.sh ./tstsh/data.sh Estes quatro foram encontrados no ./tstsh/velha.sh diretório tstsh, sob o diretório corrente ./tstsh/charascii.sh

Preciso abrir espaço em um determinado file system com muita urgência, então vou remover arquivos com mais de um megabyte e cujo último acesso foi há mais de 60 dias. Para isso, vou para este file system e faço:

$ find . –type f –size +1000000c –atime +60 –exec rm {} \;

Repare que no exemplo acima usei três critérios de pesquisa, a saber:

-type f Todos os arquivos regulares (normais)
-size +1000000c   Tamanho maior do que 1000000 de caracteres (+1000000c)
-atime +60 Último acesso há mais de 60 (+60) dias.

Repare ainda que entre estes três critérios foi usado o conector e, isto é, arquivos regulares e maiores que 1MByte e sem acesso há mais de 60 dias.

Para listar todos os arquivos do disco terminados por .sh ou .txt, faria:

$ find / -name \*.sh –o –name \*.txt –print

Neste exemplo devemos salientar além das contrabarras (\) antes dos asteriscos (*), o uso do –o para uma ou outra extensão e que o diretório inicial era o raiz (/); assim sendo, esta pesquisa deu-se no disco inteiro (o que freqüentemente é bastante demorado).

Com o printf é possível formatar a saída do comando find e especificar os dados desejados. A formatação do printf é muito semelhante à do mesmo comando na linguagem C e interpreta caracteres de formatação precedidos por um símbolo de percentual (%). Vejamos seus efeitos sobre a formatação:

Caractere Significado
%U Número do usuário (UID) do dono do arquivo
%f Nome do arquivo (caminho completo não aparece)
%F Indica a qual tipo de file system o arquivo pertence
%g Grupo ao qual o arquivo pertence
%G Grupo ao qual o arquivo pertence (GID- Numérico)
%h Caminho completo do arquivo (tudo menos o nome)
%i Número do inode do arquivo (em decimal)
%m Permissão do arquivo (em octal)
%p Nome do arquivo
%s Tamanho do arquivo
%u Nome de usuário (username) do dono do arquivo

Também é possível formatar datas e horas obedecendo às tabelas a seguir:

Caractere Significado
%a Data do último acesso
%c Data de criação
%t Data de alteração

Os três caracteres anteriores produzem uma data semelhante ao do comando date.

Veja um exemplo:

$ find . -name ".b*" -printf '%t %p\n' Mon Nov 29 11:18:51 2004 ./.bash_logout Tue Nov 1 09:44:16 2005 ./.bash_profile Tue Nov 1 09:45:28 2005 ./.bashrc Fri Dec 23 20:32:31 2005 ./.bash_history

Nesse exemplo, o %p foi o responsável por colocar os nomes dos arquivos. Caso fosse omitido, somente as datas seriam listadas. Observe ainda que ao final foi colocado um /n. Sem ele não haveria salto de linha e a listagem anterior seria uma grande tripa.

Essas datas também podem ser formatadas, para isso basta passar as letras da tabela anterior para maiúsculas (%A, %C e %T) e usar um dos formatadores das duas tabelas a seguir:

Tabela de formatação de tempo
Z  Fuso horário (na Cidade Maravilhosa BRST)
  Caractere     Significado  
H  Hora (00..23)
I  Hora (01..12)
k  Hora (0..23)
l  Hora (1..12)
M  Minuto (00..59)
p  AM or PM
r  Horário de 12 horas (hh:mm:ss) seguido de AM ou PM
S  Segundos (00 ... 61)
T  Horário de 24-horas (hh:mm:ss)

Tabela de formatação de datas
Y  Ano com 4 dígitos
  Caractere     Significado  
a  Dia da semana abreviado (Dom...Sab)
A  Dia da semana por extenso (Domingo...Sábado)
b  Nome do mês abreviado (Jan...Dez)
B  Dia do mês por extenso (Janeiro...Dezembro)
c  Data e hora completa (Fri Dec 23 15:21:41 2005)
d  Dia do mês (01...31)
D  Data no formato mm/dd/aa
h  Idêntico a b
j  Dia seqüencial do ano (001…366)
m  Mês (01...12)
U  Semana seqüencial do ano. Domingo como 1º dia da semana (00...53)
w  Dia seqüencial da semana (0..6)
W  Semana seqüencial do ano. Segunda-feira como 1º dia da semana (00...53)
x  Representação da data no formato do país (definido por $LC_ALL)
y  Ano com 2 dígitos (00...99)

Para melhorar a situação, vejamos uns exemplos; porém, vejamos primeiro quais são os arquivos do diretório corrente que começam por .b:

$ ls -la .b* -rw------- 1 d276707 ssup 21419 Dec 26 17:35 .bash_history -rw-r--r-- 1 d276707 ssup 24 Nov 29 2004 .bash_logout -rw-r--r-- 1 d276707 ssup 194 Nov 1 09:44 .bash_profile -rw-r--r-- 1 d276707 ssup 142 Nov 1 09:45 .bashrc

Para listar esses arquivos em ordem de tamanho, podemos fazer:

$ find . -name ".b*" -printf '%s\t%p\n' | sort -n 24 ./.bash_logout 142 ./.bashrc 194 ./.bash_profile 21419 ./.bash_history

No exemplo que acabamos de ver, o \t foi substituído por um na saída de forma a tornar a listagem mais legível. Para listar os mesmos arquivos classificados por data e hora da última alteração:

$ find . -name ".b*" -printf '%TY-%Tm-%Td %TH:%TM:%TS %p\n' | sort 2004-11-29 11:18:51 ./.bash_logout 2005-11-01 09:44:16 ./.bash_profile 2005-11-01 09:45:28 ./.bashrc 2005-12-26 17:35:13 ./.bash_history

Algumas implementações do Bash 4.0

Aqui neste tópico lançarei somente o que é inteiramente novo a partir do Bash 4.0. O que já existia, mas que foi aprimorado a partir desta versão do Bash (como as expansões de parâmetro), está sendo publicado na seção correspondente.

Coprocessos

A partir da versão 4.0, o Bash incorporou o comando coproc. Este novo intrínseco (builtin) permite dois processos assíncronos se comunicarem e interagirem. Como cita Chet Ramey no Bash FAQ, ver. 4.01:

"Há uma nova palavra reservada, coproc, que especifica um coprocesso: um comando assíncrono que é executado com 2 pipes conectados ao Shell criador. coproc pode receber nome. Os descritores dos arquivos de entrada e saída e o PID do coprocesso estão disponíveis para o Shell criador em variáveis com nomes específicos do coproc."

George Dimitriu explica:

"O coproc é uma facilidade usada na substituição de processos que agora está publicamente disponível."

A comprovação do que disse Dimitriu não é complicada, quer ver? Veja a substituição de processos a seguir:

$ cat <(echo xxx; sleep 3; echo yyy; sleep 3)

Viu?! O cat não esperou pela conclusão dos comandos entre parênteses, mas foi executado no fim de cada um deles. Isso aconteceu porque estabeleceu-se um pipe temporário/dinâmico e os comandos que estavam sendo executados, mandavam para ele as suas saídas, que por sua vez as mandava para a entrada do cat.

Isso significa que os comandos desta substituição de processos rodaram paralelos, sincronizando somente nas saídas dos echo com a entrada do cat.

A sintaxe de um coprocesso é:

   coproc [nome] cmd redirecionamentos

Isso criará um coprocesso chamado nome. Se nome for informado, cmd deverá ser um comando composto. Caso contrário (no caso de nome não ser informado), cmd poderá ser um comando simples ou composto.

Quando um coproc é executado, ele cria um vetor com o mesmo nome nome no Shell criador. Sua saída padrão é ligada via um pipe a um descritor de arquivo associado à variável ${nome[0]} à entrada padrão do Shell pai (lembra que a entrada padrão de um processo é sempre associada por default ao descritor zero?). Da mesma forma, a entrada do coproc é ligada à saída padrão do script, via pipe, a um descritor de arquivos chamado ${nome[1]}. Assim, simplificando, vemos que o script mandará dados para o coproc pela variável ${nome[0]}, e receberá sua saída em ${nome[1]}. Note que estes pipes serão criados antes dos redirecionamentos especificados pelo comando, já que eles serão as entradas e saídas do coprocesso.

A partir daqui, vou detalhar rapidamente uns estudos que fiz. Isso contém um pouco de divagações e muita teoria. Se você pular para depois desses ls's, não perderá nada, mas se acompanhar, pode ser bom para a compreensão do mecanismo do coproc.

Após colocar um coproc rodando, se ele está associado a um descritor de arquivo, vamos ver o que tem ativo no diretório correspondente:

$ ls -l /dev/fd lrwxrwxrwx 1 root root 13 2010-01-06 09:31 /dev/fd -> /proc/self/fd

Hummm, é um link para o /proc/self/fd... O que será que tem lá?

$ ls -l /proc/self/fd total 0 lrwx------ 1 julio julio 64 2010-01-06 16:03 0 -> /dev/pts/0 lrwx------ 1 julio julio 64 2010-01-06 16:03 1 -> /dev/pts/0 lrwx------ 1 julio julio 64 2010-01-06 16:03 2 -> /dev/pts/0 lr-x------ 1 julio julio 64 2010-01-06 16:03 3 -> /proc/3127/fd

Epa, que o 0, 1 e 2 apontavam para /dev/pts/0 eu já sabia, pois são a entrada padrão, saída padrão e saída de erros padrão apontando para o pseudo terminal corrente, mas quem será esse maldito device 3? Vejamos:

$ ls -l /proc/$$/fd # $$ É o PID do Shell corrente total 0 lr-x------ 1 julio julio 64 2010-01-06 09:31 0 -> /dev/pts/0 lrwx------ 1 julio julio 64 2010-01-06 09:31 1 -> /dev/pts/0 lrwx------ 1 julio julio 64 2010-01-06 09:31 2 -> /dev/pts/0 lrwx------ 1 julio julio 64 2010-01-06 16:07 255 -> /dev/pts/0 l-wx------ 1 julio julio 64 2010-01-06 16:07 54 -> pipe:[168521] l-wx------ 1 julio julio 64 2010-01-06 16:07 56 -> pipe:[124461] l-wx------ 1 julio julio 64 2010-01-06 16:07 58 -> pipe:[122927] lr-x------ 1 julio julio 64 2010-01-06 16:07 59 -> pipe:[168520] l-wx------ 1 julio julio 64 2010-01-06 16:07 60 -> pipe:[121302] lr-x------ 1 julio julio 64 2010-01-06 16:07 61 -> pipe:[124460] lr-x------ 1 julio julio 64 2010-01-06 16:07 62 -> pipe:[122926] lr-x------ 1 julio julio 64 2010-01-06 16:07 63 -> pipe:[121301]

Epa, aí estão os links apontando para os pipes. Esse monte de arquivo de pipe que foi listado, deve ser porque estava testando exaustivamente essa nova facilidade do Bash.

Para terminar esta teoria chata, falta dizer que o PID do Shell gerado para interpretar o coproc pode ser obtido na variável $nome_PID e o comando wait pode ser usado para esperar pelo fim do coprocesso. O código de retorno do coprocesso ($?) é o mesmo de cmd.

Exemplo:

Vamos começar com o mais simples: um exemplo sem nome e direto no prompt:

$ coproc while read Entra # coproc ativo > do > echo -=-=- $Entra -=-=- > done [2] 3030 $ echo Olá >&${COPROC[1]} # Manda Olá para a pipe da saída $ read -u ${COPROC[0]} Sai # Lê do pipe da entrada $ echo $Sai -=-=- Olá -=-=- $ kill $COPROC_PID # Isso não pode ser esquecido...

Como você viu, o vetor COPROC, está associado a dois pipes; o ${COPROC[1]} que contém o endereço do pipe de saída, e por isso a saída do echo esta redirecionada para ele e o ${COPROC[0]} que contém o endereço do pipe de entrada, e por isso usamos a opção -u do read que lê dados a partir de um descritor de arquivo definido, ao invés da entrada padrão.

Como o coprocesso utilizava a sintaxe sem nome, o padrão do nome do vetor é COPROC.

Só mais uma teoriazinha chata:

$ echo ${COPROC[@]} # Lista todos os elementos do vetor 59 54

Como você viu ${COPROC[0]} estava usando o pipe apontado por /proc/$$/fd/59 e ${COPROC[1]} usava /proc/$$/fd/54. Agora chega de teoria mesmo! Vamos agora usar nome neste mesmo exemplo, para ver que pouca coisa muda:

$ coproc teste { > while read Entra > do > echo -=-=- $Entra -=-=- > done > } [6] 3192 $ echo Olá >&${teste[1]} $ read -u ${teste[0]} Sai $ echo $Sai -=-=- Olá -=-=- $ kill $teste_PID

Nesse momento, é bom mostrar uma coisa interessante: Quais são os processos em execução?

$ ps # Somente no Bash em execução PID TTY TIME CMD 1900 pts/0 00:00:01 bash 2882 pts/0 00:00:00 ps

Vamos executar 2 coprocessos simultâneos:

$ coproc nome1 { # Coprocesso nome1 > while read x > do > echo $x > done; } [1] 2883 $ coproc nome2 { # Coprocesso nome2 > while read y > do > echo $y > done; } bash: aviso: execute_coproc: coproc [2883:nome1] still exists [2] 2884

Xiiii! Acho que deu zebra! Mas será que deu mesmo? Repare que além do PID 2883 de nome1, ele também me devolveu o PID 2884, que deve ser de nome2. Vamos ver o que está acontecendo:

$ ps PID TTY TIME CMD 1900 pts/0 00:00:01 bash Esse já existia 2883 pts/0 00:00:00 bash Esse está executando nome1 2884 pts/0 00:00:00 bash Esse está executando nome2 2885 pts/0 00:00:00 ps

Parece que foi só um aviso, pois os dois PIDs informados quando iniciamos os dois coprocessos, estão ativos. Então vamos testar esses 2 caras:

$ echo xxxxxxxxx >&${nome1[1]} # Mandando cadeia para nome1 $ echo yyyyyyyyy >&${nome2[1]} # Mandando cadeia para nome2 $ read -u ${nome1[0]} Recebe $ echo $Recebe xxxxxxxxx $ read -u ${nome2[0]} Recebe $ echo $Recebe yyyyyyyyy $ kill $nome1_PID $ kill $nome2_PID

Vetores associativos

A partir do Bash 4.0, passou a existir o vetor associativo. Chama-se vetor associativo, aqueles cujos índices são alfabéticos. As regras que valem para os vetores inteiros, valem também para os associativos, porém antes de valorar estes últimos, é obrigatório declará-los.

Exemplo:

$ declare -A Animais # Obrigatório para vetor associativo $ Animais[cavalo]=doméstico $ Animais[zebra]=selvagem $ Animais[gato]=doméstico $ Animais[tigre]=selvagem

Pinguim com placa de atenção É impossível gerar todos os elementos de uma só vez, como nos vetores inteiros. Assim sendo, não funciona a sintaxe:
Animais=([cavalo]=doméstico [zebra]=selvagem  [gato]=doméstico [tigre]=selvagem)

$ echo ${Animais[@]} doméstico selvagem doméstico selvagem $ echo ${!Animais[@]} gato zebra cavalo tigre

Repare que os valores não são ordenados, ficam armazenados na ordem que são criados, diferentemente dos vetores inteiros que ficam em ordem numérica.

Supondo que esse vetor tivesse centenas de elementos, para listar separadamente os domésticos dos selvagens, poderíamos fazer um script assim:

$ cat animal.sh #!/bin/bash # Separa animais selvagens e domésticos declare -A Animais Animais[cavalo]=doméstico # Criando vetor para teste Animais[zebra]=selvagem # Criando vetor para teste Animais[gato]=doméstico # Criando vetor para teste Animais[tigre]=selvagem # Criando vetor para teste Animais[urso pardo]=selvagem # Criando vetor para teste for Animal in "${!Animais[@]}" # Percorrendo vetor pelo índice do if [[ "${Animais[$Animal]}" == selvagem ]] then Sel=("${Sel[@]}" "$Animal") # Gerando vetor p/ selvagens else Dom=("${Dom[@]}" "$Animal") # Gerando vetor p/ domésticos fi done # Operador condicional, usado para descobrir qual #+ vetor tem mais elementos. Veja detalhes na seção #+ O interpretador aritmético do Shell Maior=$[${#Dom[@]}>${#Sel[@]}?${#Dom[@]}:${#Sel[@]}] clear tput bold; printf "%-15s%-15s\n" Domésticos Selvagens; tput sgr0 for ((i=0; i<$Maior; i++)) { tput cup $[1+i] 0; echo ${Dom[i]} tput cup $[1+i] 14; echo ${Sel[i]} }

Gostaria de chamar a sua atenção para um detalhe: neste script me referi a um elemento de vetor associativo empregando ${Animais[$Animal]} ao passo que me referi a um elemento de um vetor inteiro usando ${Sel[i]}. Ou seja, quando usamos uma variável como índice de um vetor inteiro, não precisamos prefixá-la com um cifrão ($), ao passo que no vetor associativo, o cifrão ($) é obrigatório.

Lendo um arquivo para um vetor

Ainda falando do Bash 4.0, eis que ele surge com uma outra novidade: o comando intrínseco (builtin) mapfile, cuja finalidade é jogar um arquivo de texto inteiro para dentro de um vetor, sem loop ou substituição de comando.

    - EPA! Isso deve ser muito rápido!

    - E é. Faça os teste e comprove!

Exemplo:

$ cat frutas abacate maçã morango pera tangerina uva $ mapfile vet < frutas # Mandando frutas para vetor vet $ echo ${vet[@]} # Listando todos elementos de vet abacate maçã morango pera tangerina uva

Obteríamos resultado idêntico se fizéssemos:

$ vet=($(cat frutas))

Porém isso seria mais lento porque a substituição de comando é executada em um subshell. Uma outra forma de fazer isso que logo vem à cabeça é ler o arquivo com a opção -a do comando read. Vamos ver como seria o comportamento disso:

$ read -a vet < frutas $ echo ${vet[@]} abacate

Como deu para perceber, foi lido somente o primeiro registro de frutas.

Caixa baixa para alta e vice versa

Usando expansão de parâmetro

  • ${parâmetro^}
  • ${parâmetro,}
Essas expansões de parâmetros foram introduzidas a partir do Bash 4.0 e modificam a caixa das letras do texto que está sendo expandido. Quando usamos circunflexo (^), a expansão é feita para maiúsculas e quando usamos vírgula (,), a expansão é feita para minúsculas.

Exemplo:

$ Nome="botelho" $ echo ${Nome^} Botelho $ echo ${Nome^^} BOTELHO $ Nome="botelho carvalho" $ echo ${Nome^} Botelho carvalho # É pena que não fique Botelho Carvalho...

Um fragmento de script que pode facilitar a sua vida:

read -p "Deseja continuar (s/n)? "
[[ ${REPLY^} == N ]] && exit

Esta forma evita testarmos se a resposta dada foi um N (maiúsculo) ou um n (minúsculo).

Usando declaratives

Podemos fazer algo parecido, porém de outra maneira. Agora, para termos somente maiúsculas em uma variável também podemos declará-la usando a opção -u ( de uppercase = maiúscula). Veja:

$ declare -u Maiusc

Uma vez assim declarada, veja este exemplo:

$ read -p "Tecle algo: " Maiusc # A variável Maiusc receberá o que for teclado Tecle algo: converte para maiusculas $ echo $Maiusc CONVERTE PARA MAIUSCULAS

O inverso disso seria usarmos a opção -l (de lowercase = minúscula). Veja:

$ declare -l Minusc $ read -p "Tecle algo: " Minusc # A variável Minusc receberá o que for teclado Tecle algo: CONVERTE PARA MINUSCULAS $ echo $Minusc converte para minusculas

Tudo que foi dito sobre estas conversões, só é valido após o declare ter sido feito. Repare:

$ var="xxxx" # Vou atribuir antes de declarar $ declare -u var $ echo $var xxxx # Nada mudou, continua minúscula $ var="xxxx" # Atribuindo após declaração $ echo $var XXXX # Agora funcionou...

Novas implementações no comando case

O bash 4.0 introduziu duas novas facilidades no comando case. A partir desta versão, existem mais dois terminadores de bloco além do ;;, que são: ;;& - Quando um bloco de comandos for encerrado com este terminador, o programa não sairá do case, mas testará os próximos padrões; ;& - Neste caso, o próximo bloco será executado, sem sequer testar o seu padrão.

Exemplo:

Veja este fragmento de código adaptado de http://tldp.org/LDP/abs/html/bashver4.html:

case "$1" in
    [[:print:]] )  echo $1 é um caractere imprimível;;&
    # O terminador ;;& testará o próximo padrão
    [[:alnum:]] )  echo $1 é um carac. alfa/numérico;;&
    [[:alpha:]] )  echo $1 é um carac. alfabético   ;;&
    [[:lower:]] )  echo $1 é uma letra minúscula    ;;&
    [[:digit:]] )  echo $1 é um caractere numérico  ;&
    # O terminador ;& executará o próximo bloco...
    %%%@@@@@    )  echo "************************"  ;;
#   ^^^^^^^^  ... mesmo com um padrão maluco.
esac

A execução deste código passando 3 como parâmetro, resultaria:

3 é um caractere imprimível 
3 é um carac. alfa/numérico 
3 é um caractere numérico
********************************

Passando m:

m é um caractere imprimível 
m é um carac. alfa/numérico 
m é um carac. alfabético
m é uma letra minúscula

Passando / :

/ é um caractere imprimível

Expansão de chaves

O Bash 4.0 incorporou duas novas formas de fazer expansão de chaves:

  • Sequência numérica com preenchimento de zeros à esquerda;
  • Possibilidade de usarmos um incremento (passo) em uma sequência numérica.

Exemplos:

$ echo {0010..0019} # Preenchendo com 2 zeros à esquerda 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 $ echo {05..15} # Preenchendo com zeros à esquerda 05 06 07 08 09 10 11 12 13 14 15 $ echo {-5..19..3} # Incrementando de 3 em 3 (Passo 3) -5 -2 1 4 7 10 13 16 19 $ echo {000..100..10} # Preenchendo com zeros e passo 10 000 010 020 030 040 050 060 070 080 090 100

Vou aproveitar também para mandar o meu jabá: diga para os amigos que quem estiver afim de fazer um curso porreta de programação em Shell que mande um e-mail para a nossa gerencia de treinamento para informar-se.

Qualquer dúvida ou falta de companhia para um chope ou até para falar mal dos políticos é só mandar um e-mail para mim.

Valeu!

 
This site is powered by FoswikiCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding Wiki-SL? Send feedback