Shell - Funções

O artigo tem por objetivo, introduzir o tão importante e poderoso conceito de funções. Ele mostra: como declarar (no padrão de escrita das funções), funções aninhadas, arquivos de funções, undeclaring (desdeclarando ?), passando argumentos, recebendo dados de retorno, recursão, etc.

[ Hits: 37.361 ]

Por: jarlisson moreira em 27/07/2012


Introduzindo e declarando funções



Quem já estudou outra linguagem de programação, sabe o que são funções ou, como são muitas vezes chamadas, sub-rotinas.

Resumidamente, são um bloco de comandos que, geralmente, recebem dados, fazem a manipulação destes através das instruções e devolvem algum resultado. Às vezes não retornam nada, mas fazem algum tipo de mudança no seu script, nem que seja uma simples exibição de texto.

Quem escreve muitos códigos em shell scripting, sabe que repetimos muitos comandos e instruções. Escrevendo, definindo e salvando as funções de maneira que estas sejam bem simples e executem uma tarefa bem específica, é uma boa prática para evitar a repetição na escrita de código, pois podemos sempre reutilizar estas funções.

Assim, quando for iniciar um projeto, já terá boa parte deste feito, em forma de funções.

Declarando funções

Em Shell, as funções tem a "cara":

funcao ()
{
     #bloco de instruções. Tudo entre {} é executado de uma vez
}


Diferente de algumas linguagens de programação, por padrão, as variáveis internas a uma função são visíveis fora desta:

{ texto="Oi, sou uma função anônima" ; }
echo $texto


Note que, após cada comando dentro do escopo das funções, usamos ';':

listar () { texto="listando items" ; echo $texto ; ls ; }


Para declarar a função, digite no terminal:

declare -f listar

Caso deseje expandir os comandos, o bash irá interpretar a quebra de linha, não sendo necessário o ';' :

listar()
{
   texto="listando items"
   echo $texto
   ls
}


* Importante: Após a primeira chaves, "{", dê espaço!
  • listar() {ls;} -> ERRADO
  • listar() { ls;}-> CERTO

Após criar e declarar a função, para chamá-la, simplesmente digite o nome dela, como se fosse um comando, no terminal:

listar

Note que isso só funcionará na instância do shell em que você declarou a função.

Como na maioria das linguagens, você precisa declarar a função antes de usá-la (em Perl, não. Por exemplo, você pode declarar até num pedaço de papel, que o Perl reconhece).

Vamos testar no script 'hello':

#!/bin/bash

hello()
{
   echo "Hello, World"
}

goodbye()
{
   echo "Goodbye, World"
}

hello
goodbye


Execute e sinta a magia no ar:

chmod +x hello
$ ./hello


Leia o artigo Processos, insira 'exit 0', ao final da função 'hello()'.

Veja e analise o resultado.

    Próxima página

Páginas do artigo
   1. Introduzindo e declarando funções
   2. Funções - Argumentos - Retorno
   3. Para entender recursão, tem que entender recursão
Outros artigos deste autor

LibreOffice Math

Sed - Introdução

Processos

AWK - Introdução

Pipelines (Canalizadores)

Leitura recomendada

Cobrando com o SQUID

Programação com Shell Script

Sed - Introdução

Introduzindo um pouco mais a fundo o shell script

Colorindo o Shell

  
Comentários
[1] Comentário enviado por removido em 27/07/2012 - 13:16h

Um detalhe:

Quando um programa qualquer retorna um valor para o sistema, o valor retorna em módulo 256.

Por exemplo:

Para "return 1000", o valor do $? aparecerá como 232, porque 1000 dividido por 256 sobram 232.

Isso acontece com outras linguagens. Considera-se apenas o valor de um byte sem sinal.

[2] Comentário enviado por removido em 27/07/2012 - 17:07h

Boa colaboração Jarlisson!

Mas tenho que fazer uma observação e peço que me corrija se estiver errado.

Você falou: Como vimos, todo e qualquer comando do Unix retorna algum código. blz ! mas nem sempre os códigos de retorno que vimos na tela vendo o conteúdo da variável $? são retornados por comandos e muitos desses códigos retornados são feitos pelo shell.

POR EXEMPLO: o código: 126 indica que o comando não tem permissão de execução. outro exemplo é quando executa um comando que não existe, quem retorna o erro é o próprio shell. pois o mesmo não encontrou aquela função embutida no shell usado e não encontrou no sistema de arquivos que contém o S.O.

abraço amigo.

[3] Comentário enviado por rai3mb em 27/07/2012 - 17:56h


[1] Comentário enviado por Listeiro 037 em 27/07/2012 - 13:16h:

Um detalhe:

Quando um programa qualquer retorna um valor para o sistema, o valor retorna em módulo 256.

Por exemplo:

Para "return 1000", o valor do $? aparecerá como 232, porque 1000 dividido por 256 sobram 232.

Isso acontece com outras linguagens. Considera-se apenas o valor de um byte sem sinal.


Legal, entendi porque algumas aplicações usam seu código de retorno até o 255, pois quando for superior o retorno poderá confundir, já que será o módulo de 256 ;-)

[4] Comentário enviado por removido em 27/07/2012 - 18:09h


[2] Comentário enviado por eabreu em 27/07/2012 - 17:07h:

Boa colaboração Jarlisson!

Mas tenho que fazer uma observação e peço que me corrija se estiver errado.

Você falou: Como vimos, todo e qualquer comando do Unix retorna algum código. blz ! mas nem sempre os códigos de retorno que vimos na tela vendo o conteúdo da variável $? são retornados por comandos e muitos desses códigos retornados são feitos pelo shell.

POR EXEMPLO: o código: 126 indica que o comando não tem permissão de execução. outro exemplo é quando executa um comando que não existe, quem retorna o erro é o próprio shell. pois o mesmo não encontrou aquela função embutida no shell usado e não encontrou no sistema de arquivos que contém o S.O.

abraço amigo.


Isto, a rigor realmente acontece. Mas há, como em tudo em Unix, a flexibilidade de enviar um número qualquer como retorno.

É só tomar cuidado com certos números e fazer a verificação caso a caso de qual situação aplica-se o que foi retornado.

Nisto, 0 é usado sempre quando tudo correu bem e 255 (255 == -1 módulo 256) costuma identificar sempre algum erro.

*** ADD ***

No caso do 126, se for resultante este código antes de algum "return", é analisada qual a situação e depois enviado um "return com um número dos seus".


[5] Comentário enviado por removido em 27/07/2012 - 18:12h


[3] Comentário enviado por rai3mb em 27/07/2012 - 17:56h:


[1] Comentário enviado por Listeiro 037 em 27/07/2012 - 13:16h:

Um detalhe:

Quando um programa qualquer retorna um valor para o sistema, o valor retorna em módulo 256.

Por exemplo:

Para "return 1000", o valor do $? aparecerá como 232, porque 1000 dividido por 256 sobram 232.

Isso acontece com outras linguagens. Considera-se apenas o valor de um byte sem sinal.

Legal, entendi porque algumas aplicações usam seu código de retorno até o 255, pois quando for superior o retorno poderá confundir, já que será o módulo de 256 ;-)


Isso ocorria/ocorre no DOS também. Lá chamavam de ERRORLEVEL.

[6] Comentário enviado por jarlisson em 27/07/2012 - 20:32h

Esses códigos altos de retorno são mais raros...por exemplo:
128 + x: fatal error signal “x” (137, pro caso do x=9, que é o do kill -9)
130 - ctrol+c
Mas acho que o erro mais raro que ouvi falar foi o:
2: misuse of shell built-in

Como o eabreu falou, algumas coisas são do próprio shell. Aí vale uma ressalva...sempre que eu ia me informar melhor sobre algumas coisas eu via que em determinado Shell podia, em outro não...outras coisas que podiam, mas não eram muito usadas.

Na verdade achei centenas de detalhes, principalmente pelo número diferente de shells: C shell, korn shell, t c shell, z shell, ash...embora alguns já estejam mortos, muitos comandos o Bash herdou totalmente, outros comandos foram herdados em certas condições e outros não foram herdados, mas ainda há gente usando todo o tipo de shell, produzindo material, livros etc.

Esses códigos de retorno são mais usados pra checar se ocorreu tudo bem ou não. Mas eu vi muita discussão a respeito desse intervalo 0-255, pois alguns alguns comandos/programas não se deram satisfeito com isso.
A saída que vi foi, caso o erro fosse maior, eles iam 'tratando'... 'agrupando' em um número...por isso é possível ter vários problemas com o mesmo código de retorno.

Quando a coisa era mais elaborada, eles passavam argumentos pra outras funções que explicavam melhor o erro, antes de agrupar esses erros e retornar o código:

descricao ()
{
if [ $1 -ge 2 ]; then echo "erro tal"
elif [ $1 -eq 1 ]; then echo "voce esqueceu isso"
elif [ $1 -eq 0 ]; then echo "ocorreu tudo bem"
fi
}
echo "ocorreu o problema $(descricao $numero)"


Mas enfim, vi muita flexibilidade...sempre achava que algo nao podia, vi que podia, mas de uma outra forma ou em outro shell ou através de mudanças no bash. Eu não me aprofundei muito nos detalhes, pois eram muitos e muita coisa específica, e o objetivo do artigo era ser bem introdutório mesmo.

Mas qualquer limitação que voces acharem que possam ter no shell, deem uma pesquisada, ṕois sempre vai dar pra contornar.

[7] Comentário enviado por rhuicamelo em 28/07/2012 - 11:36h

artigo de shell é mais pra referência...até a documentação é bizarra
shell é bizarro

sempre que pensar nao da pra fazer algo no shell, pesquise que vera que da pa fazer. as vezes pode mas é em outro shel ou com plugin ou baixando mais comandos

daqui a pouco shel vai ser orientado a objetos

[8] Comentário enviado por di4s em 30/07/2012 - 00:38h

Otimo artigo.

uma duvida que tenho é como retornar algo que a função fez ( entenda usar o return como nas outras linguagens ), algo do tipo:

variavel = funcao(); #função está retornando um valor que está sendo armazenado em variavel

atualmente faço assim:

#!/bin/bash

function quadrado() {

echo $(($1*$1));
}

resultado=$(quadrado 5);



alguém sabe de outra forma?






[9] Comentário enviado por removido em 30/07/2012 - 02:45h


[8] Comentário enviado por prmjunior em 30/07/2012 - 00:38h:

Otimo artigo.

uma duvida que tenho é como retornar algo que a função fez ( entenda usar o return como nas outras linguagens ), algo do tipo:

variavel = funcao(); #função está retornando um valor que está sendo armazenado em variavel

atualmente faço assim:

#!/bin/bash

function quadrado() {

echo $(($1*$1));
}

resultado=$(quadrado 5);



alguém sabe de outra forma?







Vou adiantar um pedaço de um texto :-P :-P :-P :-P

[code]#!/bin/bash

export variavel


func1(){

let a=2+2;

variavel=$a;

return;

}

variavel=2;

echo "Antes: $variavel"

func1;

echo "Depois: $variavel"[/code]


Faça o teste para ver se isto serve.

Dependendo do que você disser eu postarei o resto mais rápido :-P :-P :-P :-P

*** ADD ***

O <CODE> não funcionou...

[10] Comentário enviado por jarlisson em 30/07/2012 - 06:07h

Como as variaveis internas sao globais, eu criaria uma la dentro que ficaria mudando conforme o argumento:

-----------------
#!/bin/bash

dobra(){
res=`expr 2 \* $1`
return
}

dobra 2
dobro2=$res
echo "o dobro de 2 é $dobro2"

dobra 3
dobro3=$res
echo "o dobro de 3 é $dobro3
------------------

Ou seja, variavel 'res' seria meu return.
Mas deve haver outros métodos...

[11] Comentário enviado por jarlisson em 30/07/2012 - 06:39h

Deixar essa URL aqui como referência, achei muito boa:
http://www.linuxtopia.org/online_books/advanced_bash_scripting_guide/complexfunct.html

[12] Comentário enviado por removido em 05/08/2012 - 22:31h


[9] Comentário enviado por Listeiro 037 em 30/07/2012 - 02:45h:


[8] Comentário enviado por prmjunior em 30/07/2012 - 00:38h:

Otimo artigo.

uma duvida que tenho é como retornar algo que a função fez ( entenda usar o return como nas outras linguagens ), algo do tipo:

variavel = funcao(); #função está retornando um valor que está sendo armazenado em variavel

atualmente faço assim:

#!/bin/bash

function quadrado() {

echo $(($1*$1));
}

resultado=$(quadrado 5);



alguém sabe de outra forma?







Vou adiantar um pedaço de um texto :-P :-P :-P :-P

[code]#!/bin/bash

export variavel


func1(){

let a=2+2;

variavel=$a;

return;

}

variavel=2;

echo "Antes: $variavel"

func1;

echo "Depois: $variavel"[/code]

Faça o teste para ver se isto serve.

Dependendo do que você disser eu postarei o resto mais rápido :-P :-P :-P :-P

*** ADD ***

O <CODE> não funcionou...




Então, respondendo conforme tinha me perguntado.

Comecei a escrever meia-dúzia de coisas sobre shell e parei por não saber em que tipo de temática elas se enquadrariam.

Modos:

1. variável global: foi isso aí de cima que mostrei e que "lembra" alguma coisa que fica "registrada" (tipo 'registrador' mesmo) para acesso imediato.

2. uso de arquivo temporário. essa não fui eu quem inventou e é bem conhecida. usa-se 'echo > variavel.$$', algo assim, por exemplo. o resto depende do que for para o arquivo.

3. um array global em que cada posição funciona como uma memória individual e usa-se o valor do return para o índice. a vantagem é que os valores retornados ficam armazenados ordenadamente e para uso posterior.

4. o modo clássico do `echo`, que é o mais usado.


Ainda não sei se há um modo de fazer isso com shift, que é para entrada de parâmetros e não saída.

O uso de shell script costuma ser para tarefas mais simples. Não é o tipo de coisa que usam para construir bancos de dados de texto.

É melhor não ficar filosofando sobre como pode ser usado. Não é adequado. Exceto neste minuto.


Teve um cara que escreveu um assembler em shell, mas não tenho a menor ideia de como fez. Não é difícil de encontrar no GOOGLE.

[13] Comentário enviado por Novaesma em 04/09/2020 - 11:39h

Então ficaria assim, assim a função e posso ta chamando essa função em outra parte do script??

CHPG ()
{
echo $ scp /home/saai/Catalogo/CHPG/* ---@ip:/home/---/Catalogo/CHPG/
}


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts