SlideShare une entreprise Scribd logo
1  sur  6
Télécharger pour lire hors ligne
Linux User                                       Papo de Botequim




                                                                       Papo de Botequim
                                                                       Curso de Shell Script



                                                                                                                                                Parte X

                                          Dave Hamilton - www.sxc.hu
                                                                       Em mais um capítulo de nossa saga através do mundo do
                                                                       Shell Script, vamos aprender a avaliar expressões, capturar
                                                                       sinais e receber parâmetros através da linha de comando.
                                                                       por Júlio Cezar Neves




     E
         aê amigo, te dei a maior moleza na                            a legibilidade do código está “horrorível”,   O comando eval
         última aula né? Um exerciciozinho                             mas o desempenho, isto é, a velocidade        Vou te dar um problema que eu duvido
         muito simples…                                                de execução, está ótimo. Como funções         que você resolva:
     – É, mas nos testes que eu fi z, e de                              são coisas muito pessoais, já que cada
  acordo com o que você ensinou sobre                                  um usa as suas e quase não há neces-          $ var1=3
  substituição de parâmetros, achei que                                sidade de manutenção, eu sempre opto          $ var2=var1
  deveria fazer algumas alterações nas fun-                            pelo desempenho.
  ções que desenvolvemos para torná-las de                                Hoje vamos sair daquela chatura que          Te dei essas duas variáveis e quero que
  uso geral, como você disse que todas as                              foi o nosso último papo e voltar à lógica,    você me diga como eu posso, me referindo
  funções deveriam ser. Quer ver?                                      saindo da decoreba. Mas volto a te lem-       apenas à variável a var2, listar o valor de
     – Claro, né, mané, se te pedi para fazer                          brar: tudo que eu te mostrei da última vez    var1 (que, no nosso caso, é 3).
  é porque estou a fi m de te ver aprender,                             aqui no Boteco do Chico é válido e quebra       – Ah, isso é mole, mole! É só digitar
  mas peraí, dá um tempo. Chico! Manda                                 um galhão. Guarde aqueles guardanapos         esse comando aqui:
  dois, um sem colarinho! Vai, mostra aí                               que rabiscamos porque, mais cedo ou
  o que você fez.                                                      mais tarde, eles lhe vão ser muito úteis.     echo $`echo $var2`
     – Bem, além do que você pediu, eu
  reparei que o programa que chamava a                                                            Listagem 1: função pergunta.func
  função teria de ter previamente defi nidas                             01   # A função recebe 3 parâmetros na seguinte ordem:
  a linha em que seria mostrada a mensa-                                02   # $1 - Mensagem a ser mostrada na tela
  gem e a quantidade de colunas. O que                                  03   # $2 - Valor a ser aceito com resposta padrão
  fi z foi incluir duas linhas – nas quais                               04   # $3 - O outro valor aceito
  empreguei substituição de parâmetros                                  05   # Supondo que $1=Aceita?, $2=s e $3=n, a linha
 – para que, caso uma dessas variáveis não                              06   # abaixo colocaria em Msg o valor "Aceita? (S/n)"
                                                                        07   TotCols=${TotCols:-$(tput cols)} # Se não estava definido, agora está
  fosse informada, ela recebesse um valor
                                                                        08   LinhaMesg=${LinhaMesg:-$(($(tput lines)-3))} # Idem
  atribuído pela própria função. A linha
                                                                        09   Msg="$1 (`echo $2 | tr a-z A-Z`/`echo $3 | tr A-Z a-z`)"
  de mensagem é três linhas antes do fi m                                10   TamMsg=${#Msg}
  da tela e o total de colunas é obtido pelo                            11   Col=$(((TotCols - TamMsg) / 2))    # Para centralizar Msg na linha
  comando tput cols. Dê uma olhada na                                   12   tput cup $LinhaMesg $Col
  listagem 1 e veja como ficou:                                          13   read -n1 -p "$Msg " SN
     – Gostei, você já se antecipou ao que eu                           14   SN=${SN:-$2}                       # Se vazia coloca o padrão em SN
  ia pedir. Só pra gente encerrar esse papo                             15   SN=$(echo $SN | tr A-Z a-z)        # A saída de SN será em minúsculas
                                                                        16   tput cup $LinhaMesg $Col; tput el # Apaga Msg da tela
  de substituição de parâmetros, repare que


86   julho 2005                     edição 10
                                                                       www.linuxmagazine.com.br
Papo de Botequim                  Linux User




  Repare que eu coloquei o echo $var2 entre crases (`), porque        $ var2=ls
dessa forma ele terá prioridade de execução e resultará em var1.      $ $var2
E echo $var1 produzirá 3…                                             10porpag1.sh alo2.sh           incusu        logado
  – Ah, é? Então execute para ver se está correto.                    10porpag2.sh ArqDoDOS.txt1 listamusica       logaute.sh
                                                                      10porpag3.sh confuso           listartista   mandamsg.func
$ echo $`echo $var2`                                                  alo1.sh         contpal.sh     listartista3 monbg.sh
$var1
                                                                        Agora vamos colocar em var2 o seguinte: ls $var1; e em
  – Ué! Que foi que aconteceu? O meu raciocínio me parecia           var1 vamos colocar l*, vejamos o resultado:
bastante lógico…
  – O seu raciocínio realmente foi lógico, o problema é que você      $ var2='ls $var1'
esqueceu de uma das primeiras coisas de que te falei aqui no          $ var1='l*'
Boteco e que vou repetir. O Shell usa a seguinte ordem para           $ $var2
resolver uma linha de comando:                                        ls: $var1: No such file or directory
P Resolve os redirecionamentos;                                       $ eval $var2
P Substitui as variáveis pelos seus valores;                          listamusica listartista listartista3 logado logaute.sh
P Resolve e substitui os meta caracteres;
P Passa a linha já toda esmiuçada para execução.                       Novamente, no tempo de substituição das variáveis, $var1
  Dessa forma, quando o interpretador chegou na fase de re-          ainda não havia se apresentado ao Shell para ser resolvida.
solução de variáveis, que como eu disse é anterior à execução,       Assim, só nos resta executar o comando eval para dar as duas
a única variável existente era var2 e por isso a tua solução         passadas necessárias.
produziu como saída $var1. O comando echo identificou isso              Uma vez um colega da excelente lista de discussão groups.yahoo.com/
como uma cadeia de caracteres e não como uma variável.               group/shell-script colocou uma dúvida: queria fazer um menu
  Problemas desse tipo são relativamente freqüentes e seriam         que numerasse e listasse todos os arquivos com extensão .sh e,
insolúveis caso não existisse a instrução eval, cuja sintaxe é       quando o operador escolhesse uma opção, o programa corres-
eval cmd, onde cmd é uma linha de comando qualquer, que              pondente fosse executado. Veja minha proposta na listagem 2:
você poderia inclusive executar direto no prompt do terminal.
Quando você põe o eval na frente, no entanto, o que ocorre é                              Listagem 2: fazmenu.sh
que o Shell trata cmd como um parâmetro do eval e, em seguida,         01   #!/bin/bash
o eval executa a linha recebida, submetendo-a ao Shell. Ou             02   #
seja, na prática cmd é analisado duas vezes. Dessa forma, se           03   # Lista que enumera os programas com extensão .sh no
executássemos o comando que você propôs colocando o eval               04   # diretório corrente e executa o escolhido pelo operador
                                                                       05   #
na frente, teríamos a saída esperada. Veja:
                                                                       06   clear; i=1
                                                                       07   printf "%11st%snn" Opção Programa
$ eval echo $`echo $var2`                                              08   CASE='case $opt in'
3                                                                      09   for arq in *.sh
                                                                       10   do
 Esse exemplo também poderia ter sido feito de outra maneira.          11        printf "t%03dt%sn" $i $arq
                                                                       12        CASE="$CASE
Dá só uma olhada:
                                                                       13        "$(printf "%03d)t %s;;" $i $arq)
                                                                       14        i=$((i+1))
$ eval echo $$var2                                                    15   done
3                                                                      16   CASE="$CASE
                                                                       17          *)        . erro;;
  Na primeira passada a contrabarra () seria retirada e $var2         18   esac"
                                                                       19   read -n3 -p "Informe a opção desejada: " opt
seria resolvido produzindo var1. Na segunda passada teria so-
                                                                       20   echo
brado echo $var1, que produziria o resultado esperado. Agora           21   eval "$CASE"
vou colocar um comando dentro de var2 e executar:


                                                                                              julho 2005                        edição 10    87
                                                                   www.linuxmagazine.com.br
Linux User               Papo de Botequim




       Parece complicado porque usei muitos      dos por) processos em execução. Vamos, "limpar a área" ao seu término. Se seu
     printf para formatação da tela, mas na      de agora em diante, dar uma olhadinha     encerramento ocorrer de forma prevista,
  verdade é bastante simples: o primei-          nos sinais enviados aos processos e mais  ou seja, se tiver um término normal, é
  ro printf foi colocado para imprimir           à frente vamos dar uma passada rápida     muito fácil fazer essa limpeza; porém,
  o cabeçalho e logo em seguida come-            pelos sinais gerados pelos processos. se o seu programa tiver um fim brusco,
  cei a montar dinamicamente a variável          Para mandar um sinal a um processo, muita coisa ruim pode ocorrer:
  $CASE, na qual ao final será feito um eval      usamos normalmente o comando kill, P É possível que em um determinado es-
  para execução do programa escolhido.           cuja sintaxe é:                             paço de tempo, o seu computador esteja
  Repare no entanto que dentro do loop                                                       cheio de arquivos de trabalho inúteis
  do for existem dois printf: o primeiro          $ kill -sig PID                          P Seu processador poderá ficar atolado
  serve para formatar a tela e o segundo                                                     de processos zombies e defuncts gera-
  para montar o case (se antes do coman-           Onde PID é o identificador do proces-      dos por processos filhos que perderam
  do read você colocar uma linha echo            so (Process Identification ou Process ID).   os pais e estão “órfãos”;
 "$CASE", verá que o comando case mon-           Além do comando kill, algumas seqüên- P É necessário liberar sockets abertos para
  tado dentro da variável está todo inden-       cias de teclas também podem gerar sinais.   não deixar os clientes congelados;
  tado. Frescura, né?:). Na saída do for, foi    A tabela 1 mostra os sinais mais impor- P Seus bancos de dados poderão ficar
  adicionada uma linha à variável $CASE          tantes para monitorarmos:                   corrompidos porque sistemas gerencia-
  para, no caso de uma escolha inválida,           Além desses, existe o famigerado si-      dores de bancos de dados necessitam
  ser executada uma função externa para          nal -9 ou SIGKILL que, para o processo      de um tempo para gravar seus buffers
  exibir mensagens de erro. Vamos execu-         que o está recebendo, equivale a meter      em disco (commit).
  tar o script para ver a saída gerada:          o dedo no botão de desligar do compu-       Enfim, existem mil razões para não usar
                                                 tador – o que é altamente indesejável, um kill com o sinal -9 e para monitorar o
     $ fazmenu.sh                                já que muitos programas necessitam        encerramento anormal de programas.
           Opcao     Programa
                                                                        Listagem 3: Nova versão do fazmenu.sh
             001     10porpag1.sh
                                                  01 #!/bin/bash
             002     10porpag2.sh
                                                  02 #
             003     10porpag3.sh                 03 # Lista enumerando os programas com extensão .sh no
             004     alo1.sh                      04 # diretório corrente; executa o escolhido pelo operador
             005     alo2.sh                      05 #
             006     contpal.sh                   06 clear; i=1
             007     fazmenu.sh                   07 printf "%11st%snn" Opção Programa
             008     logaute.sh                   08 CASE='case $opt in'
             009     monbg.sh                     09 for arq in *.sh
             010     readpipe.sh                  10 do
             011     redirread.sh                 11      printf "t%03dt%sn" $i $arq
     Informe a opção desejada:                    12      CASE="$CASE
                                                  13      "$(printf "%03d)t %s;;" $i $arq)
       Seria interessante incluir uma opção       14      i=$((i+1))
     para terminar o programa e, para isso,       15 done
     seria necessária a inclusão de uma linha     16 printf "t%dt%snn" 999 "Fim do programa" # Linha incluída
     após o loop de montagem da tela e a alte-    17 CASE="$CASE

     ração da linha na qual fazemos a atribui-    18      999)          exit;;                      # Linha alterada

     ção final do valor da variável $CASE. Veja    19         *)         ./erro;;
                                                  20 esac"
     na listagem 3 como ele ficaria:
                                                  21 read -n3 -p "Informe a opção desejada: " opt
       Existe no Linux uma coisa chamada
                                                  22 echo
     sinal (signal). Existem diversos sinais
                                                  23 eval "$CASE"
     que podem ser mandados para (ou gera-


88    julho 2005                     edição 10
                                                 www.linuxmagazine.com.br
Papo de Botequim               Linux User



O comando trap                                 Caso a transferência seja interrompida               Tabela 1: Principais sinais
Para fazer a monitoração de sinais existe    por um kill ou um [CTRL]+[C], certa-
                                                                                             Código       Nome     Gerado por:
o comando trap, cuja sintaxe pode ser        mente deixará lixo no disco. É exatamen-
                                                                                                0          EXIT  Fim normal do programa
uma das mostradas a seguir:                  te essa a forma mais comum de uso do               1        SIGHUP  Quando o programa
                                             comando trap. Como isso é trecho de                                 recebe um kill -HUP
trap "cmd1; cmd2; cmdn" S1 S2 … SN           um script devemos, logo no início dele,            2         SIGINT Interrupção pelo teclado.
trap 'cmd1; cmd2; cmdn' S1 S2 … SN           digitar o comando:                                                  ([CTRL]+[C])
                                                                                                3        SIGQUIT Interrupção pelo teclado
                                                                                                                 ([CTRL]+[])
  Onde os comandos cmd1, cmd2, cmdn          trap "rm -f /tmp/$$ ; exit" 0 1 2 3 15
                                                                                               15        SIGTERM Quando o programa
serão executados caso o programa receba                                                                          recebe um kill ou
os sinais S1, S2 … SN. As aspas (") ou          Dessa forma, caso houvesse uma inter-                              kill -TERM
as apóstrofes (') só são necessárias caso    rupção brusca (sinais 1, 2 , 3 ou 15) antes
o trap possua mais de um comando cmd         do programa encerrar (no exit dentro do
associado. Cada uma delas pode ser tam-      comando trap), ou um fim normal (sinal      1º Caso: O comando ftp encontra-se
bém uma função interna, uma externa          0), o arquivo /tmp/$$ seria removido.    em script1. Nesse caso, o argumento do
ou outro script.                                Caso não houvesse a instrução exit    comando trap deveria vir entre aspas (")
  Para entender o uso de aspas (") e         na linha de comando do trap, ao final     porque, caso ocorresse uma interrupção
apóstrofes (') vamos recorrer a um           da execução dessa linha o fluxo do pro-   ([CTRL]+[C] ou [CTRL]+[]) no script2,
exemplo que trata um fragmento de            grama retornaria ao ponto em que estava  a linha só seria interpretada nesse mo-
um script que faz uma transferência de       quando recebeu o sinal que originou a    mento e o PID do script2 seria diferente
arquivos via FTP para uma máquina            execução desse trap.                     do encontrado em /tmp/$$ (não esqueça
remota ($RemoComp), na qual o usuário           Note também que o Shell pesquisa a    que $$ é a variável que contém o PID do
é $Fulano, sua senha é $Segredo e o          linha de comando uma vez quando o trap   processo ativo);
arquivo a ser enviado é $Arq. Suponha        é interpretado (e é por isso que é usual   2º Caso: O comando ftp encontra-se
ainda que essas quatro variáveis foram       colocá-lo no início do programa) e nova- em script2. Nesse caso, o argumento
recebidas por uma rotina anterior de         mente quando um dos sinais listados é    do comando trap deveria estar entre
leitura e que esse script seja muito usado   recebido. Então, no último exemplo, o va-apóstrofes ('), pois caso a interrupção
por diversas pessoas. Vejamos o trecho       lor de $$ será substituído no momento em se desse durante a execução de script1,
de código a seguir:                          que o comando trap é lido pela primeira  o arquivo não teria sido criado; caso ela
                                             vez, já que as aspas (") não protegem o  ocorresse durante a execução de script2,
ftp -ivn $RemoComp << FimFTP >> /tmp/$$ U    cifrão ($) da interpretação do Shell.    o valor de $$ seria o PID desse processo,
2>> /tmp/$$                                     Se você quisesse fazer a substituição que coincidiria com o de /tmp/$$.
    user $Fulano $Segredo                    somente ao receber o sinal, o comando      O comando trap, quando executado
    binary                                   deveria ser colocado entre apóstrofes (').
                                                                                      sem argumentos, lista os sinais que estão
    get $Arq                                 Assim, na primeira interpretação do trap,sendo monitorados no ambiente, bem
FimFTP                                       o Shell não veria o cifrão ($), as apóstro-
                                                                                      como a linha de comando que será exe-
                                             fes (') seriam removidas e, finalmente, o cutada quando tais sinais forem recebidos.
  Repare que tanto as saídas dos diálo-                                               Se a linha de comandos do trap for nula
                                             Shell poderia substituir o valor da variá-
gos do FTP como os erros encontrados         vel. Nesse caso, a linha ficaria assim:   (vazia), isso significa que os sinais espe-
estão sendo redirecionados para /tmp/$$,                                              cificados devem ser ignorados quando
o que é uma construção bastante comum         trap 'rm -f /tmp/$$ ; exit' 0 1 2 3 15  recebidos. Por exemplo, o comando trap
para arquivos temporários usados em                                                  "" 2 especifica que o sinal de interrup-
scripts com mais de um usuário, porque          Suponha dois casos: você tem dois     ção ([CTRL]+[C]) deve ser ignorado. No
$$ é a variável que contém o número do       scripts que chamaremos de script1, cuja  último exemplo, note que o primeiro ar-
processo (PID), que é único. Com esse        primeira linha será um trap, e script2, gumento deve ser especificado para que o
tipo de construção evita-se que dois ou      colocado em execução por script1. Por    sinal seja ignorado e não é equivalente a
mais usuários disputem a posse e os di-      serem dois processos diferentes, terão   escrever trap 2, cuja finalidade é retornar
reitos sobre um arquivo.                     dois PIDs distintos.                     o sinal 2 ao seu estado padrão.         ➟

                                                                                            julho 2005                           edição 10   89
                                                                 www.linuxmagazine.com.br
Linux User                 Papo de Botequim




       Se você ignorar um sinal, todos os sub-       Para terminar esse assunto, abra um         cadeiadeopcoes deve ser abc. Se você
     shells irão ignorá-lo. Portanto, se você      console gráfico e escreva no prompt de         desejar que uma opção seja seguida por
     especificar qual ação deve ser tomada          comando o seguinte:                           um argumento, ponha um sinal de dois
     quando receber um sinal, todos os sub-                                                      pontos (:) depois da letra, como em a:bc.
     shells irão tomar a mesma ação quando          $ trap "echo Mudou o tamanho da janela" 28   Isso diz ao getopts que a opção -a tem a
     receberem esse sinal. Ou seja, os sinais                                                    forma -a argumento. Normalmente um
     são automaticamente exportados. Para o          Em seguida, pegue o mouse e arraste-o       ou mais espaços em branco separam o
     sinal mostrado (sinal 2), isso significa que   de forma a variar o tamanho da janela         parâmetro da opção; no entanto, getopts
     os sub-shells serão encerrados. Suponha       corrente. Surpreso? É o Shell orientado       também manipula parâmetros que vêm
     que você execute o comando trap "" 2 e        a eventos… Mais unzinho, porque não           colados à opção como em -aargumento.
     então execute um sub-shell, que tornará a     consigo resistir. Escreva isto:               cadeiadeopcoes não pode conter um si-
     executar outro script como um sub-shell.                                                    nal de interrogação (?).
     Se for gerado um sinal de interrupção,         $ trap "echo já era" 17                        O nome constante da linha de sintaxe
     este não terá efeito nem sobre o Shell                                                      acima define uma variável que receberá,
     principal nem sobre os sub-shell por ele         Em seguida digite:                         a cada vez que o comando getopts for
     chamados, já que todos eles ignorarão                                                       executado, o próximo dos parâmetros
     o sinal.                                       $ sleep 3 &                                  posicionais e o colocará na variável nome.
       Em korn shell (ksh) não existe a opção                                                    getopts coloca uma interrogação (?) na
     -s do comando read para ler uma senha.          Você acabou de criar um sub-shell que       variável definida em nome se achar uma
     O que costumamos fazer é usar usar o          irá dormir durante três segundos em           opção não definida em cadeiadeopcoes
     comando stty com a opção -echo, que           background. Ao fim desse tempo, você           ou se não achar o argumento esperado
     inibe a escrita na tela até que se encon-     receberá a mensagem “já era”, porque o        para uma determinada opção.
     tre um stty echo para restaurar essa          sinal 17 é emitido a cada vez em que um         Como já sabemos, cada opção passada
     escrita. Então, se estivéssemos usando o      sub-shell termina a sua execução. Para        por uma linha de comandos tem um ín-
     interpretador ksh, a leitura da senha teria   devolver esses sinais ao seu comporta-        dice numérico; assim, a primeira opção
     que ser feita da seguinte forma:              mento padrão, digite: trap 17 28.             estará contida em $1, a segunda em $2 e
                                                     Muito legal esse comando, né? Se você       assim por diante. Quando o getopts obtém
     echo -n "Senha: "                             descobrir algum material bacana sobre         uma opção, ele armazena o índice do
     stty -echo                                    uso de sinais, por favor me informe por       próximo parâmetro a ser processado na
     read Senha                                    email, porque é muito rara a literatura       variável OPTIND.
     stty echo                                     sobre o assunto.                                Quando uma opção tem um argumento
                                                                                                 associado (indicado pelo : na cadeiade-
        O problema com esse tipo de constru-       Comando getopts                               opcoes), getopts armazena o argumento
     ção é que, caso o operador não soubes-         O comando getopts recupera as opções e       na variável OPTARG. Se uma opção não
     se a senha, ele provavelmente teclaria         seus argumentos de uma lista de parâ-        possuir argumento ou se o argumento
     [CTRL]+[C] ou um [CTRL]+[] durante            metros de acordo com a sintaxe POSIX.2,      esperado não for encontrado, a variável
     a instrução read para descontinuar o pro-      isto é, letras (ou números) após um sinal    OPTARG será "apagada" (com unset). O co-
     grama e, caso agisse dessa forma, o seu        de menos (-) seguidas ou não de um           mando encerra sua execução quando:
     terminal estaria sem echo. Para evitar que     argumento; no caso de somente letras         P Encontra um parâmetro que não come-
     isso aconteça, o melhor a fazer é:             (ou números), elas podem ser agrupa-           ça com um hífen (-).
                                                    das. Você deve usar esse comando para        P O parâmetro especial -- indica o fim
     echo -n "Senha: "                             "fatiar" opções e argumentos passados           das opções.
     trap "stty echo                                para o seu script.                           P Quando encontra um erro (por exemplo,
           exit" 2 3                                   A sintaxe é getopts cadeiadeopcoes          uma opção não reconhecida).
     stty -echo                                     nome. A cadeiadeopcoes deve explicitar         O exemplo da listagem 4 é meramente
     read Senha                                     uma cadeia de caracteres com todas as        didático, servindo para mostrar, em um
     stty echo                                      opções reconhecidas pelo script; assim,      pequeno fragmento de código, o uso ple-
     trap 2 3                                       se ele reconhece as opções -a -b e –c,       no do comando.


90    julho 2005                       edição 10
                                                    www.linuxmagazine.com.br
Papo de Botequim                Linux User



  Para entender melhor, vamos executar o script:                OPTARG eh 'impressora'
                                                        Dispensando os primeiros $OPTIND-1 = 3 argumentos
$ getoptst.sh -h -Pimpressora arq1 arq2                 O que sobrou da linha de comandos foi 'arq1 arq2'
getopts fez a variavel OPT_LETRA igual a 'h'
        OPTARG eh ''                                     Repare, no exemplo a seguir, que se passarmos uma opção inválida a
getopts fez a variavel OPT_LETRA igual a 'P'           variável $OPT_LETRA receberá um ponto de interrogação (?) e a $OPTARG
        OPTARG eh 'impressora'                         será "apagada" (unset).
Dispensando os primeiros $OPTIND-1 = 2 argumentos
O que sobrou da linha de comandos foi 'arq1 arq2'       $ getoptst.sh -f -Pimpressora arq1 arq2 # A opção –f não é valida
                                                       ./getoptst.sh: illegal option -- f
  Dessa forma, sem ter muito trabalho, separei          getopts fez a variavel OPT_LETRA igual a '?'
todas as opções com seus respectivos argumentos,                OPTARG eh ''
deixando somente os parâmetros que foram passa-         getopts fez a variavel OPT_LETRA igual a 'P'
dos pelo operador para posterior tratamento. Repare             OPTARG eh 'impressora'
que, se tivéssemos escrito a linha de comando com       Dispensando os primeiros $OPTIND-1 = 2 argumentos
o argumento (impressora) separado da opção (-P),        O que sobrou da linha de comandos foi 'arq1 arq2'
o resultado seria exatamente o mesmo, exceto pelo
OPTIND, já que nesse caso ele identifica um conjun-         – Me diz uma coisa: você não poderia ter usado um condicional com
to de três opções (ou argumentos) e, no anterior,        case para evitar o getopts?
somente dois. Veja só:                                     – Poderia sim, mas para quê? Os comandos estão aí para serem usados…
                                                         O exemplo foi didático, mas imagine um programa que aceitasse muitas
$ getoptst.sh -h -P impressora arq1 arq2                 opções e cujos parâmetros poderiam ou não estar colados às opções, sen-
getopts fez a variavel OPT_LETRA igual a 'h'             do que as opções também poderiam ou não estar coladas: ia ser um case
        OPTARG eh ''                                     infernal! Com getopts, é só seguir os passos acima.
getopts fez a variavel OPT_LETRA igual a 'P'               – É… Vendo dessa forma, acho que você tem razão. É porque eu já estou
                                                                               meio cansado com tanta informação nova na minha
                        Listagem 4: getoptst.sh                                cabeça. Vamos tomar a saideira ou você ainda quer
 01 $ cat getoptst.sh                                                          explicar alguma particularidade do Shell?
 02 #!/bin/sh                                                                    – Nem um nem outro, eu também já cansei mas
 03                                                                            hoje não vou tomar a saideira porque estou indo
 04 # Execute assim:                                                           dar aula na UniRIO, que é a primeira universidade
 05 #                                                                          federal que está preparando seus alunos do curso
 06 #        getoptst.sh -h -Pimpressora arq1 arq2                             de graduação em Informática para o uso de Soft-
 07 #
                                                                               ware Livre. Mas antes vou te deixar um problema
 08 # e note que as informações de todas as opções são exibidas
                                                                               para te encucar: quando você varia o tamanho de
 09 #
 10 # A cadeia 'P:h' diz que a opção -P é uma opção complexa                   uma janela do terminal, no centro dela não aparece
 11 # e requer um argumento e que h é uma opção simples que não requer         dinamicamente, em vídeo reverso, a quantidade de
 12 # argumentos.                                                              linhas e colunas? Então! Eu quero que você repro-
 13                                                                            duza isso usando a linguagem Shell. Chico, traz
 14 while getopts 'P:h' OPT_LETRA                                              rapidinho a minha conta! Vou contar até um e se
 15 do                                                                         você não trouxer eu me mando!
 16      echo "getopts fez a variavel OPT_LETRA igual a '$OPT_LETRA'"
                                                                                 Não se esqueça, qualquer dúvida ou falta de compa-
 17      echo " OPTARG eh '$OPTARG'"
                                                                               nhia para um chope é só mandar um email para julio.
 18 done
 19 used_up=`expr $OPTIND – 1`
                                                                               neves@gmail.com. Vou aproveitar também para mandar
 20 echo "Dispensando os primeiros $OPTIND-1 = $used_up argumentos"           o meu jabá: diga para os amigos que quem estiver a
 21 shift $used_up                                                             fim de fazer um curso porreta de programação em
 22 echo "O que sobrou da linha de comandos foi '$*'"                          Shell que mande um e-mail para julio.neves@tecnohall.
                                                                               com.br para informar-se. Valeu!                   ■


                                                                                            julho 2005                   edição 10     91
                                                                www.linuxmagazine.com.br

Contenu connexe

Tendances

Aula 01 introdução a linguagem pascal
Aula 01   introdução a linguagem pascalAula 01   introdução a linguagem pascal
Aula 01 introdução a linguagem pascalTácito Graça
 
Aula 02 operadores aritiméticos
Aula 02   operadores aritiméticosAula 02   operadores aritiméticos
Aula 02 operadores aritiméticosTácito Graça
 
Conceitos e técnicas de programação aula 5
Conceitos e técnicas de programação aula 5Conceitos e técnicas de programação aula 5
Conceitos e técnicas de programação aula 5Robson Ferreira
 
Estrutura de Dados - Características da linguagem C - 2
Estrutura de Dados - Características da linguagem C - 2Estrutura de Dados - Características da linguagem C - 2
Estrutura de Dados - Características da linguagem C - 2Adriano Teixeira de Souza
 
Conceitos base de programação - parte 2
Conceitos base de programação - parte 2Conceitos base de programação - parte 2
Conceitos base de programação - parte 2João Piedade
 
Shell Script - Luz e trevas
Shell Script - Luz e trevasShell Script - Luz e trevas
Shell Script - Luz e trevasOsvaldo Filho
 
Aula 03 estrutura de seleção
Aula 03   estrutura de seleçãoAula 03   estrutura de seleção
Aula 03 estrutura de seleçãoTácito Graça
 
Introdução à Shellscript
Introdução à ShellscriptIntrodução à Shellscript
Introdução à ShellscriptVinícius Hax
 
Tutorial aed iii 008 - algoritmo de ordenação heapsort
Tutorial aed iii   008 - algoritmo de ordenação heapsortTutorial aed iii   008 - algoritmo de ordenação heapsort
Tutorial aed iii 008 - algoritmo de ordenação heapsortFlávio Freitas
 
Tutorial aed iii 007 - algoritmo de ordenação heapsort
Tutorial aed iii   007 - algoritmo de ordenação heapsortTutorial aed iii   007 - algoritmo de ordenação heapsort
Tutorial aed iii 007 - algoritmo de ordenação heapsortFlávio Freitas
 
Python: a primeira mordida
Python: a primeira mordidaPython: a primeira mordida
Python: a primeira mordidaBonoBee
 
Introdução ao php
Introdução ao phpIntrodução ao php
Introdução ao phpTiago Davi
 
Logica Algoritmo 05 Repeticao
Logica Algoritmo 05 RepeticaoLogica Algoritmo 05 Repeticao
Logica Algoritmo 05 RepeticaoRegis Magalhães
 
Aula 6 1 linguagem pascal-parte_1
Aula 6   1 linguagem pascal-parte_1Aula 6   1 linguagem pascal-parte_1
Aula 6 1 linguagem pascal-parte_1Duane Bertoldo
 
TDD em C++
TDD em C++TDD em C++
TDD em C++thiagodp
 

Tendances (19)

Aula 01 introdução a linguagem pascal
Aula 01   introdução a linguagem pascalAula 01   introdução a linguagem pascal
Aula 01 introdução a linguagem pascal
 
Javafx Introdução
Javafx IntroduçãoJavafx Introdução
Javafx Introdução
 
Aula 02 operadores aritiméticos
Aula 02   operadores aritiméticosAula 02   operadores aritiméticos
Aula 02 operadores aritiméticos
 
Conceitos e técnicas de programação aula 5
Conceitos e técnicas de programação aula 5Conceitos e técnicas de programação aula 5
Conceitos e técnicas de programação aula 5
 
Estrutura de Dados - Características da linguagem C - 2
Estrutura de Dados - Características da linguagem C - 2Estrutura de Dados - Características da linguagem C - 2
Estrutura de Dados - Características da linguagem C - 2
 
Conceitos base de programação - parte 2
Conceitos base de programação - parte 2Conceitos base de programação - parte 2
Conceitos base de programação - parte 2
 
Shell Script - Luz e trevas
Shell Script - Luz e trevasShell Script - Luz e trevas
Shell Script - Luz e trevas
 
Aula 03 estrutura de seleção
Aula 03   estrutura de seleçãoAula 03   estrutura de seleção
Aula 03 estrutura de seleção
 
Introdução à Shellscript
Introdução à ShellscriptIntrodução à Shellscript
Introdução à Shellscript
 
Algoritmos - capítulo 6
Algoritmos - capítulo 6Algoritmos - capítulo 6
Algoritmos - capítulo 6
 
Tutorial aed iii 008 - algoritmo de ordenação heapsort
Tutorial aed iii   008 - algoritmo de ordenação heapsortTutorial aed iii   008 - algoritmo de ordenação heapsort
Tutorial aed iii 008 - algoritmo de ordenação heapsort
 
Aula 05 subprogramas
Aula 05   subprogramasAula 05   subprogramas
Aula 05 subprogramas
 
Algoritmos - Aula 07 A - Lacos
Algoritmos - Aula 07 A - LacosAlgoritmos - Aula 07 A - Lacos
Algoritmos - Aula 07 A - Lacos
 
Tutorial aed iii 007 - algoritmo de ordenação heapsort
Tutorial aed iii   007 - algoritmo de ordenação heapsortTutorial aed iii   007 - algoritmo de ordenação heapsort
Tutorial aed iii 007 - algoritmo de ordenação heapsort
 
Python: a primeira mordida
Python: a primeira mordidaPython: a primeira mordida
Python: a primeira mordida
 
Introdução ao php
Introdução ao phpIntrodução ao php
Introdução ao php
 
Logica Algoritmo 05 Repeticao
Logica Algoritmo 05 RepeticaoLogica Algoritmo 05 Repeticao
Logica Algoritmo 05 Repeticao
 
Aula 6 1 linguagem pascal-parte_1
Aula 6   1 linguagem pascal-parte_1Aula 6   1 linguagem pascal-parte_1
Aula 6 1 linguagem pascal-parte_1
 
TDD em C++
TDD em C++TDD em C++
TDD em C++
 

En vedette

Analiseinstrumental 110427142842-phpapp02
Analiseinstrumental 110427142842-phpapp02Analiseinstrumental 110427142842-phpapp02
Analiseinstrumental 110427142842-phpapp02Flavio Cardoso Reis
 
Sistema operativo miguel sosa
Sistema operativo miguel sosaSistema operativo miguel sosa
Sistema operativo miguel sosaMiguel Sosa
 
Secuestro de barcos en Estados Unidos de América
Secuestro de barcos en Estados Unidos de AméricaSecuestro de barcos en Estados Unidos de América
Secuestro de barcos en Estados Unidos de Américaadelcas13
 
PFI Mantenimiento UF2 Práctica 3
PFI Mantenimiento UF2 Práctica 3PFI Mantenimiento UF2 Práctica 3
PFI Mantenimiento UF2 Práctica 3Sergi Escola
 
A terra conta a sua história ii
A terra conta a sua história iiA terra conta a sua história ii
A terra conta a sua história iiBárbara Pereira
 
Veronica Bluguermann at Festival Rodante Edición Diseño, Buenos Aires
Veronica Bluguermann at Festival Rodante Edición Diseño, Buenos AiresVeronica Bluguermann at Festival Rodante Edición Diseño, Buenos Aires
Veronica Bluguermann at Festival Rodante Edición Diseño, Buenos AiresDESMA
 
Orígenes del teatro
Orígenes del teatroOrígenes del teatro
Orígenes del teatroAnabel López
 
Plano para o Desenvolvimento da Educação de Taquara/RS
Plano para o Desenvolvimento da Educação de Taquara/RSPlano para o Desenvolvimento da Educação de Taquara/RS
Plano para o Desenvolvimento da Educação de Taquara/RSBarbara Benedetti
 
Baço artigo de divulgação científica (final)1
Baço artigo de divulgação científica (final)1Baço artigo de divulgação científica (final)1
Baço artigo de divulgação científica (final)1Maria Laura Gomes
 
презентация против гриппа1
презентация против гриппа1презентация против гриппа1
презентация против гриппа1Roouskkk
 

En vedette (20)

SOPH - EDITAL - CONCURSO.
SOPH - EDITAL - CONCURSO.SOPH - EDITAL - CONCURSO.
SOPH - EDITAL - CONCURSO.
 
Analiseinstrumental 110427142842-phpapp02
Analiseinstrumental 110427142842-phpapp02Analiseinstrumental 110427142842-phpapp02
Analiseinstrumental 110427142842-phpapp02
 
Sistema operativo miguel sosa
Sistema operativo miguel sosaSistema operativo miguel sosa
Sistema operativo miguel sosa
 
Alonso ing. economica
Alonso ing. economicaAlonso ing. economica
Alonso ing. economica
 
proyecto
proyectoproyecto
proyecto
 
Secuestro de barcos en Estados Unidos de América
Secuestro de barcos en Estados Unidos de AméricaSecuestro de barcos en Estados Unidos de América
Secuestro de barcos en Estados Unidos de América
 
Qué comían
Qué comíanQué comían
Qué comían
 
El beisbol
El beisbolEl beisbol
El beisbol
 
PFI Mantenimiento UF2 Práctica 3
PFI Mantenimiento UF2 Práctica 3PFI Mantenimiento UF2 Práctica 3
PFI Mantenimiento UF2 Práctica 3
 
A terra conta a sua história ii
A terra conta a sua história iiA terra conta a sua história ii
A terra conta a sua história ii
 
Veronica Bluguermann at Festival Rodante Edición Diseño, Buenos Aires
Veronica Bluguermann at Festival Rodante Edición Diseño, Buenos AiresVeronica Bluguermann at Festival Rodante Edición Diseño, Buenos Aires
Veronica Bluguermann at Festival Rodante Edición Diseño, Buenos Aires
 
Orígenes del teatro
Orígenes del teatroOrígenes del teatro
Orígenes del teatro
 
Mat64a
Mat64aMat64a
Mat64a
 
Plano para o Desenvolvimento da Educação de Taquara/RS
Plano para o Desenvolvimento da Educação de Taquara/RSPlano para o Desenvolvimento da Educação de Taquara/RS
Plano para o Desenvolvimento da Educação de Taquara/RS
 
M4 43 vb
M4 43 vbM4 43 vb
M4 43 vb
 
Churchill C5 Paris, June 2010
Churchill C5 Paris, June 2010Churchill C5 Paris, June 2010
Churchill C5 Paris, June 2010
 
Informática forense
Informática forenseInformática forense
Informática forense
 
Baço artigo de divulgação científica (final)1
Baço artigo de divulgação científica (final)1Baço artigo de divulgação científica (final)1
Baço artigo de divulgação científica (final)1
 
ուրմիա
ուրմիաուրմիա
ուրմիա
 
презентация против гриппа1
презентация против гриппа1презентация против гриппа1
презентация против гриппа1
 

Similaire à Parâmetros e variáveis no Shell Script

Curso de ShellScript - Lm10 shellscript10
Curso de ShellScript - Lm10 shellscript10Curso de ShellScript - Lm10 shellscript10
Curso de ShellScript - Lm10 shellscript10Pessoal
 
Curso de ShellScript - Lm04 shellscript3
Curso de ShellScript - Lm04 shellscript3Curso de ShellScript - Lm04 shellscript3
Curso de ShellScript - Lm04 shellscript3Pessoal
 
Curso de ShellScript - Lm03 shellscript3
Curso de ShellScript - Lm03 shellscript3Curso de ShellScript - Lm03 shellscript3
Curso de ShellScript - Lm03 shellscript3Pessoal
 
Curso de ShellScript - Lm05 shellscript5
Curso de ShellScript - Lm05 shellscript5Curso de ShellScript - Lm05 shellscript5
Curso de ShellScript - Lm05 shellscript5Pessoal
 
Curso de ShellScript - Lm06 shellscript6
Curso de ShellScript - Lm06 shellscript6Curso de ShellScript - Lm06 shellscript6
Curso de ShellScript - Lm06 shellscript6Pessoal
 
Curso de Shell Script 11/11
Curso de Shell Script 11/11Curso de Shell Script 11/11
Curso de Shell Script 11/11Rodrigo Silva
 
Curso de Shell Script 04/11
Curso de Shell Script 04/11Curso de Shell Script 04/11
Curso de Shell Script 04/11Rodrigo Silva
 
Curso de ShellScript - Lm09 shellscript9
Curso de ShellScript - Lm09 shellscript9Curso de ShellScript - Lm09 shellscript9
Curso de ShellScript - Lm09 shellscript9Pessoal
 
10 Boas Práticas de Programação
10 Boas Práticas de Programação10 Boas Práticas de Programação
10 Boas Práticas de ProgramaçãoCarlos Schults
 
Oficina shell
Oficina shellOficina shell
Oficina shellapsegundo
 
Curso De Shell Aula 3
Curso De Shell   Aula 3Curso De Shell   Aula 3
Curso De Shell Aula 3Felipe Santos
 
Introdução ao Shell Script (versão estendida)
Introdução ao Shell Script (versão estendida)Introdução ao Shell Script (versão estendida)
Introdução ao Shell Script (versão estendida)Hugo Maia Vieira
 
JavaScript for Beginners
JavaScript for BeginnersJavaScript for Beginners
JavaScript for BeginnersSAPO Sessions
 

Similaire à Parâmetros e variáveis no Shell Script (20)

Curso de ShellScript - Lm10 shellscript10
Curso de ShellScript - Lm10 shellscript10Curso de ShellScript - Lm10 shellscript10
Curso de ShellScript - Lm10 shellscript10
 
Curso de ShellScript - Lm04 shellscript3
Curso de ShellScript - Lm04 shellscript3Curso de ShellScript - Lm04 shellscript3
Curso de ShellScript - Lm04 shellscript3
 
Curso de ShellScript - Lm03 shellscript3
Curso de ShellScript - Lm03 shellscript3Curso de ShellScript - Lm03 shellscript3
Curso de ShellScript - Lm03 shellscript3
 
Curso de ShellScript - Lm05 shellscript5
Curso de ShellScript - Lm05 shellscript5Curso de ShellScript - Lm05 shellscript5
Curso de ShellScript - Lm05 shellscript5
 
Curso de ShellScript - Lm06 shellscript6
Curso de ShellScript - Lm06 shellscript6Curso de ShellScript - Lm06 shellscript6
Curso de ShellScript - Lm06 shellscript6
 
Fpar aula5
Fpar aula5Fpar aula5
Fpar aula5
 
Curso de Shell Script 11/11
Curso de Shell Script 11/11Curso de Shell Script 11/11
Curso de Shell Script 11/11
 
Curso de Shell Script 04/11
Curso de Shell Script 04/11Curso de Shell Script 04/11
Curso de Shell Script 04/11
 
Curso de ShellScript - Lm09 shellscript9
Curso de ShellScript - Lm09 shellscript9Curso de ShellScript - Lm09 shellscript9
Curso de ShellScript - Lm09 shellscript9
 
10 Boas Práticas de Programação
10 Boas Práticas de Programação10 Boas Práticas de Programação
10 Boas Práticas de Programação
 
Shell script
Shell script Shell script
Shell script
 
Matlab
Matlab Matlab
Matlab
 
Oficina shell
Oficina shellOficina shell
Oficina shell
 
Comandos e expressões
Comandos e expressõesComandos e expressões
Comandos e expressões
 
Curso De Shell Aula 3
Curso De Shell   Aula 3Curso De Shell   Aula 3
Curso De Shell Aula 3
 
3ª aula php
3ª aula php3ª aula php
3ª aula php
 
Introdução ao Shell Script (versão estendida)
Introdução ao Shell Script (versão estendida)Introdução ao Shell Script (versão estendida)
Introdução ao Shell Script (versão estendida)
 
Shell scripts
Shell scriptsShell scripts
Shell scripts
 
Shell script i
Shell script iShell script i
Shell script i
 
JavaScript for Beginners
JavaScript for BeginnersJavaScript for Beginners
JavaScript for Beginners
 

Parâmetros e variáveis no Shell Script

  • 1. Linux User Papo de Botequim Papo de Botequim Curso de Shell Script Parte X Dave Hamilton - www.sxc.hu Em mais um capítulo de nossa saga através do mundo do Shell Script, vamos aprender a avaliar expressões, capturar sinais e receber parâmetros através da linha de comando. por Júlio Cezar Neves E aê amigo, te dei a maior moleza na a legibilidade do código está “horrorível”, O comando eval última aula né? Um exerciciozinho mas o desempenho, isto é, a velocidade Vou te dar um problema que eu duvido muito simples… de execução, está ótimo. Como funções que você resolva: – É, mas nos testes que eu fi z, e de são coisas muito pessoais, já que cada acordo com o que você ensinou sobre um usa as suas e quase não há neces- $ var1=3 substituição de parâmetros, achei que sidade de manutenção, eu sempre opto $ var2=var1 deveria fazer algumas alterações nas fun- pelo desempenho. ções que desenvolvemos para torná-las de Hoje vamos sair daquela chatura que Te dei essas duas variáveis e quero que uso geral, como você disse que todas as foi o nosso último papo e voltar à lógica, você me diga como eu posso, me referindo funções deveriam ser. Quer ver? saindo da decoreba. Mas volto a te lem- apenas à variável a var2, listar o valor de – Claro, né, mané, se te pedi para fazer brar: tudo que eu te mostrei da última vez var1 (que, no nosso caso, é 3). é porque estou a fi m de te ver aprender, aqui no Boteco do Chico é válido e quebra – Ah, isso é mole, mole! É só digitar mas peraí, dá um tempo. Chico! Manda um galhão. Guarde aqueles guardanapos esse comando aqui: dois, um sem colarinho! Vai, mostra aí que rabiscamos porque, mais cedo ou o que você fez. mais tarde, eles lhe vão ser muito úteis. echo $`echo $var2` – Bem, além do que você pediu, eu reparei que o programa que chamava a Listagem 1: função pergunta.func função teria de ter previamente defi nidas 01 # A função recebe 3 parâmetros na seguinte ordem: a linha em que seria mostrada a mensa- 02 # $1 - Mensagem a ser mostrada na tela gem e a quantidade de colunas. O que 03 # $2 - Valor a ser aceito com resposta padrão fi z foi incluir duas linhas – nas quais 04 # $3 - O outro valor aceito empreguei substituição de parâmetros 05 # Supondo que $1=Aceita?, $2=s e $3=n, a linha – para que, caso uma dessas variáveis não 06 # abaixo colocaria em Msg o valor "Aceita? (S/n)" 07 TotCols=${TotCols:-$(tput cols)} # Se não estava definido, agora está fosse informada, ela recebesse um valor 08 LinhaMesg=${LinhaMesg:-$(($(tput lines)-3))} # Idem atribuído pela própria função. A linha 09 Msg="$1 (`echo $2 | tr a-z A-Z`/`echo $3 | tr A-Z a-z`)" de mensagem é três linhas antes do fi m 10 TamMsg=${#Msg} da tela e o total de colunas é obtido pelo 11 Col=$(((TotCols - TamMsg) / 2)) # Para centralizar Msg na linha comando tput cols. Dê uma olhada na 12 tput cup $LinhaMesg $Col listagem 1 e veja como ficou: 13 read -n1 -p "$Msg " SN – Gostei, você já se antecipou ao que eu 14 SN=${SN:-$2} # Se vazia coloca o padrão em SN ia pedir. Só pra gente encerrar esse papo 15 SN=$(echo $SN | tr A-Z a-z) # A saída de SN será em minúsculas 16 tput cup $LinhaMesg $Col; tput el # Apaga Msg da tela de substituição de parâmetros, repare que 86 julho 2005 edição 10 www.linuxmagazine.com.br
  • 2. Papo de Botequim Linux User Repare que eu coloquei o echo $var2 entre crases (`), porque $ var2=ls dessa forma ele terá prioridade de execução e resultará em var1. $ $var2 E echo $var1 produzirá 3… 10porpag1.sh alo2.sh incusu logado – Ah, é? Então execute para ver se está correto. 10porpag2.sh ArqDoDOS.txt1 listamusica logaute.sh 10porpag3.sh confuso listartista mandamsg.func $ echo $`echo $var2` alo1.sh contpal.sh listartista3 monbg.sh $var1 Agora vamos colocar em var2 o seguinte: ls $var1; e em – Ué! Que foi que aconteceu? O meu raciocínio me parecia var1 vamos colocar l*, vejamos o resultado: bastante lógico… – O seu raciocínio realmente foi lógico, o problema é que você $ var2='ls $var1' esqueceu de uma das primeiras coisas de que te falei aqui no $ var1='l*' Boteco e que vou repetir. O Shell usa a seguinte ordem para $ $var2 resolver uma linha de comando: ls: $var1: No such file or directory P Resolve os redirecionamentos; $ eval $var2 P Substitui as variáveis pelos seus valores; listamusica listartista listartista3 logado logaute.sh P Resolve e substitui os meta caracteres; P Passa a linha já toda esmiuçada para execução. Novamente, no tempo de substituição das variáveis, $var1 Dessa forma, quando o interpretador chegou na fase de re- ainda não havia se apresentado ao Shell para ser resolvida. solução de variáveis, que como eu disse é anterior à execução, Assim, só nos resta executar o comando eval para dar as duas a única variável existente era var2 e por isso a tua solução passadas necessárias. produziu como saída $var1. O comando echo identificou isso Uma vez um colega da excelente lista de discussão groups.yahoo.com/ como uma cadeia de caracteres e não como uma variável. group/shell-script colocou uma dúvida: queria fazer um menu Problemas desse tipo são relativamente freqüentes e seriam que numerasse e listasse todos os arquivos com extensão .sh e, insolúveis caso não existisse a instrução eval, cuja sintaxe é quando o operador escolhesse uma opção, o programa corres- eval cmd, onde cmd é uma linha de comando qualquer, que pondente fosse executado. Veja minha proposta na listagem 2: você poderia inclusive executar direto no prompt do terminal. Quando você põe o eval na frente, no entanto, o que ocorre é Listagem 2: fazmenu.sh que o Shell trata cmd como um parâmetro do eval e, em seguida, 01 #!/bin/bash o eval executa a linha recebida, submetendo-a ao Shell. Ou 02 # seja, na prática cmd é analisado duas vezes. Dessa forma, se 03 # Lista que enumera os programas com extensão .sh no executássemos o comando que você propôs colocando o eval 04 # diretório corrente e executa o escolhido pelo operador 05 # na frente, teríamos a saída esperada. Veja: 06 clear; i=1 07 printf "%11st%snn" Opção Programa $ eval echo $`echo $var2` 08 CASE='case $opt in' 3 09 for arq in *.sh 10 do Esse exemplo também poderia ter sido feito de outra maneira. 11 printf "t%03dt%sn" $i $arq 12 CASE="$CASE Dá só uma olhada: 13 "$(printf "%03d)t %s;;" $i $arq) 14 i=$((i+1)) $ eval echo $$var2 15 done 3 16 CASE="$CASE 17 *) . erro;; Na primeira passada a contrabarra () seria retirada e $var2 18 esac" 19 read -n3 -p "Informe a opção desejada: " opt seria resolvido produzindo var1. Na segunda passada teria so- 20 echo brado echo $var1, que produziria o resultado esperado. Agora 21 eval "$CASE" vou colocar um comando dentro de var2 e executar: julho 2005 edição 10 87 www.linuxmagazine.com.br
  • 3. Linux User Papo de Botequim Parece complicado porque usei muitos dos por) processos em execução. Vamos, "limpar a área" ao seu término. Se seu printf para formatação da tela, mas na de agora em diante, dar uma olhadinha encerramento ocorrer de forma prevista, verdade é bastante simples: o primei- nos sinais enviados aos processos e mais ou seja, se tiver um término normal, é ro printf foi colocado para imprimir à frente vamos dar uma passada rápida muito fácil fazer essa limpeza; porém, o cabeçalho e logo em seguida come- pelos sinais gerados pelos processos. se o seu programa tiver um fim brusco, cei a montar dinamicamente a variável Para mandar um sinal a um processo, muita coisa ruim pode ocorrer: $CASE, na qual ao final será feito um eval usamos normalmente o comando kill, P É possível que em um determinado es- para execução do programa escolhido. cuja sintaxe é: paço de tempo, o seu computador esteja Repare no entanto que dentro do loop cheio de arquivos de trabalho inúteis do for existem dois printf: o primeiro $ kill -sig PID P Seu processador poderá ficar atolado serve para formatar a tela e o segundo de processos zombies e defuncts gera- para montar o case (se antes do coman- Onde PID é o identificador do proces- dos por processos filhos que perderam do read você colocar uma linha echo so (Process Identification ou Process ID). os pais e estão “órfãos”; "$CASE", verá que o comando case mon- Além do comando kill, algumas seqüên- P É necessário liberar sockets abertos para tado dentro da variável está todo inden- cias de teclas também podem gerar sinais. não deixar os clientes congelados; tado. Frescura, né?:). Na saída do for, foi A tabela 1 mostra os sinais mais impor- P Seus bancos de dados poderão ficar adicionada uma linha à variável $CASE tantes para monitorarmos: corrompidos porque sistemas gerencia- para, no caso de uma escolha inválida, Além desses, existe o famigerado si- dores de bancos de dados necessitam ser executada uma função externa para nal -9 ou SIGKILL que, para o processo de um tempo para gravar seus buffers exibir mensagens de erro. Vamos execu- que o está recebendo, equivale a meter em disco (commit). tar o script para ver a saída gerada: o dedo no botão de desligar do compu- Enfim, existem mil razões para não usar tador – o que é altamente indesejável, um kill com o sinal -9 e para monitorar o $ fazmenu.sh já que muitos programas necessitam encerramento anormal de programas. Opcao Programa Listagem 3: Nova versão do fazmenu.sh 001 10porpag1.sh 01 #!/bin/bash 002 10porpag2.sh 02 # 003 10porpag3.sh 03 # Lista enumerando os programas com extensão .sh no 004 alo1.sh 04 # diretório corrente; executa o escolhido pelo operador 005 alo2.sh 05 # 006 contpal.sh 06 clear; i=1 007 fazmenu.sh 07 printf "%11st%snn" Opção Programa 008 logaute.sh 08 CASE='case $opt in' 009 monbg.sh 09 for arq in *.sh 010 readpipe.sh 10 do 011 redirread.sh 11 printf "t%03dt%sn" $i $arq Informe a opção desejada: 12 CASE="$CASE 13 "$(printf "%03d)t %s;;" $i $arq) Seria interessante incluir uma opção 14 i=$((i+1)) para terminar o programa e, para isso, 15 done seria necessária a inclusão de uma linha 16 printf "t%dt%snn" 999 "Fim do programa" # Linha incluída após o loop de montagem da tela e a alte- 17 CASE="$CASE ração da linha na qual fazemos a atribui- 18 999) exit;; # Linha alterada ção final do valor da variável $CASE. Veja 19 *) ./erro;; 20 esac" na listagem 3 como ele ficaria: 21 read -n3 -p "Informe a opção desejada: " opt Existe no Linux uma coisa chamada 22 echo sinal (signal). Existem diversos sinais 23 eval "$CASE" que podem ser mandados para (ou gera- 88 julho 2005 edição 10 www.linuxmagazine.com.br
  • 4. Papo de Botequim Linux User O comando trap Caso a transferência seja interrompida Tabela 1: Principais sinais Para fazer a monitoração de sinais existe por um kill ou um [CTRL]+[C], certa- Código Nome Gerado por: o comando trap, cuja sintaxe pode ser mente deixará lixo no disco. É exatamen- 0 EXIT Fim normal do programa uma das mostradas a seguir: te essa a forma mais comum de uso do 1 SIGHUP Quando o programa comando trap. Como isso é trecho de recebe um kill -HUP trap "cmd1; cmd2; cmdn" S1 S2 … SN um script devemos, logo no início dele, 2 SIGINT Interrupção pelo teclado. trap 'cmd1; cmd2; cmdn' S1 S2 … SN digitar o comando: ([CTRL]+[C]) 3 SIGQUIT Interrupção pelo teclado ([CTRL]+[]) Onde os comandos cmd1, cmd2, cmdn trap "rm -f /tmp/$$ ; exit" 0 1 2 3 15 15 SIGTERM Quando o programa serão executados caso o programa receba recebe um kill ou os sinais S1, S2 … SN. As aspas (") ou Dessa forma, caso houvesse uma inter- kill -TERM as apóstrofes (') só são necessárias caso rupção brusca (sinais 1, 2 , 3 ou 15) antes o trap possua mais de um comando cmd do programa encerrar (no exit dentro do associado. Cada uma delas pode ser tam- comando trap), ou um fim normal (sinal 1º Caso: O comando ftp encontra-se bém uma função interna, uma externa 0), o arquivo /tmp/$$ seria removido. em script1. Nesse caso, o argumento do ou outro script. Caso não houvesse a instrução exit comando trap deveria vir entre aspas (") Para entender o uso de aspas (") e na linha de comando do trap, ao final porque, caso ocorresse uma interrupção apóstrofes (') vamos recorrer a um da execução dessa linha o fluxo do pro- ([CTRL]+[C] ou [CTRL]+[]) no script2, exemplo que trata um fragmento de grama retornaria ao ponto em que estava a linha só seria interpretada nesse mo- um script que faz uma transferência de quando recebeu o sinal que originou a mento e o PID do script2 seria diferente arquivos via FTP para uma máquina execução desse trap. do encontrado em /tmp/$$ (não esqueça remota ($RemoComp), na qual o usuário Note também que o Shell pesquisa a que $$ é a variável que contém o PID do é $Fulano, sua senha é $Segredo e o linha de comando uma vez quando o trap processo ativo); arquivo a ser enviado é $Arq. Suponha é interpretado (e é por isso que é usual 2º Caso: O comando ftp encontra-se ainda que essas quatro variáveis foram colocá-lo no início do programa) e nova- em script2. Nesse caso, o argumento recebidas por uma rotina anterior de mente quando um dos sinais listados é do comando trap deveria estar entre leitura e que esse script seja muito usado recebido. Então, no último exemplo, o va-apóstrofes ('), pois caso a interrupção por diversas pessoas. Vejamos o trecho lor de $$ será substituído no momento em se desse durante a execução de script1, de código a seguir: que o comando trap é lido pela primeira o arquivo não teria sido criado; caso ela vez, já que as aspas (") não protegem o ocorresse durante a execução de script2, ftp -ivn $RemoComp << FimFTP >> /tmp/$$ U cifrão ($) da interpretação do Shell. o valor de $$ seria o PID desse processo, 2>> /tmp/$$ Se você quisesse fazer a substituição que coincidiria com o de /tmp/$$. user $Fulano $Segredo somente ao receber o sinal, o comando O comando trap, quando executado binary deveria ser colocado entre apóstrofes ('). sem argumentos, lista os sinais que estão get $Arq Assim, na primeira interpretação do trap,sendo monitorados no ambiente, bem FimFTP o Shell não veria o cifrão ($), as apóstro- como a linha de comando que será exe- fes (') seriam removidas e, finalmente, o cutada quando tais sinais forem recebidos. Repare que tanto as saídas dos diálo- Se a linha de comandos do trap for nula Shell poderia substituir o valor da variá- gos do FTP como os erros encontrados vel. Nesse caso, a linha ficaria assim: (vazia), isso significa que os sinais espe- estão sendo redirecionados para /tmp/$$, cificados devem ser ignorados quando o que é uma construção bastante comum trap 'rm -f /tmp/$$ ; exit' 0 1 2 3 15 recebidos. Por exemplo, o comando trap para arquivos temporários usados em "" 2 especifica que o sinal de interrup- scripts com mais de um usuário, porque Suponha dois casos: você tem dois ção ([CTRL]+[C]) deve ser ignorado. No $$ é a variável que contém o número do scripts que chamaremos de script1, cuja último exemplo, note que o primeiro ar- processo (PID), que é único. Com esse primeira linha será um trap, e script2, gumento deve ser especificado para que o tipo de construção evita-se que dois ou colocado em execução por script1. Por sinal seja ignorado e não é equivalente a mais usuários disputem a posse e os di- serem dois processos diferentes, terão escrever trap 2, cuja finalidade é retornar reitos sobre um arquivo. dois PIDs distintos. o sinal 2 ao seu estado padrão. ➟ julho 2005 edição 10 89 www.linuxmagazine.com.br
  • 5. Linux User Papo de Botequim Se você ignorar um sinal, todos os sub- Para terminar esse assunto, abra um cadeiadeopcoes deve ser abc. Se você shells irão ignorá-lo. Portanto, se você console gráfico e escreva no prompt de desejar que uma opção seja seguida por especificar qual ação deve ser tomada comando o seguinte: um argumento, ponha um sinal de dois quando receber um sinal, todos os sub- pontos (:) depois da letra, como em a:bc. shells irão tomar a mesma ação quando $ trap "echo Mudou o tamanho da janela" 28 Isso diz ao getopts que a opção -a tem a receberem esse sinal. Ou seja, os sinais forma -a argumento. Normalmente um são automaticamente exportados. Para o Em seguida, pegue o mouse e arraste-o ou mais espaços em branco separam o sinal mostrado (sinal 2), isso significa que de forma a variar o tamanho da janela parâmetro da opção; no entanto, getopts os sub-shells serão encerrados. Suponha corrente. Surpreso? É o Shell orientado também manipula parâmetros que vêm que você execute o comando trap "" 2 e a eventos… Mais unzinho, porque não colados à opção como em -aargumento. então execute um sub-shell, que tornará a consigo resistir. Escreva isto: cadeiadeopcoes não pode conter um si- executar outro script como um sub-shell. nal de interrogação (?). Se for gerado um sinal de interrupção, $ trap "echo já era" 17 O nome constante da linha de sintaxe este não terá efeito nem sobre o Shell acima define uma variável que receberá, principal nem sobre os sub-shell por ele Em seguida digite: a cada vez que o comando getopts for chamados, já que todos eles ignorarão executado, o próximo dos parâmetros o sinal. $ sleep 3 & posicionais e o colocará na variável nome. Em korn shell (ksh) não existe a opção getopts coloca uma interrogação (?) na -s do comando read para ler uma senha. Você acabou de criar um sub-shell que variável definida em nome se achar uma O que costumamos fazer é usar usar o irá dormir durante três segundos em opção não definida em cadeiadeopcoes comando stty com a opção -echo, que background. Ao fim desse tempo, você ou se não achar o argumento esperado inibe a escrita na tela até que se encon- receberá a mensagem “já era”, porque o para uma determinada opção. tre um stty echo para restaurar essa sinal 17 é emitido a cada vez em que um Como já sabemos, cada opção passada escrita. Então, se estivéssemos usando o sub-shell termina a sua execução. Para por uma linha de comandos tem um ín- interpretador ksh, a leitura da senha teria devolver esses sinais ao seu comporta- dice numérico; assim, a primeira opção que ser feita da seguinte forma: mento padrão, digite: trap 17 28. estará contida em $1, a segunda em $2 e Muito legal esse comando, né? Se você assim por diante. Quando o getopts obtém echo -n "Senha: " descobrir algum material bacana sobre uma opção, ele armazena o índice do stty -echo uso de sinais, por favor me informe por próximo parâmetro a ser processado na read Senha email, porque é muito rara a literatura variável OPTIND. stty echo sobre o assunto. Quando uma opção tem um argumento associado (indicado pelo : na cadeiade- O problema com esse tipo de constru- Comando getopts opcoes), getopts armazena o argumento ção é que, caso o operador não soubes- O comando getopts recupera as opções e na variável OPTARG. Se uma opção não se a senha, ele provavelmente teclaria seus argumentos de uma lista de parâ- possuir argumento ou se o argumento [CTRL]+[C] ou um [CTRL]+[] durante metros de acordo com a sintaxe POSIX.2, esperado não for encontrado, a variável a instrução read para descontinuar o pro- isto é, letras (ou números) após um sinal OPTARG será "apagada" (com unset). O co- grama e, caso agisse dessa forma, o seu de menos (-) seguidas ou não de um mando encerra sua execução quando: terminal estaria sem echo. Para evitar que argumento; no caso de somente letras P Encontra um parâmetro que não come- isso aconteça, o melhor a fazer é: (ou números), elas podem ser agrupa- ça com um hífen (-). das. Você deve usar esse comando para P O parâmetro especial -- indica o fim echo -n "Senha: " "fatiar" opções e argumentos passados das opções. trap "stty echo para o seu script. P Quando encontra um erro (por exemplo, exit" 2 3 A sintaxe é getopts cadeiadeopcoes uma opção não reconhecida). stty -echo nome. A cadeiadeopcoes deve explicitar O exemplo da listagem 4 é meramente read Senha uma cadeia de caracteres com todas as didático, servindo para mostrar, em um stty echo opções reconhecidas pelo script; assim, pequeno fragmento de código, o uso ple- trap 2 3 se ele reconhece as opções -a -b e –c, no do comando. 90 julho 2005 edição 10 www.linuxmagazine.com.br
  • 6. Papo de Botequim Linux User Para entender melhor, vamos executar o script: OPTARG eh 'impressora' Dispensando os primeiros $OPTIND-1 = 3 argumentos $ getoptst.sh -h -Pimpressora arq1 arq2 O que sobrou da linha de comandos foi 'arq1 arq2' getopts fez a variavel OPT_LETRA igual a 'h' OPTARG eh '' Repare, no exemplo a seguir, que se passarmos uma opção inválida a getopts fez a variavel OPT_LETRA igual a 'P' variável $OPT_LETRA receberá um ponto de interrogação (?) e a $OPTARG OPTARG eh 'impressora' será "apagada" (unset). Dispensando os primeiros $OPTIND-1 = 2 argumentos O que sobrou da linha de comandos foi 'arq1 arq2' $ getoptst.sh -f -Pimpressora arq1 arq2 # A opção –f não é valida ./getoptst.sh: illegal option -- f Dessa forma, sem ter muito trabalho, separei getopts fez a variavel OPT_LETRA igual a '?' todas as opções com seus respectivos argumentos, OPTARG eh '' deixando somente os parâmetros que foram passa- getopts fez a variavel OPT_LETRA igual a 'P' dos pelo operador para posterior tratamento. Repare OPTARG eh 'impressora' que, se tivéssemos escrito a linha de comando com Dispensando os primeiros $OPTIND-1 = 2 argumentos o argumento (impressora) separado da opção (-P), O que sobrou da linha de comandos foi 'arq1 arq2' o resultado seria exatamente o mesmo, exceto pelo OPTIND, já que nesse caso ele identifica um conjun- – Me diz uma coisa: você não poderia ter usado um condicional com to de três opções (ou argumentos) e, no anterior, case para evitar o getopts? somente dois. Veja só: – Poderia sim, mas para quê? Os comandos estão aí para serem usados… O exemplo foi didático, mas imagine um programa que aceitasse muitas $ getoptst.sh -h -P impressora arq1 arq2 opções e cujos parâmetros poderiam ou não estar colados às opções, sen- getopts fez a variavel OPT_LETRA igual a 'h' do que as opções também poderiam ou não estar coladas: ia ser um case OPTARG eh '' infernal! Com getopts, é só seguir os passos acima. getopts fez a variavel OPT_LETRA igual a 'P' – É… Vendo dessa forma, acho que você tem razão. É porque eu já estou meio cansado com tanta informação nova na minha Listagem 4: getoptst.sh cabeça. Vamos tomar a saideira ou você ainda quer 01 $ cat getoptst.sh explicar alguma particularidade do Shell? 02 #!/bin/sh – Nem um nem outro, eu também já cansei mas 03 hoje não vou tomar a saideira porque estou indo 04 # Execute assim: dar aula na UniRIO, que é a primeira universidade 05 # federal que está preparando seus alunos do curso 06 # getoptst.sh -h -Pimpressora arq1 arq2 de graduação em Informática para o uso de Soft- 07 # ware Livre. Mas antes vou te deixar um problema 08 # e note que as informações de todas as opções são exibidas para te encucar: quando você varia o tamanho de 09 # 10 # A cadeia 'P:h' diz que a opção -P é uma opção complexa uma janela do terminal, no centro dela não aparece 11 # e requer um argumento e que h é uma opção simples que não requer dinamicamente, em vídeo reverso, a quantidade de 12 # argumentos. linhas e colunas? Então! Eu quero que você repro- 13 duza isso usando a linguagem Shell. Chico, traz 14 while getopts 'P:h' OPT_LETRA rapidinho a minha conta! Vou contar até um e se 15 do você não trouxer eu me mando! 16 echo "getopts fez a variavel OPT_LETRA igual a '$OPT_LETRA'" Não se esqueça, qualquer dúvida ou falta de compa- 17 echo " OPTARG eh '$OPTARG'" nhia para um chope é só mandar um email para julio. 18 done 19 used_up=`expr $OPTIND – 1` neves@gmail.com. Vou aproveitar também para mandar 20 echo "Dispensando os primeiros $OPTIND-1 = $used_up argumentos" o meu jabá: diga para os amigos que quem estiver a 21 shift $used_up fim de fazer um curso porreta de programação em 22 echo "O que sobrou da linha de comandos foi '$*'" Shell que mande um e-mail para julio.neves@tecnohall. com.br para informar-se. Valeu! ■ julho 2005 edição 10 91 www.linuxmagazine.com.br