Cómo definir una función Bash que pueda ser utilizada por diferentes scripts

13

He definido una bashfunción en mi ~/.bashrcarchivo. Esto me permite usarlo en terminales de shell. Sin embargo, no parece existir cuando lo llamo desde un script.

¿Cómo puedo definir una bashfunción para que la utilicen también los scripts?

Onturenio
fuente
Pero mi .bash_profile básicamente lee el archivo .basrc, por lo que esperaría que el resultado sea el mismo independientemente de si uso el shell de inicio de sesión o no inicio de sesión.
Onturenio
¿Estás usando /bin/shen la línea shebang?
Kevin

Respuestas:

9

~/.bash_profiley ~/.bashrcno son leídos por scripts, y las funciones no se exportan por defecto. Para hacerlo, puede usar export -fasí:

$ 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 footambién podría llamarse ~/.bash_profilepara que esta función esté disponible para los scripts después de iniciar sesión. Ten en cuenta que export -fno es portátil.

Una mejor solución sería obtener el archivo que contiene la función usando . file. Esto es mucho más portátil y no depende de que su entorno esté configurado de una manera particular.

Chris Down
fuente
¿por qué no simplemente declaras una función como function myFunction { ... }en ~/.bash_profiley estás listo?
anfibio
Si entendí correctamente su respuesta (con respecto a la obtención de un archivo con la función), esto significaría que tengo que obtener el archivo explícitamente en cada script, lo cual es bastante molesto. Esto no es mucho menos complicado que simplemente copiar y pegar la función en cada script. Guardaría algunas líneas, claro, pero eso es todo. Sin embargo, la exportsolución parece funcionar correctamente. Gracias.
Onturenio
@foampile, esto es precisamente lo que hice y no funciona al llamar a la función desde un script.
Onturenio
1
@Onturenio: el segundo método propuesto por @ chris-down es realmente mejor: 1) Cuando alguien lee el script, es consciente de que necesita alguna foofunción de algunos file2) Puede controlar mejor el contenido de eso fileque asegurarse de que el shell de invocación no cambió fooantes de invocar su script. Puede agregar controles de seguridad filepara asegurarse de que no esté sujeto, por ejemplo. (No es fácil, pero posible). (bueno, también podrías hacer esas verificaciones en la función foo definida ... pero entiendes ^^ Creo que el método 2 es más limpio). 3) filesolo contendrá lo que se necesita, no más.
Olivier Dulac
8

.bashrcsolo se lee mediante shells interactivos. (En realidad, eso es una simplificación excesiva: bash es peculiar a este respecto. Bash no lee .bashrcsi es un shell de inicio de sesión, interactivo o no. Y hay una excepción incluso a la excepción: si el proceso padre de bash es rshdo sshd, entonces bash lee .bashrc, ya sea interactivo o no)

Coloque las definiciones de sus funciones en un archivo en un lugar conocido y use el .( sourceincorporado también deletreado ) para incluir ese archivo en un script.

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

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

Si lo desea, puede seguir la función de carga automática de ksh. Coloque cada definición de función en un archivo con el mismo nombre que la función. Enumere los directorios que contienen las definiciones de funciones en la FPATHvariable (una lista de directorios separados por dos puntos). Aquí hay una aproximación cruda de ksh autoloadque realmente carga la función inmediatamente en lugar de bajo 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- deja de ser malvado'
fuente
+1 para carga automática, aunque recomiendo usar los que vienen con bash. El último admite carga perezosa.
Starfish
0

¿ Necesitas una función? Si no es así, considere extraer la lógica en un script Bash independiente e independiente en su $PATH. Por ejemplo, tuve esto en mi ~/.bashrc:

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

~/binestá en mi $PATH, así que creé ~/bin/wanipcon los siguientes contenidos:

#!/bin/bash

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

Y corrió chmod 0755 ~/bin/wanippara hacerlo ejecutable. Ahora puedo ejecutar wanipdesde otros scripts.

Me gusta tener wanipun script Bash independiente. Me recuerda que quiero que esta lógica esté generalmente disponible (además de solo en mi sesión interactiva actual de Bash). El script encapsula muy bien la lógica y la documentación para el mismo.

Adam Monsen
fuente