Como definir uma função Bash que pode ser usada por diferentes scripts

13

Eu defini uma bashfunção no meu ~/.bashrcarquivo. Isso me permite usá-lo em terminais shell. No entanto, parece não existir quando eu o chamo de dentro de um script.

Como posso definir uma bashfunção a ser usada pelos scripts também?

Onturenio
fonte
Mas meu .bash_profile basicamente lê o arquivo .basrc, portanto, espero que o resultado seja o mesmo, independentemente de eu usar o shell de login ou não.
Onturenio
Você está usando /bin/shna linha shebang?
Kevin

Respostas:

9

~/.bash_profilee ~/.bashrcnão são lidos por scripts, e as funções não são exportadas por padrão. Para fazer isso, você pode usar export -fo seguinte:

$ cat > script << 'EOF'
#!/bin/bash
foo
EOF
$ chmod a+x script
$ ./script
./script: line 2: foo: command not found
$ foo() { echo "works" ; } 
$ export -f foo
$ ./script
works

export -f footambém pode ser chamado ~/.bash_profilepara disponibilizar essa função para scripts após o login. Esteja avisado de que export -fnão é portátil.

Uma solução melhor seria obter o arquivo que contém a função usando . file. Isso é muito mais portátil e não depende de seu ambiente ser configurado de uma maneira específica.

Chris Down
fonte
por que não apenas declarar uma função como function myFunction { ... }em ~/.bash_profilee você está pronto?
amphibient
Se eu entendi corretamente sua resposta (em relação à obtenção de um arquivo com a função), isso significaria que eu teria que fornecer o arquivo explicitamente em todos os scripts, o que é bastante irritante. Isso não é muito menos complicado do que apenas copiar e colar a própria função em todos os scripts. Eu salvaria algumas linhas, claro, mas é tudo. No entanto, a exportsolução parece funcionar corretamente. Obrigado.
Onturenio
@ ampampile, isto é precisamente o que eu fiz e não funciona ao chamar a função de um script.
Onturenio
1
@Onturenio: o segundo método proposto por chris-down é realmente melhor: 1) Quando alguém lê o script, sabe que ele precisa de alguma foofunção de file2) Você pode controlar melhor o conteúdo do que filegarantir que o shell de chamada não mudou fooantes de chamar seu script. Você pode adicionar verificações de segurança filepara garantir que ela não seja alterada, por exemplo. (não é fácil, mas é possível). (bem, você também pode fazer essas verificações na função foo definida ... mas você entende meu desvio ^^ Acho que o método 2 é mais limpo.) 3) fileconterá apenas o necessário, e não mais.
Olivier Dulac
8

.bashrcé lido apenas por conchas interativas. (Na verdade, isso é uma simplificação excessiva: o bash é peculiar a esse respeito. O Bash não lê .bashrcse é um shell de logon, interativo ou não. E há uma exceção até a exceção: se o processo pai do bash for rshdor sshd, então o bash lê .bashrc, seja interativo ou não.)

Coloque suas definições de função em um arquivo em um local conhecido e use o .(também escrito source) para incluir esse arquivo em um script.

$ cat ~/lib/bash/my_functions.bash
foo () {

$ cat ~/bin/myscript
#!/bin/bash
. ~/lib/bash/my_functions.bash
foo bar

Se desejar, você pode seguir o recurso de carregamento automático do ksh. Coloque cada definição de função em um arquivo com o mesmo nome que a função. Liste os diretórios que contêm as definições de função na FPATHvariável (uma lista de diretórios separados por dois pontos). Aqui está uma aproximação grosseira do ksh, autoloadque realmente carrega a função imediatamente, em vez de sob demanda:

autoload () {
  set -- "$(set +f; IFS=:;
            for d in $FPATH; do
              if [ -r "$d/$1" ]; then echo -E "$d/$1"; break; fi;
            done)"
  [[ -n $1 ]] && . "$1"
}
Gilles 'SO- parar de ser mau'
fonte
+1 para carregamento automático, embora eu recomende usar os que vêm com o bash. O mais recente suporta carga lenta.
Starfish
0

Você precisa de uma função? Caso contrário, considere extrair a lógica em um script Bash independente e separado no seu $PATH. Por exemplo, eu tive isso no meu ~/.bashrc:

# echo public IP address
alias wanip='dig +short myip.opendns.com @resolver1.opendns.com'

~/binestá no meu $PATH, então eu criei ~/bin/wanipcom o seguinte conteúdo:

#!/bin/bash

# echo public IP address
dig +short myip.opendns.com @resolver1.opendns.com

E correu chmod 0755 ~/bin/wanippara torná-lo executável. Agora eu posso executar a wanippartir de outros scripts.

Eu gosto de ter wanipum script Bash independente. Isso me lembra que eu quero essa lógica geralmente disponível (além apenas da minha atual sessão interativa do Bash). O script encapsula bem a lógica e a documentação para o mesmo.

Adam Monsen
fonte