Jak uruchomić funkcję ze skryptu w wierszu poleceń?

119

Mam skrypt, który ma kilka funkcji.

Czy mogę uruchomić jedną z funkcji bezpośrednio z wiersza poleceń?

Coś takiego?

myScript.sh func()
AAaa
źródło

Odpowiedzi:

66

Jeśli skrypt definiuje tylko funkcje i nie robi nic więcej, możesz najpierw wykonać skrypt w kontekście bieżącej powłoki za pomocą polecenia sourcelub, .a następnie po prostu wywołać funkcję. Zobacz, help sourceaby uzyskać więcej informacji.

Sven Marnach
źródło
1
Jedynym problemem z tą metodą jest to, że jeśli użyjesz exitw swojej funkcji, zamknie ona terminal po wykonaniu funkcji. Czy można to obejść? @SvenMarnach
user1527227
@ user1527227: Przejdź do następnej odpowiedzi w tym przypadku, biorąc pod uwagę, że masz kontrolę nad skryptem powłoki. Jeśli tego nie zrobisz, możesz najpierw wywołać interaktywną podpowłokę (po prostu wprowadź bash) i exitzakończy ona tylko podpowłokę, ale nie zakończy swojego terminala.
Sven Marnach
238

Cóż, podczas gdy inne odpowiedzi są prawidłowe - z pewnością możesz zrobić coś innego: jeśli masz dostęp do skryptu bash, możesz go zmodyfikować i po prostu umieścić na końcu specjalny parametr "$@"- który rozwinie się do argumentów wiersza poleceń określasz, a ponieważ jest „sam”, powłoka będzie próbowała nazywać je dosłownie; i tutaj możesz określić nazwę funkcji jako pierwszy argument. Przykład:

$ 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

W przypadku języka polskiego możesz najpierw sprawdzić, czy polecenie istnieje i jest funkcją:

# 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
źródło
16
Używaj "$@"w większości przypadków. $@w niektórych przypadkach nie jest bezpieczne.
fumiyas
1
Jak uruchomić więcej niż funkcję? na przykład czy mogę biegać bash test.sh testA testB?
Jeff Pang,
To również musi być opakowane, w [ ! -z "$1" ]przeciwnym razie source podniesie instrukcję else w niektórych
wersjach
Szukałem blisko i daleko tej magicznej zmiennej "$ @", aby użyć dowolnej funkcji w pliku, dziękuję @sdaau!
Justin Hammond
36

Następujące polecenie najpierw rejestruje funkcję w kontekście, a następnie ją wywołuje:

. ./myScript.sh && function_name
TimonWang
źródło
1
Możesz też po prostu użyć source. Jak w - source myScript.sh && function_name
stolen_leaves
17

Krótko mówiąc, nie.

Możesz zaimportować wszystkie funkcje skryptu do swojego środowiska za pomocą source( help sourceaby uzyskać szczegółowe informacje), co pozwoli ci na ich wywołanie. Ma to również wpływ na wykonanie skryptu, więc uważaj.

Nie ma możliwości wywołania funkcji ze skryptu powłoki tak, jakby była to biblioteka współdzielona.

sorpigal
źródło
1
Myślę, że należy temu nadać większą wagę jako właściwą odpowiedź. Próbowałem zrobić coś podobnego do tego, czego oczekuje OP, ale skrypty powłoki po prostu nie są zaprojektowane do "czystego, programowania OOP" (IMHO).
Dan L
4

Za pomocą 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

Ten skrypt uruchomi funkcje fun1 i fun2, ale jeśli uruchomisz go z opcją fun1 lub fun2, uruchomi tylko daną funkcję z argumentami (jeśli są podane) i zakończy działanie. Stosowanie

$ ./test 
run function1
run function2

$ ./test fun2 a b c
run function2
options: a b c
Ivan
źródło
1

Edycja: OSTRZEŻENIE - wydaje się, że to nie działa we wszystkich przypadkach, ale działa dobrze w wielu publicznych skryptach.

Jeśli masz skrypt basha o nazwie „control”, a wewnątrz niego znajduje się funkcja o nazwie „build”:

function build() { 
  ... 
}

Następnie możesz nazwać to w ten sposób (z katalogu, w którym się znajduje):

./control build

Jeśli znajduje się w innym folderze, oznaczałoby to:

another_folder/control build

Jeśli twój plik nazywa się „control.sh”, to odpowiednio sprawi, że funkcja będzie wywoływana w następujący sposób:

./control.sh build
Arturas M
źródło
1
Nie działało to dla mnie w powłoce interaktywnej. Ale to zadziałało:. ./control.sh && build
saulius2
1

Mam sytuację, w której potrzebuję funkcji ze skryptu basha, której wcześniej nie można wykonać (np. Przez source) i problem @$polega na tym, że myScript.sh jest wtedy uruchamiany dwukrotnie, wydaje się ... Więc wpadłem na pomysł aby uzyskać funkcję za pomocą seda:

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

Aby wykonać to w momencie, w którym go potrzebuję, umieszczam go w pliku i używam source:

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

vchrizz
źródło
0

możesz wywołać funkcję z argumentu wiersza poleceń, jak poniżej

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

Po zakończeniu funkcji wstaw $ 1, aby zaakceptować argument, powiedzmy, że powyższy kod zostanie zapisany w fun.sh, aby uruchomić funkcję ./fun.sh irfan & ./fun.sh config

Irfan Khan
źródło
0

Post rozwiązany, ale chciałbym wspomnieć o moim preferowanym rozwiązaniu. Mianowicie zdefiniuj ogólny jednoliniowy skrypt eval_func.sh:

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

Następnie wywołaj dowolną funkcję w dowolnym skrypcie poprzez:

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

Problem, na który natknąłem się przy przyjętym rozwiązaniu, polega na tym, że podczas pozyskiwania mojego skryptu zawierającego funkcję w innym skrypcie argumenty tego drugiego byłyby oceniane przez ten pierwszy, powodując błąd.

Evan
źródło