Dúvida funções em script

Iniciado por Cristiano_UP, 16 de Junho de 2017, 16:40

tópico anterior - próximo tópico

Cristiano_UP

Boa tarde,

Tenho um script com nome upd.sh, que possui menu principal e 8 funções. Está funcionando tudo, ok. Mas está em um único arquivo.

Para detalhar melhor:

- menu principal e função01, função02 ... função08 (mesmo arquivo).

Pergunta: Se criar cada função um arquivo separado, qual o comando que utilizo para chamar está função?

Logo ficaria assim:
   menu principal.sh e função01.sh ...... função08.sh!!!!

Como fazer para chamar uma função em um arquivo separado?

Principal motivo seria se criar outro script poder reutilizar a mesma função arquivos diferentes.

druidaobelix

#1
Citação de: Cristiano_UP online 16 de Junho de 2017, 16:40
[...] Como fazer para chamar uma função em um arquivo separado?
Principal motivo seria se criar outro script poder reutilizar a mesma função arquivos diferentes.

Se bem entendi a questão, de uma forma simples não há necessidade de um comando especial para chamar uma função que está em um script externo.
Trata-se de uma chamada como a de um outro programa executável qualquer, apenas com o detalhe de que o caminho completo deve ser informado e usando o /bin/bash

Ilustrando:

Tem-se um script externo nominado function01.sh e que se encontra em /home/username
O conteúdo desse hipotético script é o seguinte:


#!/bin/sh

echo "function 01"
echo "vale più l'opinione di un solo sapiente che quella di una moltitudine di stolti"
echo "finish first script italo-americano"


Tem-se ainda um outro script externo nominado function02.sh, que se encontra em /home/username/Downloads
O conteúdo desse também hipotético segundo script é o seguinte:


#!/bin/sh

echo "function 02"
echo "quel celeste sentiero"
echo "di luce coprendo"
echo "è del mar, del sole."
echo "finish second script italo-americano"


Tem-se agora um outro script, nominado mainfunction.sh, que num dado momento de sua execução precisa executar também os comandos que estão no script01.sh e no script02.sh, então o conteúdo do nosso hipotético mainfunction.sh poderá ser:


#!/bin/sh

#script principal que chama outros scripts

echo "primeiro comando"
echo "segundo comando"
echo "terceiro comando"

echo "chamando agora outros scripts externos com tais e quais comandos"

/bin/bash ~/function01.sh

echo "tá chamado o primeiro script"
echo "verifique se executou corretamente"

echo "quarto comando"
echo "quinto comando"

/bin/bash ~/Downloads/function02.sh

echo "tá chamado o segundo script"
echo "verifique se também executou corretamente"

echo "fim do processamento"


Experimenta aí com esse exemplo hipotético acima e veja o resultado.
www.arredondar.org.br
Vencedor Desafio de Impacto Social Google 2016!
Você também pode participar e fazer a diferença.

druidaobelix

Apenas complementando, acho que não fui muito claro: uma função num bash script nada mais é que um simples rótulo (label) aplicado a um subconjunto de código.

Não há nada de especial numa função, a atribuição do rótulo, em si, não altera absolutamente nada no código que vem a seguir, pois, como dito, é apenas um marcador de início e fim de um subconjunto de código para não ter que ficar repetindo código ao longo da construção lógica do bash script, que nada mais é que um programa como qualquer outro, apenas que interpretado em tempo de execução.

Assim sendo, um script pode chamar um outro script, como chama qualquer outro programa executável, não precisando ser qualificado de função. É função, no sentido de rótulo, se estiver dentro do mesmo script, ou então será o mesmo código apenas que colocado num outro script, portanto, externo.
www.arredondar.org.br
Vencedor Desafio de Impacto Social Google 2016!
Você também pode participar e fazer a diferença.

druidaobelix

#3
Usando o source para incluir um script (ou uma função)

Indo um passo além (e complicando um pouquinho mais), uma outra forma de se fazer isso é usar o recurso source para executar outros scrip e, por conseguinte, se o outro script é uma função, então estará incluindo a função.

Isso pode ser interessante e necessário quando o script envolve questões de variáveis.

Em linhas gerais se pode entender assim: quando é chamado um script dentro de um outro script, as variáveis do shell daquele que chama não são afetadas pela execução do script chamado, o que significa que se o script chamado deveria alterar variáveis no processamento global, apenas não irá fazer.

Na execução direta o script chamado será executado num shell diferente, que será encerrado ao término daquele script e isso nem sempre é conveniente, muito embora frequentemente também não faça diferença, dependendo do que concretamente se está processando.

Para que todo o processo seja feito dentro do mesmo shell, e então nesse caso o script chamado, se o caso, irá afetar as variáveis locais, então o melhor é usar o source para incluir scripts chamados.

Também aqui se o script chamado pelo source não estiver no mesmo diretório, então é necessário fornecer o caminho completo.

Ilustrando o uso do source:

Tem-se três scripts, quais sejam:

main.sh

#!/bin/bash

source incluso01.sh

source incluso02.sh

echo "comando 01"
echo "comando 02"
echo "comandos etc..."

echo "Este é o main.sh script"

incluso01.sh

#!/bin/bash

echo "comando 01 do incluso01"
echo "comando 02 do incluso01"
echo "comando etc... do incluso01"

echo "Este é o incluso01.sh script"

incluso02.sh

#!/bin/bash

echo "comando 01 do incluso02"
echo "comando 02 do incluso02"
echo "comando etc... do incluso02"

echo "Este é o incluso02.sh script"

Criados os scripts, e apenas para simplificar se está supondo que estejam todos dentro do mesmo diretório, então execute o principal fazendo:

./main.sh

O output será:

comando 01 do incluso01
comando 02 do incluso01
comando etc... do incluso01
Este é o incluso01.sh script
comando 01 do incluso02
comando 02 do incluso02
comando etc... do incluso02
Este é o incluso02.sh script
comando 01
comando 02
comandos etc...
Este é o main.sh script


Assim sendo, o source também pode ser utilizado para incluir outros scripts.

Existem outros aspectos, mas para começar a conversar sobre o tema, acho que isso por enquanto basta.  :)

www.arredondar.org.br
Vencedor Desafio de Impacto Social Google 2016!
Você também pode participar e fazer a diferença.

Cristiano_UP

Boa tarde Druidaobelix,

Explicação nota 10! - Perfect!

Testei e funcionou, muito grato pelo seu auxílio!

Tenho script com várias funções, e gostaria de reaproveitar o código em outros scripts!

Faltou testar com o comando source, porém entendi bem a diferença que você falou sobre alteração em variáveis!

----------------------------

Criei um script que após uma instalação do sistema faça as principais tarefas automatizadas!
- Update
- Remover pacotes não utilizados
- limpar cache (.deb)
- Entre tantos outros tarefas.

Igualmente se tiver alguma outra dica, muito legal aprender com os outros!

Thank you!
Cristiano.

druidaobelix

Citação de: Cristiano_UP online 17 de Junho de 2017, 15:13
Tenho script com várias funções, e gostaria de reaproveitar o código em outros scripts!

Pois então, "Cristiano_UP",

Note que é possível criar um arquivo que seja uma biblioteca de funções, tornando-o disponível dentro do mesmo ambiente do shell quando da execução do script principal.

Uma vez carregado e tornado disponível, as funções podem ser chamadas no script principal como se estivessem transcritas no corpo dele.

Nesse caso chame a biblioteca de funções informando o caminho usando:

. /path/to/myfunctionslibrary.sh


exemplo:

. ~/myfunctionslibrary.sh

ou

. /home/username/myfunctionslibrary.sh

no exemplo acima, username, claro, é o nome concreto do usuário

Ilustrando:

Um arquivo com as funções de biblioteca de funções contendo 3 funções pré-definidas (ou 30 ou 300, tanto faz), que para ilustar vamos dar o nome de myfunctionslibrary.sh

myfunctionslibrary.sh


#!/bin/sh

#Biblioteca de Funções para Teste

F_FUNCTION01TESTE()
{
echo "Sou a função 01 para teste"
echo "sou parte da biblioteca de funções"
echo "fui carregada no início do script"
echo "fui chamada no script principal"
echo "comando a"
echo "comando b"
echo "comando etc..."
echo "terminando processamento da função01teste"
}

F_FUNCTION02TESTE()
{
echo "Sou a função 02 para teste"
echo "também faço parte da biblioteca de funções"
echo "também fui carregada no início do script"
echo "fui igualmente chamada no script principal"
echo "comando c"
echo "comando d"
echo "comando etc..."
echo "terminando processamento da função02teste"
}

F_FUNCTION03TESTE()
{
echo "Sou a função 03 para teste"
echo "Estou no conjunto de funções da biblioteca"
echo "Faço parte do arquivo myfunctionslibrary.sh"
echo "Mas poderia fazer parte de qualquer outro arquivo"
echo "Desde que carregado no início do script"
echo "A partir da carga do arquivo do qual faço parte"
echo "comando e"
echo "comando f"
echo "comando etc..."
echo "terminando processamento da função03teste"
echo "Bye, Bye..."
}


Agora um script, ao qual para ilustar daremos o nome de myscript.sh, que irá carregar o arquivo da biblioteca de funções e em seguida chamará comandos e ainda tais e quais funções a partir do seu próprio rótulo individualizado.

myscript.sh


#!/bin/sh

#script de teste de chamada de funções usando o rótulo da função

#carregando a biblioteca de funções

. ~/myfunctionslibrary.sh

echo "inicie sempre carregando o arquivo de funções no início do script"
echo "exatamente igual ao que faria"
echo "se a função estivesse reproduzida no próprio script"

echo

echo "uma vez que o arquivo de bibliotecas foi carregado,"
echo "as funções podem ser chamadas como se estivessem no próprio script"
echo "Vamos testar?"

echo

echo "comando 01 do myscript"
echo "comando 02 do myscript"
echo "comando 03 do myscript"

echo "chamando a função01teste"

F_FUNCTION01TESTE

echo "comando 04 do myscript"
echo "comando 05 do myscript"

echo "chamando a função02teste"

F_FUNCTION02TESTE

echo "comando 06 do myscript"
echo "comando 07 do myscript"
echo "comando 08 do myscript"

echo "chamando a função01 teste novamente"

F_FUNCTION01TESTE

echo "comando 09 do myscript"
echo "comando 10 do myscript"

echo "chamando a função 03 teste"

F_FUNCTION03TESTE

echo "encerrando o processamento..."
echo "Hello World :-) "


Criados os dois arquivos dos scripts acima, que para efeitos de execução vamos presumir que já tenha sido dado autorização de execução (chmod +x script) e que estejam ambos diretamente na /home do sistema, então execute fazendo:

./myscript.sh




www.arredondar.org.br
Vencedor Desafio de Impacto Social Google 2016!
Você também pode participar e fazer a diferença.

Cristiano_UP

Boa noite Druidaobelix,

É exatamente isto que gostaria de fazer, em outras palavras essa é finalidade, ou seja, criar uma biblioteca de funções para facilitar nas tarefas.

Por exemplo, antes scripts eram assim:

- 01 script_principal.sh (mais utilizado) com diversas funções
- por ex.: Para mostrar os arquivos ocultos na inicialização e remover o que não utilizo. Utilizo uma função para isso. Entre tantas outras funções.

- 01 script somente instalar pacotes (.deb) principais após instalação
- 01 script algumas personalizações para Unity
- 01 script somente para o Gnome (algumas personalizações, muito útil)

Entre esses scripts contém algumas funções "iguais" por exemplo:
Em todos os scripts tem uma função que seria o comando Reinicar ou Desligar, ou seja, com o comando shutdown. Pois, é raro utilizar o Menu Desligar ou Reiniciar!!!

E o melhor é saber que iniciar com apenas alguns comandos e adicionando aos poucos, parar para pensar, quantos comandos já incluí que facilita e muito nesta tarefa, é muito legal.

Bom, a ideia é esta, criar uma biblioteca de funções, para facilitar!!!

Todas as suas dicas foram muito importantes!!!

Obrigado.

Cristiano_UP

Druidaobelix,

Antes executava o script direto pelo terminal seguinte comando:

./Área\ de\ Trabalho/Script/tarefas.sh "funcionava" (versão anterior).

Agora com as suas dicas criei várias bibliotecas em outros arquivos e utilizo o comando source para carregar no início do script.
Se executar o script pelo nautilus, "executar pelo terminal" (lembrando dentro do nautilus) funciona todas as opções sem erros.
Permissão de execução, nome dos arquivos, nome de cada função etc.

Se abrir direto pelo terminal e executar o comando:
./Área\ de\ Trabalho/Script/tarefas.sh o script executa, porém, não carrega os arquivos com os outros script (erro ao ler o comando source).

Mas se voltar a executar pelo nautilus sem fazer nenhuma alteração nos arquivos funciona.

Notei que, teria que abrir o terminal digitar manualmente o caminho e depois executar o script.
Exemplo: cd Área\ de\ Trabalho/Script e depois ./tarefas.sh sem ter feito nenhuma alteração funciona (comando source).

Pergunta por que direto pelo terminal não abre a não ser digitando todo o caminho manualmente e sem alterar os arquivos se abrir pelo nautilus executa sem erros?

No aguardo,
Cristiano.


druidaobelix

Isso está relacionado as variáveis de ambiente disponíveis para o script no momento da execução.

Note que global e recursivamente a /home não faz, por padrão, parte da path do sistema.

Aliás, como norma de segurança, um diretório /home/ubuntu/bin deveria ser criado e os scripts, que são executáveis, deixados exclusivamente lá dentro, notando ainda que esse caminho já vem pré-definido na variável $PATH

À propósito, também é uma boa prática incluir os seus scripts uma path local para o script, que informe a própria variável $PATH do sistema mais o caminho específico daquilo que se está trabalhando.

Um exemplo:

PATH=$PATH:/usr/local/lib/python2.7/dist-packages/wx-3.0-gtk2.pth

Estou dizendo para o script que além da variável $PATH global do sistema é para acrescentar aquele outro caminho de trabalho, que obviamente não faz parte da variável global.

Para não ter que repetir tudo aqui, dê uma lida nesse artigo, ele explica bem a questão:

https://elias.praciano.com/2016/01/por-que-precisamos-usar-antes-do-nome-de-um-script-para-executa-lo-no-linux/
www.arredondar.org.br
Vencedor Desafio de Impacto Social Google 2016!
Você também pode participar e fazer a diferença.

Cristiano_UP

Boa noite Druidaobelix,

Fiz alteração conforme você citou, variáveis de ambientes, funcionou!!!

Já alterei ficou muito legal, cada função em arquivo separado para poder utilizar em outros scripts.

Obrigado pelas dicas!

Cristiano.