Docsity
Docsity

Prepare-se para as provas
Prepare-se para as provas

Estude fácil! Tem muito documento disponível na Docsity


Ganhe pontos para baixar
Ganhe pontos para baixar

Ganhe pontos ajudando outros esrudantes ou compre um plano Premium


Guias e Dicas
Guias e Dicas


Utilizando Funções e Chamadas Externas em Shell Scripts, Notas de estudo de Informática

Neste documento, aprenda a utilizar funções e chamadas externas em scripts shell para simplificar o código, manter o script e reutilizar código. Saiba como declarar, chamar e passar parâmetros para funções, além de como centralizar mensagens na tela. Este artigo é uma tradução de um texto original em inglês.

Tipologia: Notas de estudo

2011

Compartilhado em 10/03/2011

william-felipe-dutra-abreu-da-silva
william-felipe-dutra-abreu-da-silva 🇧🇷

21 documentos

1 / 6

Toggle sidebar

Esta página não é visível na pré-visualização

Não perca as partes importantes!

bg1
Chegou a hora de fazer como Jack e dividir os programas
em pedacinhos. Com funções e chamadas externas
os scripts cam menores, a manutenção mais fácil
e ainda por cima reaproveitamos código.
por Júlio Cezar Neves
E
aê, cara, tudo bem?
Tudo beleza! Eu queria te mostrar o que fi z mas já sei
que você vai querer molhar o bico primeiro, né?
Só pra te cont rariar, hoje não quero. Vai, mostra logo
o que você fez.
Poxa, o exercício que você passou é muito grande. Dá uma
olhada na l ista gem 1 e vê como eu resolvi:
É, o programa tá legal, tá todo estruturadinho, mas gosta-
ria de fazer a lguns poucos comentários: só para relembrar,
as seguintes construções: [ ! $Album ] && e [ $Musica ]
|| representam a mesma coisa, isto é: no caso da primeira,
testamos se a variável $Album não (!) tem nada dentro, então
(&&)… Na segunda, testamos se $Musica tem algum dado,
senão (||)…
Se você reclamou do tamanho do progra ma, é porque ainda
não te dei algumas dicas. Repare que a maior pa rte do script
é para mostrar mensagens cent ral iza-
das na penúltima linha da tela. Repare
ainda que algumas mensagens pedem
um S ou um N como resposta e outras
são só de advertência. Isso é um caso
típico que pede o uso de funções, que
seriam escritas somente uma vez e
executadas em diversos pontos do
script. Vou montar duas funções para
resolver esses c asos e vamos incor-
porá-las ao seu prog rama para ver o
resultado fi nal.
Chico! Agora traz dois chopes, um
sem colarinho, para me dar inspira-
ção. E você, de olho na l ista gem 2.
Como podemos ver, uma função é
defi nida quando digitamos nome_da_
função () e todo o seu corpo está
entre chaves ({}). conversamos aqui
no boteco sobre passagem de parâ-
metros e as funções os recebem da
mesma forma, isto é, são parâmetros
posicionais ($1, $2, …, $n). Todas as regras que se aplicam
à passagem de parâmetros para programas também valem para
funções, mas é muito importante realçar que os pa râmetros
passados para um prog rama não se confundem com aqueles
que são passados para suas funções. Isso signifi ca, por exem-
plo, que o $1 de um script é diferente do $1 de uma de suas
funções internas.
Repare que as variáveis $Msg, $TamMsg e $Col são de uso
restrito dessa rotina e, por isso, foram criadas como variáveis
locais. A razão é simplesmente a economia de memória, já que
ao sair da rotina elas serão devidamente detonadas, coisa que
não aconteceria se eu não tivesse usado esse artifício.
A linha de código que cria a variável local Msg concatena ao
texto recebido ($1) um parêntese, a resposta padrão ($2) em
caixa alta, uma barra, a outra resposta (
$3
) em caixa baixa
e fi naliza fechando o parêntese. Uso essa convenção para, ao
Curso de Shell Script
Papo de Botequim
Parte VIII
Listagem 1: musinc5.sh
01 $ cat musinc5.sh
02 #!/bin/bash
03 # Cadastra CDs (versao 5)
04 #
05 clear
06 LinhaMesg=$((`tput lines` - 3)) # Linha onde serão mostradas as msgs para o operador
07 TotCols=$(tput cols) # Qtd colunas da tela para enquadrar msgs
08 echo “
Inclusão de Músicas
======== == =======
Título do Álbum:
| Este campo foi
Faixa: < criado somente para
| orientar o preenchimento
Nome da Música:
Intérprete:” # Tela montada com um único echo
09 while true
10 do
11 tput cup 5 38; tput el # Posiciona e limpa linha
Dave Hamilt on - www.sxc.hu
Linux User
86
Papo de botequim
www.linu xmagazine.co m.br
maio 2005 edição 08
pf3
pf4
pf5

Pré-visualização parcial do texto

Baixe Utilizando Funções e Chamadas Externas em Shell Scripts e outras Notas de estudo em PDF para Informática, somente na Docsity!

Chegou a hora de fazer como Jack e dividir os programas

em pedacinhos. Com funções e chamadas externas

os scripts ficam menores, a manutenção mais fácil

e ainda por cima reaproveitamos código.

por Júlio Cezar Neves

E

aê, cara, tudo bem?

  • Tudo beleza! Eu queria te mostrar o que fi z mas já sei

que você vai querer molhar o bico primeiro, né?

  • Só pra te contrariar, hoje não quero. Vai, mostra logo aí

o que você fez.

  • Poxa, o exercício que você passou é muito grande. Dá uma

olhada na listagem 1 e vê como eu resolvi:

  • É, o programa tá legal, tá todo estruturadinho, mas gosta-

ria de fazer alguns poucos comentários: só para relembrar,

as seguintes construções: [! $Album ] && e [ $Musica ]

|| representam a mesma coisa, isto é: no caso da primeira,

testamos se a variável $Album não (!) tem nada dentro, então

(&&)… Na segunda, testamos se $Musica tem algum dado,

senão (||)…

Se você reclamou do tamanho do programa, é porque ainda

não te dei algumas dicas. Repare que a maior parte do script

é para mostrar mensagens centraliza-

das na penúltima linha da tela. Repare

ainda que algumas mensagens pedem

um S ou um N como resposta e outras

são só de advertência. Isso é um caso

típico que pede o uso de funções, que

seriam escritas somente uma vez e

executadas em diversos pontos do

script. Vou montar duas funções para

resolver esses casos e vamos incor-

porá-las ao seu programa para ver o

resultado fi nal.

  • Chico! Agora traz dois chopes, um

sem colarinho, para me dar inspira-

ção. E você, de olho na listagem 2.

Como podemos ver, uma função é

defi nida quando digitamos nome_da_

função () e todo o seu corpo está

entre chaves ({}). Já conversamos aqui

no boteco sobre passagem de parâ-

metros e as funções os recebem da

mesma forma, isto é, são parâmetros

posicionais ($1, $2, …, $n). Todas as regras que se aplicam

à passagem de parâmetros para programas também valem para

funções, mas é muito importante realçar que os parâmetros

passados para um programa não se confundem com aqueles

que são passados para suas funções. Isso significa, por exem-

plo, que o $1 de um script é diferente do $1 de uma de suas

funções internas.

Repare que as variáveis $Msg, $TamMsg e $Col são de uso

restrito dessa rotina e, por isso, foram criadas como variáveis

locais. A razão é simplesmente a economia de memória, já que

ao sair da rotina elas serão devidamente detonadas, coisa que

não aconteceria se eu não tivesse usado esse artifício.

A linha de código que cria a variável local Msg concatena ao

texto recebido ($1) um parêntese, a resposta padrão ($2) em

caixa alta, uma barra, a outra resposta ($3) em caixa baixa

e fi naliza fechando o parêntese. Uso essa convenção para, ao

Curso de Shell Script

Papo de Botequim

Parte VIII

Listagem 1: musinc5.sh 01 $ cat musinc5.sh 02 #!/bin/bash 03 # Cadastra CDs (versao 5) 04 # 05 clear 06 LinhaMesg=$((tput lines - 3)) # Linha onde serão mostradas as msgs para o operador 07 TotCols=$(tput cols) # Qtd colunas da tela para enquadrar msgs 08 echo “ Inclusão de Músicas ======== == ======= Título do Álbum: | Este campo foi Faixa: < criado somente para | orientar o preenchimento Nome da Música: Intérprete:” # Tela montada com um único echo 09 while true 10 do

11 tput cup 5 38; tput el # Posiciona e limpa linha ➟

Dave Hamilton - www.sxc.hu Linux User 86

Papo de botequim

maio 2005 edição 08

mesmo tempo, mostrar as opções dis-

poníveis e realçar a resposta oferecida

como padrão.

Quase no fim da rotina, a resposta

recebida ($SN) é convertida para caixa

baixa (minúsculas) de forma que no

corpo do programa não precisemos

fazer esse teste. Veja na listagem 3

como ficaria a função para exibir uma

mensagem na tela.

Essa é uma outra forma de definir

uma função: não a chamamos, como

no exemplo anterior, usando uma

construção com a sintaxe nome_da_

função (), mas sim como function

nome_da_função. Em nada mais ela

difere da anterior, exceto que, como

consta dos comentários, usamos a

variável $* que, como já sabemos,

representa o conjunto de todos os

parâmetros passados ao script, para

que o programador não precise usar

aspas envolvendo a mensagem que

deseja passar à função.

Para terminar com esse blá-blá-blá,

vamos ver na listagem 4 as alterações

no programa quando usamos o con-

ceito de funções:

Repare que a estrutura do script

segue a ordem Variáveis Globais , Fun-

ções e Corpo do Programa. Esta estrutu-

ração se deve ao fato de Shell Script ser

uma linguagem interpretada, em que

o programa é lido da esquerda para

a direita e de cima para baixo. Para

ser vista pelo script e suas funções,

uma variável deve ser declarada (ou

inicializada, como preferem alguns)

antes de qualquer outra coisa. Por sua

vez, as funções devem ser declaradas

antes do corpo do programa propria-

mente dito. A explicação é simples: o

interpretador de comandos do shell

deve saber do que se trata a função

antes que ela seja chamada no pro-

grama principal.

Uma coisa bacana na criação de fun-

ções é fazê-las tão genéricas quanto

possível, de forma que possam ser

reutilizadas em outros scripts e apli-

cativos sem a necessidade de reinven-

tarmos a roda. As duas funções que

acabamos de ver são bons exemplos,

pois é difícil um script de entrada de

dados que não use uma rotina como

a MandaMsg ou que não interaja com

o operador por meio de algo seme-

lhante à Pergunta.

12 read Album 13 [! “$Album” ] && # Operador deu 14 { 15 Msg=”Deseja Terminar? (S/n)” 16 TamMsg=${#Msg} 17 Col=$(((TotCols - TamMsg) / 2)) # Centraliza msg na linha 18 tput cup $LinhaMesg $Col 19 echo “$Msg” 20 tput cup $LinhaMesg $((Col + TamMsg + 1)) 21 read -n1 SN 22 tput cup $LinhaMesg $Col; tput el # Apaga msg da tela 23 [ $SN = “N” -o $SN = “n” ] && continue # $SN é igual a N ou (-o) n? 24 clear; exit # Fim da execução 25 } 26 grep “^$Album^” musicas > /dev/null && 27 { 28 Msg=”Este álbum já está cadastrado” 29 TamMsg=${#Msg} 30 Col=$(((TotCols - TamMsg) / 2)) # Centraliza msg na linha 31 tput cup $LinhaMesg $Col 32 echo “$Msg” 33 read -n 34 tput cup $LinhaMesg $Col; tput el # Apaga msg da tela 35 continue # Volta para ler outro álbum 36 } 37 Reg=”$Album^” # $Reg receberá os dados para gravação 38 oArtista= # Variável que guarda artista anterior 39 while true 40 do 41 ((Faixa++)) 42 tput cup 7 38 43 echo $Faixa 44 tput cup 9 38 # Posiciona para ler música 45 read Musica 46 [ “$Musica” ] || # Se o operador tiver dado ... 47 { 48 Msg=”Fim de Álbum? (S/n)” 49 TamMsg=${#Msg} 50 Col=$(((TotCols - TamMsg) / 2)) # Centraliza msg na linha 51 tput cup $LinhaMesg $Col 52 echo “$Msg” 53 tput cup $LinhaMesg $((Col + TamMsg + 1) 54 read -n1 SN 55 tput cup $LinhaMesg $Col; tput el # Apaga msg da tela 56 [ “$SN” = N -o “$SN” = n ] && continue # $SN é igual a N ou (-o) n? 57 break # Sai do loop para gravar 58 } 59 tput cup 11 38 # Posiciona para ler Artista 60 [ “$oArtista” ] && echo -n “($oArtista) “ # Artista anterior é default 61 read Artista 62 [ “$Artista” ] && oArtista=”$Artista” 63 Reg=”$Reg$oArtista~$Musica:” # Montando registro 64 tput cup 9 38; tput el # Apaga Música da tela 65 tput cup 11 38; tput el # Apaga Artista da tela 66 done 67 echo “$Reg” >> musicas # Grava registro no fim do arquivo 38 sort musicas -0 musicas # Classifica o arquivo 69 done papo de botequim (^) Linux User maio 2005 edição 08 87

Listagem 4: musinc6.sh 01 $ cat musinc 02 #!/bin/bash 03 # Cadastra CDs (versao 6) 04 # 05 # Área de variáveis globais 06 # Linha onde as mensagens serão exibidas 07 LinhaMesg=$((tput lines - 3)) 08 # Quantidade de colunas na tela (para enquadrar as mensagens) 09 TotCols=$(tput cols) 10 # Área de funções 11 Pergunta () 12 { 13 # A função recebe 3 parâmetros na seguinte ordem: 14 # $1 - Mensagem a ser dada na tela 15 # $2 - Valor a ser aceito com resposta default 16 # $3 - O outro valor aceito 17 # Supondo que $1=Aceita?, $2=s e $3=n, a linha 18 # abaixo colocaria em Msg o valor “Aceita? (S/n)” 19 local Msg=”$1 (echo $2 | tr a-z A-Z/echo $3 | tr A-Z a-z)” 20 local TamMsg=${#Msg} 21 # Centraliza a mensagem na linha 22 local Col=$(((TotCols - TamMsg) / 2)) 23 tput cup $LinhaMesg $Col 24 echo “$Msg” 25 tput cup $LinhaMesg $((Col + TamMsg + 1)) 26 read -n1 SN 27 [! $SN ] && SN=$2 # Se vazia, coloca default em SN 28 echo $SN | tr A-Z a-z # A saída de SN será em minúsculas 29 tput cup $LinhaMesg $Col; tput el # Apaga msg da tela 30 return # Sai da função 31 } 32 function MandaMsg 33 { 34 # A função recebe somente um parâmetro 35 # com a mensagem que se deseja exibir; 36 # para não obrigar o programador a passar 37 # a msg entre aspas, usaremos $* (todos 38 # os parâmetro, lembra?) e não $1. 39 local Msg=”$*” 40 local TamMsg=${#Msg} 41 # Centraliza mensagem na linha 42 local Col=$(((TotCols - TamMsg) / 2)) 43 tput cup $LinhaMesg $Col 44 echo “$Msg” 45 read -n 46 tput cup $LinhaMesg $Col; tput el # Apaga msg da tela 47 return # Sai da função 48 } 49 # O corpo do programa propriamente dito começa aqui 50 clear 51 # A tela a seguir é montada com um único comando echo 52 echo “ Inclusão de Músicas ======== == ======= Título do Álbum: Faixa: Nome da Música: Intérprete:” 53 while true 54 do 55 tput cup 5 38; tput el # Posiciona e limpa linha 56 read Album 57 [! “$Album” ] && # Operador deu 58 { 59 Pergunta “Deseja Terminar” s n 60 # Agora só testo caixa baixa 61 [ $SN = “n” ] && continue 62 clear; exit # Fim da execução 63 } 64 grep -iq “^$Album^” musicas 2> /dev/null && 65 { 66 MandaMsg Este álbum já está cadastrado 67 continue # Volta para ler outro álbum 68 } 69 Reg=”$Album^” # $Reg receberá os dados de gravação 70 oArtista= # Guardará artista anterior 71 while true 72 do 73 ((Faixa++)) 74 tput cup 7 38 75 echo $Faixa 76 tput cup 9 38 # Posiciona para ler música 77 read Musica 78 [ “$Musica” ] || # Se o operador teclou ... 79 { 80 Pergunta “Fim de Álbum?” s n 81 # Agora só testo a caixa baixa 82 [ “$SN” = n ] && continue 83 break # Sai do loop para gravar dados 84 } 85 tput cup 11 38 # Posiciona para ler Artista 86 # O artista anterior é o padrão 87 [ “$oArtista” ] && echo -n “($oArtista) “ 88 read Artista 89 [ “$Artista” ] && oArtista=”$Artista” 90 Reg=”$Reg$oArtista~$Musica:” # Montando registro 91 tput cup 9 38; tput el # Apaga Música da tela 92 tput cup 11 38; tput el # Apaga Artista da tela 93 done 94 # Grava registro no fim do arquivo 95 echo “$Reg” >> musicas 96 # Classifica o arquivo 97 sort musicas -o musicas 98 done papo de botequim (^) Linux User maio 2005 edição 08 89

Ahh! Agora sim! Quando passado

como parâmetro do comando source ,

o script foi executado no shell cor-

rente, deixando nele todo o ambiente

criado. Agora vamos rebobinar a fita

até o início da explicação sobre este

comando. Lá falamos do .bash_pro-

file e, a esta altura, você já deve saber

que sua incumbência é, logo após o

login, preparar o ambiente de trabalho

para o usuário. Agora entendemos que

é por isso mesmo que ele é executado

usando esse artifício.

E agora você deve estar se per-

guntando se é só para isso que esse

comando serve. Eu lhe digo que sim,

mas isso nos traz um monte de vanta-

gens – e uma das mais usadas é tratar

funções como rotinas externas. Veja

na listagem 5 uma outra forma de fazer

o nosso programa para incluir CDs no

arquivo musicas.

Agora o programa deu uma boa enco-

lhida e as chamadas de função foram

trocadas por arquivos externos chama-

dos pergunta.func e mandamsg.func,

que assim podem ser chamados por

qualquer outro programa, dessa forma

reutilizando o seu código.

Por motivos meramente didáticos, as

chamadas a pergunta.func e manda-

msg.func estão sendo feitas por source

e por. (ponto) indiscriminadamente,

embora eu prefira o source que, por

ser mais visível, melhora a legibili-

dade do código e facilita sua posterior

manutenção. Veja na listagem 6 como

ficaram esses dois arquivos.

Em ambos os arquivos, fiz somente

duas mudanças, que veremos nas

observações a seguir. Porém, tenho

mais três observações a fazer:

1. As variáveis não estão sendo mais

declaradas como locais, porque essa

é uma diretiva que só pode ser usada

no corpo de funções e, portanto, essas

variáveis permanecem no ambiente do

shell, poluindo-o;

2. O comando return não está mais

presente, mas poderia estar sem alte-

rar em nada a lógica do script, uma

vez que só serviria para indicar um

eventual erro por meio de um código

de retorno previamente estabelecido

(por exemplo return 1, return 2, …),

sendo que o return e return 0 são

idênticos e significam que a rotina foi

executada sem erros;

Listagem 5: musinc7.sh 01 $ cat musinc7.sh 02 #!/bin/bash 03 # Cadastra CDs (versao 7) 04 # 05 # Área de variáveis globais 06 LinhaMesg=$((tput lines - 3)) # Linha onde serão mostradas as msgs para o operador 07 TotCols=$(tput cols) # Qtd colunas da tela para enquadrar msgs 08 # O corpo do programa propriamente dito começa aqui 09 clear 10 echo “ Inclusão de Músicas ======== == ======= Título do Álbum: | Este campo foi Faixa: < criado somente para | orientar o preenchimento Nome da Música: Intérprete:” # Tela montada com um único echo 11 while true 12 do 13 tput cup 5 38; tput el # Posiciona e limpa linha 14 read Album 15 [! “$Album” ] && # Operador deu 16 { 17 source pergunta.func “Deseja Terminar” s n 18 [ $SN = “n” ] && continue # Agora só testo a caixa baixa 19 clear; exit # Fim da execução 20 } 21 grep -iq “^$Album^” musicas 2> /dev/null && 22 {

  1. mandamsg.func Este álbum já está cadastrado 24 continue # Volta para ler outro álbum 25 } 26 Reg=”$Album^” # $Reg receberá os dados de gravação 27 oArtista= # Guardará artista anterior 28 while true 29 do 30 ((Faixa++)) 31 tput cup 7 38 32 echo $Faixa 33 tput cup 9 38 # Posiciona para ler música 34 read Musica 35 [ “$Musica” ] || # Se o operador tiver dado ... 36 {
  2. pergunta.func “Fim de Álbum?” s n 38 [ “$SN” = n ] && continue # Agora só testo a caixa baixa 39 break # Sai do loop para gravar dados 40 } 41 tput cup 11 38 # Posiciona para ler Artista 42 [ “$oArtista” ] && echo -n “($oArtista) “ # Artista anterior é default 43 read Artista 44 [ “$Artista” ] && oArtista=”$Artista” 45 Reg=”$Reg$oArtista~$Musica:” # Montando registro 46 tput cup 9 38; tput el # Apaga Música da tela 47 tput cup 11 38; tput el # Apaga Artista da tela 48 done 49 echo “$Reg” >> musicas # Grava registro no fim do arquivo 50 sort musicas -o musicas # Classifica o arquivo 51 done Linux User 90

Papo de botequim

maio 2005 edição 08