"Gazeta do Linux... tornando o Linux um pouco mais divertido!"


Aprendendo Perl, Parte 1

Por Ben Okopnik

Tradução por Bill Bennett
12 de Junho de 2001, para Gazeta do Linux


Se você vem usando o Linux por algum tempo, provavelmente ouviu falar do Perl; talvez tenha até executado alguns scripts, mesmo sem saber. Programas como "inews", "mirror", "debconf", "madjordomo", "sirc" e muitos outros foram escritos inteiramente em Perl. Utilizando o "zgrep" no arquivo "Packages.gz" no debian, descobrimos que 382 dos pacotes dependem do Perl (o que significa que uma parte importante do pacote com ele foi escrita), e outros 28 ou sugerem ou recomendam-o.
 

Então, Para Que Serve?

"Perl é ótimo para processamento de texto, e para integrar e manter as coisas juntas. Para uma linguagem script, todos os outros aspectos permanecem os mesmos."
 -- John Ousterhout, autor da linguagem de script Tcl

"Perl" significa "Practical Extraction and Report Language". Parece complicado, mas é necessário para você convencer seu chefe a usá-lo. Aliás, Larry Wall <larry@wall.org> (o autor do Perl) diz no manual do Perl: "Perl significa na prática Pathologically Eclectic Rubbish Lister, mas não diga pra ninguém que eu disse isso." Umm... OK, Larry. Minha boca é um túmulo.

O Perl já foi classificado como uma "linguagem de script com ilusão de uma linguagem completa", "O Canivete Suiço do Unix", "A Fita-cola da Internet", e outros... umm... nomes. Foi muito usado para escrever scripts de apenas uma linha, programas de execução rápida, grandes projetos (todo o editorial da Amazon.com bem como seu sistema de controle, sistema de gerência de conteúdo da netscape e seu sistema de entrega, o projeto Genoma para decodificação do DNA humano, etc.), e milhões de programas rápidos que executam uma enorme variedade de tarefas.  O Perl pode também emular um grande número de utilitários do sistema Unix (dica: se você pretende aprender 'awk', 'sed', 'grep', e 'tr', eu recomendo começar com Perl. Você terá a mesma funcionalidade, mais velocidade e nunca vai estourar suas capacidades. Se eu soubesse disso antes...)

Como é esperado de qualquer linguagem moderna, Perl permite programação orientada a objetos. Também suporta comunicações (sockets, etc.), sendo fácilmente portável (um script bem escrito pode rodar no Linux, BSD, Solaris, DOS, Win9x, NT, MacOS, OS/2, AmigaOS, VMS, etc., sem qualquer modificação), e possui um ciclo muito curto de programação/depuração - não é necessária a compilação; você inclui as modificações e executa o script. Existem muitos módulos (rotinas Perl pré-construídas) para executar qualquer tarefa; o "Comprehensive Perl Archive Network" (CPAN) é uma grande referência para programadores.
 

OK, Mas O Que É De Verdade??

Boa pergunta. Espero que, depois de usá-lo por um ano, você possa me dizer. Qualquer descrição é inconsistente... e ainda estou procurando uma boa definição para o Perl (de preferência uma forte e imediata.)
 

No Que o Perl Não É Bom?

Hmmm. Eu não usaria para fazer um processador de textos gráfico, um video game ou um navegador gráfico. No entanto, o Perl pode dar um excelente acabamento para outras linguagens, de modo que você possa fazer todas essas coisas - mas na minha opinião, existem maneiras mais eficientes de realizar essas tarefas usando outras linguagens. "Para um homem com um martelo, todo problema parece um prego" - estejam avisados!

Note também que o Perl não foi escrito em Perl; nem tão pouco o kernel do Linux. Para programas de baixo-nível devemos usar C/C++ com um pouco de assembler; "as ferramentas certas para as tarefas certas" deve ser o moto dos programadores.
 

Um Último Aviso Antes de Começarmos

Se você sabe um pouco de Perl, e encontrar algo diferente do que aprendeu, lembre-se do Mandamento Perl: Sempre Existe Mais De Uma Maneira De Executar Uma Tarefa. Esta é a filosofia básica do Perl. Correções no código serão bem-vindas.

Para quem já leu alguma coisa sobre scripts vai se lembrar que devemos sempre iniciá-los com a seguinte linha:

#! /bin/bash

Ela diz ao shell para criar um subshell onde será executado o código pelo programa especificado. Esta linha também é necessária para scripts Perl - a primeira linha deve ser:

#! /usr/bin/perl

ou qualquer que seja o caminho do seu executável perl.

Note os requesitos para esta linha:

1) Deve ser a primeira linha do script.
2) O sinal de cardinal (#) deve ser o primeiro caractére da linha, e não pode haver nada entre ela e a exclamação(!).
3) Você deve usar o caminho completo, e não só o nome do executável.

Vamos então criar o nosso primeiro script em Perl:


#!/usr/bin/perl
# "goodbye" - a modern, high-angst replacement for "Hello World"

print "Goodbye, cruel world!\n";
unlink $0;

Bem... pelo menos ele disse adeus antes de ir. O que acabamos de fazer? Muitas coisas são bastante óbvias: primeiro, a linha "#!"; depois, uma linha que nos diz o que o script faz - uma herança do shell scripting, que foi uma excelente idéia (não há nada parecido a não ser os comentários de código!) Depois, nós imprimimos uma mensagem usando a função "print". Note o "\n" no final da string: Perl não muda de linha automaticamente, por isso você deve decidir se o quer fazer. Note também o ponto-e-vírgula no final da sentença: assim como o C, Perl exige que o usemos para indicar o final de uma instrução. Aliás, a verificação de erros do Perl é muito boa, pois seu código é bem legível; são apenas os pontos-e-vírgulas, que separam sentenças, que causam erros a serem reportados na próxima linha. Se você já esté acostumado, tudo bem. Senão, nunca se esqueça dos pontos-e-vírgulas.

A última linha é que apaga o arquivo. O "$0" é só uma referência ao script que está sendo executado, e unlink faz o mesmo que "rm". Note que "$0" é muito mais útil que "goodbye", ou até "./goodbye" - não importa o nome do arquivo, "$0" retorna esse nome.
 

Não Se Esqueça Da Identação

Estamos longe de escrevermos um código com perfeição, mas há pouco tempo escrevi um código só para escrita que se apresentava em várias cores quando alguém tentava lê-lo. Estou tentando melhorar cada vez mais - e gostaria de vê-lo fazendo o mesmo.

O Perl trata espaços vazios - tabulações e espaços em branco - como eles merecem; ou seja, ignorando-os. Por causa disso, você pode estruturar o código Perl para abstrair a idéia principal do script. Veja o exemplo abaixo:

@boats = ("Aloa", "Cheoy Lee", "Pearson", "Mason", "Swan", "Westsail", "S2", "Petersen", "Hereshoff");  # List of sailboats

Aqui nós preenchemos um vector chamado '@boats' com barcos. OK, isso funciona - mas poderia ser mais legível:

@array = ("Aloa",       # French OSTAR/IOR boat
         "Cheoy Lee",   # Comfortable but expensive
         "Pearson",     # Strong but rather heavy
         "Mason",       # Well designed, but a bit of a pig
         "Swan",        # Classy boat - if you've got the money
         "Westsail",    # Wetsnails are OK, for double-enders
         "S2",          # Nice bay boats - not for offshore use
         "Petersen",    # Steel world cruiser, roomy but slow
         "Hereshoff");  # Fast and gorgeous; cramped and expensive

Esta organização não é útil só para o Perl. A maioria das linguagens modernas permitem-nos usarmos espaços em branco para tornar o código mais legível. Durante a nossa jornada, eu farei o melhor que puder para mostrar pelo menos a minha versão de um bom código; gostaria de encorajar a todos a desenvolverem seu próprio estilo.
 

Variáveis

No Perl, o objetivo é a simplicidade. É também chamado de uma linguagem não-tipada, pois as variáveis não são restringidas a um único tipo; de fato, não há como definir uma variável para guardar apenas um número real de 32 bits.

Os três tipos de variáveis do Perl são escalares, vectores, e hashes. Apesar dos nomes assustadores, eles são bem simples: apenas variáveis para guardar tipos diferentes de informações.

Escalares - números, strings ou referências
Uma variável escalar é declarada com um '$', como: $num, $joe, $pointer
Exemplos:
"0.0421", "Joe's glove", memory location "0xA000"

Vectores - listas sequenciais e ordenadas de escalares
Uma variável vector é declarada com um '@', como @v, @list, @variable
       Exemplo:
   0 - "Sunday"
   1 - "Monday"
   2 - "Tuesday"
   3 - "Wednesday"
   ...

Hashes - chaves de referências a listas de escalares
Hashes são declarados com um '%', como %people, %x, %this_is_a_hash
       Exemplo:
   resident - "Sherlock Holmes"
   addr     - "221B Baker Street"
   code     - "NW1"
   city     - "London"
   country  - "GB"
   job      - "sleuth"
   ...

Note que os vectores são ordenados numericamente, mas os hashes não - ler o primeiro elemento de um hash não tem normalmente a haver com o primeiro elemento que você colocou nele. Hashes são referenciados por suas chaves, e não por suas posições na estrutura.

Com esses três tipos de dados você pode guardar (ou apontar) qualquer coisa que quiser - e facilmente acessar o que guardou.

Outra nota importante: $a, @a, and %a são completamente diferentes uns dos outros. Eles estão em espaços de nomes diferentes. Tenho muito cuidado em não usr nomes visualmente conflituantes como esses nos meus programas, especialmente porque coisas como $a[0] (uma referência para o primeiro elemento do vector @a) existem - é algo que você realmente precisa saber.
 

Já que as variáveis podem conter diferentes tipos de dados - numéricos ou strings - precisaremos de operadores que funcionem para ambos. O Perl oferece os seguintes operadores:

   Operador                   Num     Str
   --------------------------------------
   Igual                      ==      eq
   Diferente                  !=      ne
   Menor que                   <      lt
   Maior que                   >      gt
   Menor ou igual             <=      le
   Maior ou igual             >=      ge

Fácil mnemônica - quando comparar letras (strings), use letras.

Como gosto de dar exemplos concretos, aqui está um para você arrancar os cabelos:

#!/usr/bin/perl
# A political evaluation script

$a = "Al";
$b = "George";

if ( $a > $b)   { print "$a would make a better President.\n"; }
if ( $a < $b)   { print "$b would make a better President.\n"; }
if ( $a == $b)  { print "$a or $b, there's no difference...\n"; }

Hmmm... A saída diz que não há diferença. O que é na verdade correto, mas e quanto às comparações? Ah, sim... Devíamos ter usado comparadores de strings, não é?


#!/usr/bin/perl
# A political evaluation script

$a = "Al";
$b = "George";

if ( $a gt $b)   { print "$a would make a better President.\n"; }
if ( $a lt $b)   { print "$b would make a better President.\n"; }
if ( $a eq $b)   { print "$a or $b, there's no difference...\n"; }

Agora os operadores de comparação funcionam corretamente, (mas não obedece à lógica do mundo real...mas estou a divagar).

Aliás, porque o Perl decidiu que "Al" é igual a "George" no primeiro exemplo? Desde quando os programas têm opiniões políticas?

É importante saber a razão: tem haver com o modo com que o Perl separa o verdadeiro do falso. Já que todos os nossos testes - "if", "while", "until", etc. - dependem desta distinção, precisamos entendê-la bem.

"0" significa falso, idependente se é um número ou string.
Todas as variáveis não definidas (aquelas que não demos valor algum) são falsas.
Uma string vazia - "" ou '' - é falsa.
Todo o resto é verdadeiro.

Vamos ver se você entendeu - veja os valores relacionados abaixo e decida se eles são verdadeiros ou falsos:

"00"    "-1"    " "    "5 - 5"

Veja as respostas na nota [1] no final deste artigo.
 

Outro aspecto importante é a interpolação de variáveis, onde podemos determinar se uma coisa entre apóstrofes deve ser interpretada ou não. Aqui está um exemplo:

$name =  'Bessie';
print    'Our cow is named $name.';

Opa! O resultado é:

Our cow is named $name.

Na minha opinião uma vaca com um pouco de respeito próprio não te obedeceria se você a chamasse assim (sem mencionar a dificuldade na pronúncia). Então, como faremos pra chamar a Bessie?

# Note the double quotes where the singles used to be!
$name =  'Bessie';
print    "Our cow is named $name.";

Sucesso total! Eu disse que podíamos fazer qualquer coisa com o Perl, não disse?

E se quiséssemos imprimir o nome da variável também? Isso é muito fácil no Perl.

$joe =   "Joe";
print    "The variable \$joe contains the value $joe.";

Podemos imprimir qualquer meta-caractére assim, ou seja, caractéres que possuem um significado especial para o Perl, se colocarmos uma barra antes. Agora veja isso:

$joe =   "Joe";
print    "The variable \"\$joe\" contains the value \"$joe.\"";

E isso:

print    'The variable "$joe" contains the value "', $joe, '".';

Raciocine um pouco e tenha certeza de que entendeu a diferença. Note que valores separados no "print" utilizam a vírgula como separador - sem ela, a sentença tem um significado totalmente diferente, o qual discutiremos no próximo artigo.

Antes de juntarmos tudo, façamos a seguinte consideração: quando criar o seu arquivo de script, sempre use o parâmetro "-w" como parte do cabeçalho:

#! /usr/bin/perl -w

Com isso o Perl gera avisos que nos dizem onde estão os problemas no script. Todo iniciante deve utilizar este recurso... e principalmente quem já é um expert! Os erros não somem a medida que você evolui; eles evoluem junto com você. :)
 

Juntando Tudo

Desta vez nós percorremos uma bela jornada, pulando os obstáculos comuns de qualquer introdução. No próximo mês vamos nos aprofundar mais; talvez explorando vectores e hashes, ou até mergulharmos de cabeça nas poderosas expressões regulares, ou "regexes" em Perl. Por enquanto, minha sugestão é que você pratique um pouco o que nós falamos, fazendo suas próprias experiências - esta é a melhor maneira de se aprender uma linguagem, onde podemos ir até o limite e então perturbar alguém que saiba mais para nos ajudar. Não se consegue boas respostas quando não temos nem a pergunta.

Boa sorte!
 

Ben Okopnik
perl -we '$@="\145\143\150\157\040\042\112\165\163\164\040\141\156".
"\157\164\150\145\162\040\120\145\162\154\040\110\141\143\153\145\162".
"\042\040\076\040\057\144\145\166\057\164\164\171";`$@`'

Nota [1]: Todos verdadeiros. Nenhum cabe nas categorias "falsa": "00" não é a mesma coisa que "0"; nem o "-1". Um espaço, " ", não é a mesma coisa que uma string vazia (""), e "5 - 5", a não ser que seja calculado, não é "0".

Referências: "Perl: The Complete Reference", Martin C. Brown

Páginas relevantes do manual de Perl (disponível em qualquer sistema que utiliza Perl):

perl      - overview               perlfaq   - frequently asked questions
perltoc   - doc TOC                perldata  - data structures
perlsyn   - syntax                 perlop    - operators and precedence
perlrun   - execution              perlfunc  - builtin functions
perltrap  - traps for the unwary   perlstyle - style guide

"perldoc" e "perldoc -f"


Copyright © 2000, Ben Okopnik.
Traduzido por Bill Bennett.
Licença de Cópia http://www.linuxgazette.com/copying.html
Publicado na Edição 61 da Gazeta do Linux, em Janeiro de 2001