SlideShare uma empresa Scribd logo
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

Mais conteúdo relacionado

PDF
Curso de Shell Script 09/11
PDF
Curso de Shell Script 08/11
PDF
Curso de ShellScript - Lm07 shellscript7
PDF
Curso de Shell Script 03/11
PDF
Curso de Shell Script 06/11
PDF
Oficina de shell script
PDF
Curso de Shell Script 05/11
PDF
Shell Script v0
Curso de Shell Script 09/11
Curso de Shell Script 08/11
Curso de ShellScript - Lm07 shellscript7
Curso de Shell Script 03/11
Curso de Shell Script 06/11
Oficina de shell script
Curso de Shell Script 05/11
Shell Script v0

Mais procurados (19)

PDF
Aula 01 introdução a linguagem pascal
PDF
Javafx Introdução
PDF
Aula 02 operadores aritiméticos
PDF
Conceitos e técnicas de programação aula 5
PDF
Estrutura de Dados - Características da linguagem C - 2
PPTX
Conceitos base de programação - parte 2
ODP
Shell Script - Luz e trevas
PDF
Aula 03 estrutura de seleção
PDF
Introdução à Shellscript
PDF
Algoritmos - capítulo 6
PDF
Tutorial aed iii 008 - algoritmo de ordenação heapsort
PDF
Aula 05 subprogramas
PPTX
Algoritmos - Aula 07 A - Lacos
PDF
Tutorial aed iii 007 - algoritmo de ordenação heapsort
PDF
Python: a primeira mordida
PPTX
Introdução ao php
PPT
Logica Algoritmo 05 Repeticao
PDF
Aula 6 1 linguagem pascal-parte_1
PDF
TDD em C++
Aula 01 introdução a linguagem pascal
Javafx Introdução
Aula 02 operadores aritiméticos
Conceitos e técnicas de programação aula 5
Estrutura de Dados - Características da linguagem C - 2
Conceitos base de programação - parte 2
Shell Script - Luz e trevas
Aula 03 estrutura de seleção
Introdução à Shellscript
Algoritmos - capítulo 6
Tutorial aed iii 008 - algoritmo de ordenação heapsort
Aula 05 subprogramas
Algoritmos - Aula 07 A - Lacos
Tutorial aed iii 007 - algoritmo de ordenação heapsort
Python: a primeira mordida
Introdução ao php
Logica Algoritmo 05 Repeticao
Aula 6 1 linguagem pascal-parte_1
TDD em C++
Anúncio

Destaque (20)

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

Semelhante a Curso de Shell Script 10/11 (20)

PDF
Curso de ShellScript - Lm10 shellscript10
PDF
Curso de ShellScript - Lm04 shellscript3
PDF
Curso de ShellScript - Lm03 shellscript3
PDF
Curso de ShellScript - Lm05 shellscript5
PDF
Curso de ShellScript - Lm06 shellscript6
PDF
Fpar aula5
PDF
Curso de Shell Script 11/11
PDF
Curso de Shell Script 04/11
PDF
Curso de ShellScript - Lm09 shellscript9
PDF
10 Boas Práticas de Programação
PDF
Shell script
PDF
Oficina shell
PDF
Comandos e expressões
PDF
Curso De Shell Aula 3
PPT
3ª aula php
PDF
Introdução ao Shell Script (versão estendida)
PDF
Shell scripts
PPTX
Shell script i
PDF
JavaScript for Beginners
Curso de ShellScript - Lm10 shellscript10
Curso de ShellScript - Lm04 shellscript3
Curso de ShellScript - Lm03 shellscript3
Curso de ShellScript - Lm05 shellscript5
Curso de ShellScript - Lm06 shellscript6
Fpar aula5
Curso de Shell Script 11/11
Curso de Shell Script 04/11
Curso de ShellScript - Lm09 shellscript9
10 Boas Práticas de Programação
Shell script
Oficina shell
Comandos e expressões
Curso De Shell Aula 3
3ª aula php
Introdução ao Shell Script (versão estendida)
Shell scripts
Shell script i
JavaScript for Beginners

Último (19)

PDF
Apple Pippin Uma breve introdução. - David Glotz
PDF
COBITxITIL-Entenda as diferença em uso governança TI
PPTX
Aula 18 - Manipulacao De Arquivos python
PDF
Processos na gestão de transportes, TM100 Col18
PDF
Custos e faturamento no SAP S/4HANA Transportation Management, S4TM3 Col26
PDF
Custos e liquidação no SAP Transportation Management, TM130 Col18
PPTX
BANCO DE DADOS - AULAS INICIAIS-sgbd.pptx
PPTX
Como-se-implementa-um-softwareeeeeeeeeeeeeeeeeeeeeeeee.pptx
PPTX
Programação - Linguagem C - Variáveis, Palavras Reservadas, tipos de dados, c...
PDF
Fundamentos de gerenciamento de ordens e planejamento no SAP TransportationMa...
PPTX
Aula16ManipulaçãoDadosssssssssssssssssssssssssssss
PDF
Mergulho profundo técnico para gestão de transportes no SAP S/4HANA, S4TM6 Col14
PDF
Aula04-Academia Heri- Tecnologia Geral 2025
PPTX
Gestao-de-Bugs-em-Software-Introducao.pptxxxxxxxx
PDF
Otimizador de planejamento e execução no SAP Transportation Management, TM120...
PDF
Fullfilment AI - Forum ecommerce 2025 // Distrito e Total Express
PPTX
Informática Aplicada Informática Aplicada Plano de Ensino - estudo de caso NR...
PDF
20250805_ServiceNow e a Arquitetura Orientada a Serviços (SOA) A Base para Ap...
PDF
Gestão de transportes básica no SAP S/4HANA, S4611 Col20
Apple Pippin Uma breve introdução. - David Glotz
COBITxITIL-Entenda as diferença em uso governança TI
Aula 18 - Manipulacao De Arquivos python
Processos na gestão de transportes, TM100 Col18
Custos e faturamento no SAP S/4HANA Transportation Management, S4TM3 Col26
Custos e liquidação no SAP Transportation Management, TM130 Col18
BANCO DE DADOS - AULAS INICIAIS-sgbd.pptx
Como-se-implementa-um-softwareeeeeeeeeeeeeeeeeeeeeeeee.pptx
Programação - Linguagem C - Variáveis, Palavras Reservadas, tipos de dados, c...
Fundamentos de gerenciamento de ordens e planejamento no SAP TransportationMa...
Aula16ManipulaçãoDadosssssssssssssssssssssssssssss
Mergulho profundo técnico para gestão de transportes no SAP S/4HANA, S4TM6 Col14
Aula04-Academia Heri- Tecnologia Geral 2025
Gestao-de-Bugs-em-Software-Introducao.pptxxxxxxxx
Otimizador de planejamento e execução no SAP Transportation Management, TM120...
Fullfilment AI - Forum ecommerce 2025 // Distrito e Total Express
Informática Aplicada Informática Aplicada Plano de Ensino - estudo de caso NR...
20250805_ServiceNow e a Arquitetura Orientada a Serviços (SOA) A Base para Ap...
Gestão de transportes básica no SAP S/4HANA, S4611 Col20

Curso de Shell Script 10/11

  • 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