Comment puis-je exécuter une fonction à partir d'un script en ligne de commande?

119

J'ai un script qui a quelques fonctions.

Puis-je exécuter l'une des fonctions directement à partir de la ligne de commande?

Quelque chose comme ça?

myScript.sh func()
AAaa
la source

Réponses:

66

Si le script définit uniquement les fonctions et ne fait rien d'autre, vous pouvez d'abord exécuter le script dans le contexte du shell actuel en utilisant la commande sourceou ., puis appeler simplement la fonction. Voir help sourcepour plus d'informations.

Sven Marnach
la source
1
Le seul problème avec cette méthode est que si vous l'utilisez exitdans votre fonction, elle fermera le terminal après l'exécution de la fonction. Y a-t-il un moyen de contourner cela? @SvenMarnach
user1527227
@ user1527227: Allez avec la réponse suivante dans ce cas, étant donné que vous avez le contrôle du script shell. Si vous ne le faites pas, vous pouvez d'abord appeler un sous-shell interactif (entrez simplement bash), et exitne terminera que le sous-shell, mais pas votre terminal.
Sven Marnach
238

Eh bien, alors que les autres réponses sont correctes - vous pouvez certainement faire autre chose: si vous avez accès au script bash, vous pouvez le modifier, et placer simplement à la fin le paramètre spécial "$@"- qui s'étendra aux arguments de la ligne de commande vous spécifiez, et comme il est "seul", le shell essaiera de les appeler textuellement; et ici, vous pouvez spécifier le nom de la fonction comme premier argument. Exemple:

$ 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

Pour le polonais, vous pouvez d'abord vérifier que la commande existe et est une fonction:

# 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
la source
16
Utilisez "$@"dans la plupart des cas. $@n'est pas sûr dans certains cas.
fumiyas
1
Comment exécuter plus qu'une fonction? par exemple puis-je courir bash test.sh testA testB?
Jeff Pang
Cela doit également être emballé avec [ ! -z "$1" ] sinon la source lèvera l'instruction else dans certaines versions de bash
JackLeo
J'ai cherché de près et de loin cette variable magique "$ @" pour utiliser la fonction appelée sur un fichier, merci @sdaau!
Justin Hammond le
36

La commande suivante enregistre d'abord la fonction dans le contexte, puis l'appelle:

. ./myScript.sh && function_name
TimonWang
la source
1
Vous pouvez également simplement utiliser la source. Comme dans - source myScript.sh && function_name
stolen_leaves
17

En bref, non.

Vous pouvez importer toutes les fonctions du script dans votre environnement avec source(help source pour plus de détails), ce qui vous permettra ensuite de les appeler. Cela a également pour effet d'exécuter le script, alors faites attention.

Il n'y a aucun moyen d'appeler une fonction à partir d'un script shell comme s'il s'agissait d'une bibliothèque partagée.

sorpigal
la source
1
Je pense que cela devrait avoir plus de poids en tant que réponse appropriée. J'ai essayé de faire quelque chose de similaire à ce que voulait l'OP, mais le script shell n'est tout simplement pas conçu pour un développement "net, POO" (IMHO).
Dan L
4

En utilisant 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

Ce script exécutera les fonctions fun1 et fun2 mais si vous le démarrez avec l'option fun1 ou fun2, il n'exécutera que la fonction donnée avec args (si fourni) et quittera. Usage

$ ./test 
run function1
run function2

$ ./test fun2 a b c
run function2
options: a b c
Ivan
la source
1

Edit: AVERTISSEMENT - semble que cela ne fonctionne pas dans tous les cas, mais fonctionne bien sur de nombreux scripts publics.

Si vous avez un script bash appelé "control" et qu'il contient une fonction appelée "build":

function build() { 
  ... 
}

Ensuite, vous pouvez l'appeler comme ceci (à partir du répertoire où il se trouve):

./control build

Si c'est dans un autre dossier, cela ferait:

another_folder/control build

Si votre fichier s'appelle "control.sh", cela rendrait la fonction appelable comme ceci:

./control.sh build
Arturas M
la source
1
Cela n'a pas fonctionné dans le shell interactif pour moi. Mais cela a fonctionné:. ./control.sh && build
saulius2
1

J'ai une situation où j'ai besoin d'une fonction du script bash qui ne doit pas être exécutée avant (par exemple par source) et le problème @$est que myScript.sh est ensuite exécuté deux fois, semble-t-il ... J'ai donc eu l'idée pour sortir la fonction avec sed:

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

Et pour l'exécuter au moment où j'en ai besoin, je le mets dans un fichier et j'utilise source:

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

vchrizz
la source
0

vous pouvez appeler la fonction à partir de l'argument de ligne de commande comme ci-dessous

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

une fois la fonction end mettez $ 1 pour accepter l'argument, disons que le code ci-dessus est enregistré dans fun.sh pour exécuter la fonction ./fun.sh irfan & ./fun.sh config

Irfan Khan
la source
0

Message résolu mais j'aimerais mentionner ma solution préférée. À savoir, définissez un script générique à une seule ligne eval_func.sh:

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

Appelez ensuite n'importe quelle fonction dans n'importe quel script via:

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

Un problème que j'ai rencontré avec la solution acceptée est que lors de la recherche de mon script contenant une fonction dans un autre script, les arguments de ce dernier seraient évalués par le premier, provoquant une erreur.

Evan
la source