8
 Awk em Exemplos, Parte 2 Registros, laços e arrays Daniel Robbins Presidente/CEO, Gentoo Technologies, Inc. Janeiro de 2001  Nesta seqüência de s eu artigo anterior,  introdução ao awk , Daniel Robbins continua a explorar o awk, uma grande linguagem com um estranho nome. Daniel irá mostrar como tratar registros multi-linhas, usar construções em laço, e criar e usar arrays no awk. No fim deste artigo, você estará vem versado em uma ampla gama de funcionalidades do awk, e estará pronto para escrever seus próprios scripts p oderosos awk.  Registros Multi-linhas  OFS e ORS  Multi-linhas para tabulado   Estruturas de laço   Break e Continue  Arrays  Índices strings de arrays   Ferramentas para arrays   Recursos  Sobre o autor  Registros Multi-linhas O awk é uma excelente ferrametna para ler e processar dados estruturados, como o arquivo de sistema /etc/passwd. O arquivo /etc/passwd é o banco de dados de usuários do UNIX, e é um arquivo delimitado  por dois-pontos, contendo muita informaçã o importante, incluindo todas as con tas de usuário existentes e IDs de usuário, entre outras coisas. E m meu  artigo anterior , eu mostrei como o awk pode facilmente tratar este arquivo. Tudo que precisamos fazer foi configurar a variável FS (separador de campos) para ":". Se a variável FS for configurada corretamente, o awk pode ser configurado para tratar quase qualquer tipo de dado estruturado, desde que exista um registro por linha. Entretanto, só configurar FS não serve para nada se queremos tratar um registro que existe em múltiplas linhas. Nestas situações, precisamos também modificar a variável RS, ou separador de registro. A variável RS informa ao awk quando o registro atual terminou e um novo r egistro começa. Por exemplo, vamos ver como tratar a tarefa de processar uma lista de participantes do Programa Federal de Proteção às Testemunhas: Jimmy the Weasel 100 Pleasant Drive San Francisco, CA 12345 Big Tony 200 Incognito Ave. Suburbia, WA 67890 Idealmente, queremos que o awk reconheça cada endereço de três linhas como sendo um registro individual, em vez de três r egistros separados. Tornaria nosso código muito mais simples se o awk

Exemplos de AWK - parte 2/3

Embed Size (px)

DESCRIPTION

Exemplos de como usar a linguagem AWK em plataformas Linux.Parte 2/3.

Citation preview

  • Awk em Exemplos, Parte 2

    Registros, laos e arrays

    Daniel Robbins

    Presidente/CEO, Gentoo Technologies, Inc.

    Janeiro de 2001

    Nesta seqncia de seu artigo anterior, introduo ao awk, Daniel Robbins continua a explorar o awk,

    uma grande linguagem com um estranho nome. Daniel ir mostrar como tratar registros multi-linhas, usar

    construes em lao, e criar e usar arrays no awk. No fim deste artigo, voc estar vem versado em uma

    ampla gama de funcionalidades do awk, e estar pronto para escrever seus prprios scripts poderosos

    awk.

    Registros Multi-linhas

    OFS e ORS

    Multi-linhas para tabulado

    Estruturas de lao

    Break e Continue

    Arrays

    ndices strings de arrays

    Ferramentas para arrays

    Recursos

    Sobre o autor

    Registros Multi-linhas

    O awk uma excelente ferrametna para ler e processar dados estruturados, como o arquivo de sistema

    /etc/passwd. O arquivo /etc/passwd o banco de dados de usurios do UNIX, e um arquivo delimitado

    por dois-pontos, contendo muita informao importante, incluindo todas as contas de usurio existentes e

    IDs de usurio, entre outras coisas. Em meu artigo anterior, eu mostrei como o awk pode facilmente tratar

    este arquivo. Tudo que precisamos fazer foi configurar a varivel FS (separador de campos) para ":".

    Se a varivel FS for configurada corretamente, o awk pode ser configurado para tratar quase qualquer tipo

    de dado estruturado, desde que exista um registro por linha. Entretanto, s configurar FS no serve para

    nada se queremos tratar um registro que existe em mltiplas linhas. Nestas situaes, precisamos tambm

    modificar a varivel RS, ou separador de registro. A varivel RS informa ao awk quando o registro atual

    terminou e um novo registro comea.

    Por exemplo, vamos ver como tratar a tarefa de processar uma lista de participantes do Programa Federal

    de Proteo s Testemunhas:

    Jimmy the Weasel

    100 Pleasant Drive

    San Francisco, CA 12345

    Big Tony

    200 Incognito Ave.

    Suburbia, WA 67890

    Idealmente, queremos que o awk reconhea cada endereo de trs linhas como sendo um registro

    individual, em vez de trs registros separados. Tornaria nosso cdigo muito mais simples se o awk

  • reconhecer a primeira linha como primeiro campo ($1), o endereo como o segundo campo ($2), e a

    cidade, estado e CEP como o campo $3. O cdigo abaixo ir fazer exatamente o que queremos:

    BEGIN {

    FS="\n"

    RS=""

    }

    No cdigo acima, configurando FS para "\n" diz ao awk que cada campo aparece em sua prpria linha.

    Configurando o RS para "", estamos informando ao awk que cada registro de endereo est separado por

    uma linha em branco. Uma vez que o awk sabe como a entrada est formatada, ele pode fazer todo o

    tratamento para ns, e o resto do script simples. Vamos dar uma olhada em um script completo que ir

    tratar esta lista de endereos e imprimir cada registro em uma nica linha, separando cada campo com

    uma vrgula.

    address.awk

    BEGIN {

    FS="\n"

    RS=""

    }

    {

    print $1 ", " $2 ", " $3

    }

    Se este script for salvo como address.awk, e a lista de endereos for armazenada em um arquivo chamado

    address.txt, voc pode executar este script escrevendo "awk -f address.awk address.txt". Este cdigo

    produz a seguinte sada:

    Jimmy the Weasel, 100 Pleasant Drive, San Francisco, CA 12345

    Big Tony, 200 Incognito Ave., Suburbia, Wa 67890

    OFS e ORS

    Na declarao print do address.awk, voc pode ver que o awk concatena (une) as strings que so

    colocadas prximas em uma linha. Usamos esta funcionalidade para inserir uma vrgula e um espao (",

    ") entre os trs campos de endereo que aparecem na linha. Apesar deste mtodo funcionar, ele tem um

    aspecto horrvel. Ao invs de inserir ", " literais entre os campos, podemos fazer que o awk faa isto

    configurando uma varivel especial do awk chamada OFS. D uma olhada no seguinte trecho de cdigo:

    print "Hello", "there", "Jim!"

    As vrgulas nesta linha no so parte da string literal. Em vez disto, elas informam ao awk que "Hello",

    "there", e "Jim!" so campos separados, e que a varivel OFS deve ser impressa entre cada string. Por

    padro, o awk produz a seguinte sada:

    Hello there Jim!

    Isto nos mostra que, por padro, o OFS est configurado como " ", um espao simples. Entretanto,

    podemos facilmente redefinir o OFS de forma que o awk insira nosso separador de campos favorito. Aqui

    est uma verso revisada do nosso programa original address.awk que usa o OFS para colocar aquelas

    strings ", " intermedirias:

  • Uma verso revisada o address.awk

    BEGIN {

    FS="\n"

    RS=""

    OFS=", "

    }

    {

    print $1, $2, $3

    }

    O awk tambm tem uma varivel especial chamada ORS, ou "separador de registros na sada".

    Configurando o ORS, que , por padro, uma nova linha ("\n"), podemos controlar os caracteres que so

    automaticamente impressos no fim de uma declarao print. O valor padro do ORS faz com que o awk

    imprime cada nova declarao print em uma nova linha. Se quisermos que a sada tenha espaamento

    duplo, podemos configurar o ORS para ser "\n\n". Ou, se queremos que os registros sejam separados por

    um espao simples (e no uma nova linha), basta configurar o ORS para " ".

    Multi-linhas para tabulado

    Digamos que tenhamos escrito um script que converte nossa lista de endereos para uma lista com um

    registro por linha, delimitado por tabulaes, para importar para uma planilha. Aps usar uma verso

    levemente modificada do address.awk, torna-se claro que nosso programa funciona somente para

    endereos de trs linhas. Se o awk encontrar o seguinte endereo, a quarta linha ser descartada e no ser

    impressa:

    Cousin Vinnie

    Vinnie's Auto Shop

    300 City Alley

    Sosueme, OR 76543

    Para tratar situaes como esta, seria interessante se noso cdigo pegar o nmero de registros por campo

    em conta, imprimindo cada um em ordem. Por enquanto, o cdigo somente imprime os trs primeiros

    campos do endereo. Aqui temos um cdigo que faz o que queremos:

    Uma verso do address.awk que funciona com endereos com qualquer

    nmero de campos

    BEGIN {

    FS="\n"

    RS=""

    ORS=""

    }

    {

    x=1

    while ( x < NF ) {

    print $x "\t"

    x++

    }

    print $NF "\n"

    }

  • Primeiro, configuramos o separador de campos FS para "\n" e o separador de registros RS para "", de

    forma que o awk trata os endereos multi-linhas corretamente, como antes. A seguir, configuramos o

    separador de registros de sada, ORS, para "", o que vai fazer com que a declarao print no coloque um

    "nova linha" ao fim de cada chamada. Isto significa que se queremos que algum texto inicie em uma nova

    linha, temos de escrever explicitamente um print "\n".

    No cdigo principal, criamos uma varivel chamada x que guarda o nmero do registro atual que estamos

    processando. Inicialmente este nmero 1. A seguir, usamos um lao while (uma estrutura de loop do

    awk que idntica que encontrada na linguagem C) para iterar por todos os registros, menos o ltimo,

    imprimindo o registro e um caracter de tabulao. Finalmente, imprimimos o ltimo registro e uma nova-

    linha literal. Novamente, uma vez que o ORS est configurado para "", o print no ir acrescentar nova-

    linhas para ns. A sada do programa parecida com o que segue, que exatamente o que queramos:

    Nossa sada pretendida. No bonita, mas delimitada por tabulaes

    para facilitar importao para uma planilha

    Jimmy the Weasel 100 Pleasant Drive San Francisco, CA 12345

    Big Tony 200 Incognito Ave. Suburbia, WA 67890

    Cousin Vinnie Vinnie's Auto Shop 300 City Alley Sosueme, OR 76543

    Estruturas de lao

    Ns j vimos a estrutura de lao while do awk, que idntica sua contraparte no C. O awk tambm tem

    uma estrutura de lao "do..while" que testa a condio no fim do bloco de cdigo, em vez de no incio,

    como um lao while padro. similar aos laos "repeat..until" que podem ser encontrados em outras

    linguagens. Veja um exemplo:

    Exemplo do...while

    {

    count=1

    do {

    print "I get printed at least once no matter what"

    } while ( count != 1 )

    }

    Como a condio testada aps o bloco de cdigo, um lao "do...while", diferente de um lao while

    normal, sempre ir executar o bloco de cdigo pelo menos uma vez. Por outro lado, um lao while nunca

    ser executado se sua condio falsa quando o lao encontrado.

    Laos for

    O awk permite que se crie laos for, que, como os laos while, idntico sua contraparte C:

    for ( initial assignment; comparison; increment ) {

    code block

    }

    Aqui temos um exemplo:

    for ( x = 1; x

  • Este trecho ir escrever:

    iteration 1

    iteration 2

    iteration 3

    iteration 4

    Break e Continue

    Novamente, exatamente como no C, o awk tem as declaraes break e continue. Estas declaraes

    permitem um melhor controle sobre as vrias estruturas de lao do awk. Segue um trecho de cdigo que

    precisa desesperadamente uma declarao break:

    Um lao while infinito

    while (1) {

    print "forever and ever..."

    }

    Como o 1 sempre verdadeiro, este lao ser executado para sempre. Aqui h um lao que executado

    somente dez vezes:

    Um exemplo da declarao break

    x=1

    while(1) {

    print "iteration",x

    if ( x == 10 {

    break

    }

    x++

    }

    Aqui, a declarao break usada para parar o lao mais interno. O break faz com que o lao seja

    terminado imediatamente e a execuo do programa continue na linha aps o cdigo do lao.

    A declarao continue complementa o break, e funciona assim:

    x=1

    while (1) {

    if ( x == 4 ) {

    x++

    continue

    }

    print "iteration", x

    if ( x > 20 ) {

    break

    }

    x++

    }

    Este cdigo ir imprimir "iteration 1" at "iteration 21", exceto por "iteration 4". Se a iterao 4, x

    incrementado e a declarao continue chamada, o que faz com que o awk imediatamente inicie o

    prximo lao sem executar o resto do bloco de cdigo. A declarao continue funciona para todos os

  • tipos de laos iterativos, da mesma forma que o break. Quando usado no corpo de um lao for, o continue

    faz com que a varivel de controle de lao seja automaticamente incrementado. Aqui h um lao for

    equivalente:

    for ( x=1; x

  • ndices strings de arrays

    Em meu artigo anterior, eu mostrei que o awk armazena valores numricos em um formato string. Apesar

    do awk executar as converses necessrias para isto funcionar, isto abre a porta para certos cdigos

    estranhos:

    a="1"

    b="2"

    c=a+b+3

    Depois que o cdigo executado, o c igual a 6. Como o awk "stringy", somar as strings "1" e "2"

    funcionalmente igual a somar os nmeros 1 e 2. Em ambos os casos, o awk ir fazer a soma. A natureza

    "stringy" do awk bastante intrigante -- voc pode se perguntar o que acontece se usarmos ndices string

    para arrays. Por exemplo, veja o seguinte cdigo:

    myarr["1"]="Mr. Whipple"

    print myarr["1"]

    Como voc deve esperar, este cdigo ir escrever "Mr. Whipple". Mas e se tirarmos as aspas que esto

    em torno do segundo ndice "1"?

    myarr["1"]="Mr. Whipple"

    print myarr[1]

    Adivinhar o resultado deste trecho de cdigo um pouco mais difcil. O awk ir considerar

    myarr["1"] e myarr[1] como sendo dois elementos seprados do array, ou eles se referem ao mesmo

    elemento? A resposta que eles se referem ao mesmo elemento, e o awk ir escrever "Mr. Whipple",

    como no primeiro trecho de cdigo. Apesar disto parecer estranho, por trs das cenas o awk tem usado

    ndices strings para seus arrays todo este tempo"

    Depois de aprender este estranho fato, alguns podem se sentir tentados a usar um cdigo esquisito como

    este:

    myarr["name"]="Mr Whipple"

    print myarr["name"]

    No s este cdigo no resulta em erro, mas funcionalmente idntico aos nossos exemplos anteriores, e

    ir escrever "Mr. Whipple" da mesma forma! Como voc pode ver, o awk no nos limita a usar ndices

    com inteiros puros, podemos usar ndices string se quisermos, sem criar nenhum problema. Onde quer

    que usemos ndices de array no-inteiros, como myarr["name"], estamos usando arrays associativos.

    Tecnicamente, o awk no est fazendo nada diferente nos bastidores quando usamos um ndice string

    (uma vez que mesmo que voc usar um ndice "inteiro", o awk ainda ir tratar ele como string).

    Entretanto, voc ainda assim deve cham-los de arrays associativos -- soa mais interesssante e ir

    impressionar seu chefe. O ndice stringy ser nosso pequeno segredo. :)

    Ferramentas para arrays

    Quando se trata de arrays, o awk nos d bastante flexibilidade. Podemos usar ndices string, e no somos

    obrigados a usar seqncias numricas contnuas de ndices (por exemplo, podemos definir myarr[1] e

    myarr[1000], e deixar todos os outros elementos indefinidos). Apesar de isto poder ser bastante til,

    em algumas circunstncias pode causar confuses. Felizmente, o awk oferece um par de funcionalidades

    para ajudar a tornar os arrays mais gerenciveis.

  • Primeiro, podemos excluir elementos de arrays. Se voc quer excluir o elemento 1 do seu array

    fooarray, escreva:

    delete fooarray[1]

    E, se voc quer ver se um determinado elemento do array existe, pode usar o operador booleano especial

    "in" conforme segue:

    if ( 1 in fooarray ) {

    print "Ayep! It's there."

    } else {

    print "Nope! Can't find it."

    }

    Na prxima vez

    Ns j cobrimos bastante cho neste artigo. Na prxima vez, eu irei arredondar seu conhecimento awk

    mostrando como usar as funes matemticas e de string do awk e como criar suas prprias funes.

    Tambm irei percorrer os passos da criao de um programa de balano de cheques. At l, eu encorajo

    voc a escrever alguns programas awk seus, e checar os seguintes recursos.

    Recursos

    Leia o Awk em exemplos, Parte 1

    Se voc do tipo que prefere um livro, o sed & awk, 2nd edition uma escolha excelente.

    Certifique-se de checar o FAQ do comp.lang.awk. Ele tambm muitos links adicionais sobre o awk.

    O awk tutorial, de Patric Hartigan, vem com muitos scripts awk teis.

    O Thompson's TAWK Compiler, compila scripts awk em executveis binrios bem rpidos. Existem verses disponveis para Windows, OS/2, DOS e UNIX.

    O GNU Awk User's Guide est disponvel como referncia online.

    Sobre o autor

    Residindo em Albuquerque, New Mexico, Daniel Robbins o Presidente/CEO da Gentoo Technologies,

    Inc., o criador do Gentoo Linux, um Linux avanado para o PC, e o sistema Portage, a prxima gerao

    de sistema de ports para o Linux. Ele tambm tem servido como autor para os livros da Macmillan

    Caldera OpenLinux Unleashed, SuSE Linux Unleashed, e Samba Unleashed. Daniel est envolvido com

    computadores de alguma forma desde o segundo grau, quando foi exposto pela primeira vez para a

    linguagem de programao Logo, bem como a uma dose perigosa de Pac Man. Isto provavelmente

    explica por que ele tem trabalhado como Lead Graphic Artist na SONY Electronic

    Publishing/Psygnosis. Daniel gosta de gastar seu tempo com sua esposa, Mary, e sua nova filhinha,

    Hadassah. Voc pode entrar em contato com Daniel no email [email protected].