¿Cómo puedo ejecutar una función desde un script en la línea de comandos?

119

Tengo un script que tiene algunas funciones.

¿Puedo ejecutar una de las funciones directamente desde la línea de comando?

¿Algo como esto?

myScript.sh func()
AAaa
fuente

Respuestas:

66

Si el script solo define las funciones y no hace nada más, primero puede ejecutar el script dentro del contexto del shell actual usando el comando sourceo .y luego simplemente llamar a la función. Consulte help sourcepara obtener más información.

Sven Marnach
fuente
1
El único problema con este método es que si lo usa exiten su función, cerrará el terminal después de que se ejecute la función. ¿Hay alguna forma de evitar esto? @SvenMarnach
user1527227
@ user1527227: Vaya con la siguiente respuesta en ese caso, dado que tiene el control del script de shell. Si no lo hace, puede llamar a una subcapa interactiva primero (solo ingrese bash), y exitsolo terminará la subcapa, pero no su terminal.
Sven Marnach
238

Bueno, mientras que las otras respuestas son correctas, ciertamente puede hacer otra cosa: si tiene acceso al script bash, puede modificarlo y simplemente colocar al final el parámetro especial "$@", que se expandirá a los argumentos de la línea de comando usted especifica, y como está "solo", el shell intentará llamarlos literalmente; y aquí podría especificar el nombre de la función como primer argumento. Ejemplo:

$ cat test.sh
testA() {
  echo "TEST A $1";
}

testB() {
  echo "TEST B $2";
}

"$@"


$ bash test.sh
$ bash test.sh testA
TEST A 
$ bash test.sh testA arg1 arg2
TEST A arg1
$ bash test.sh testB arg1 arg2
TEST B arg2

Para pulir, primero puede verificar que el comando existe y es una función:

# Check if the function exists (bash specific)
if declare -f "$1" > /dev/null
then
  # call arguments verbatim
  "$@"
else
  # Show a helpful error
  echo "'$1' is not a known function name" >&2
  exit 1
fi
sdaau
fuente
16
Úselo "$@"en la mayoría de los casos. $@no es seguro en algunos casos.
fumiyas
1
¿Cómo ejecutar más de una función? por ejemplo, ¿puedo correr bash test.sh testA testB?
Jeff Pang
Esto también debe [ ! -z "$1" ]cerrarse con, de lo contrario, la fuente generará la declaración else en algunas versiones de bash
JackLeo
He estado buscando de cerca y de lejos esta variable mágica "$ @" para usar cualquier función que se llame en un archivo, ¡gracias @sdaau!
Justin Hammond
36

El siguiente comando primero registra la función en el contexto y luego la llama:

. ./myScript.sh && function_name
TimonWang
fuente
1
También puede simplemente usar source. Como en - source myScript.sh && function_name
stolen_leaves
17

Brevemente, no.

Puede importar todas las funciones del script a su entorno con source(help source para obtener más detalles), que luego le permitirá llamarlas. Esto también tiene el efecto de ejecutar el script, así que tenga cuidado.

No hay forma de llamar a una función desde un script de shell como si fuera una biblioteca compartida.

sorigal
fuente
1
Creo que a esto se le debería dar más peso como respuesta apropiada. Traté de hacer algo similar a lo que quiere el OP, pero los scripts de shell simplemente no están diseñados para un "desarrollo limpio de OOP" (en mi humilde opinión).
Dan L
4

Utilizando case

#!/bin/bash

fun1 () {
    echo "run function1"
    [[ "$@" ]] && echo "options: $@"
}

fun2 () {
    echo "run function2"
    [[ "$@" ]] && echo "options: $@"
}

case $1 in
    fun1) "$@"; exit;;
    fun2) "$@"; exit;;
esac

fun1
fun2

Este script ejecutará las funciones fun1 y fun2, pero si lo inicia con la opción fun1 o fun2, solo ejecutará la función dada con args (si se proporciona) y saldrá. Uso

$ ./test 
run function1
run function2

$ ./test fun2 a b c
run function2
options: a b c
Iván
fuente
1

Editar: ADVERTENCIA: parece que esto no funciona en todos los casos, pero funciona bien en muchos scripts públicos.

Si tiene un script de bash llamado "control" y dentro de él tiene una función llamada "construir":

function build() { 
  ... 
}

Entonces puedes llamarlo así (desde el directorio donde está):

./control build

Si está dentro de otra carpeta, eso lo haría:

another_folder/control build

Si su archivo se llama "control.sh", eso haría que la función se pueda llamar así:

./control.sh build
Arturas M
fuente
1
Esto no funcionó en shell interactivo para mí. Pero esto funcionó:. ./control.sh && build
saulius2
1

Tengo una situación en la que necesito una función del script bash que no debe ejecutarse antes (por ejemplo, por source) y el problema @$es que myScript.sh se ejecuta dos veces, parece ... Así que se me ocurrió la idea para sacar la función con sed:

sed -n "/^func ()/,/^}/p" myScript.sh

Y para ejecutarlo en el momento que lo necesito, lo guardo en un archivo y uso source:

sed -n "/^func ()/,/^}/p" myScript.sh > func.sh; source func.sh; rm func.sh

vchrizz
fuente
0

puede llamar a la función desde el argumento de la línea de comando como se muestra a continuación

function irfan() {
echo "Irfan khan"
date
hostname
}
function config() {
ifconfig
echo "hey"
}
$1

una vez que finalice la función, coloque $ 1 para aceptar el argumento, digamos que el código anterior se guarda en fun.sh para ejecutar la función ./fun.sh irfan & ./fun.sh config

Irfan Khan
fuente
0

Publicación resuelta, pero me gustaría mencionar mi solución preferida. Es decir, defina un script genérico de una sola línea eval_func.sh:

#!/bin/bash
source $1 && shift && "@a"

Luego llame a cualquier función dentro de cualquier script a través de:

./eval_func.sh <any script> <any function> <any args>...

Un problema que encontré con la solución aceptada es que cuando obtengo mi script que contiene la función dentro de otro script, los argumentos de este último serían evaluados por el primero, lo que provocaría un error.

Evan
fuente