Czy mogę wywołać funkcję skryptu powłoki z innego skryptu powłoki?

86

Mam 2 skrypty powłoki.

Drugi skrypt powłoki zawiera następujące funkcje second.sh

func1 
func2

Plik first.sh wywoła drugi skrypt powłoki z pewnymi parametrami i wywoła funkcje func1 i func2 z innymi parametrami specyficznymi dla tej funkcji.

Oto przykład tego, o czym mówię

second.sh

val1=`echo $1`
val2=`echo $2`

function func1 {

fun=`echo $1`
book=`echo $2`

}

function func2 {

fun2=`echo $1`
book2=`echo $2`


}

first.sh

second.sh cricket football

func1 love horror
func2 ball mystery

Jak mogę to osiągnąć?

avirup
źródło
3
v=$(echo $1)jest całkowicie zbędny. Po prostu napisz fun2=$1. Jedyna różnica polega na tym, że $()(lub lewy apostrof) usuwają końcowe znaki nowej linii.
William Pursell
1
Ponieważ nie ma nic specjalnego w wywoływaniu funkcji ze skryptu powłoki w przeciwieństwie do wiersza poleceń, to pytanie można sprowadzić do „Jak wywołać funkcję bash?”
Tom Russell

Odpowiedzi:

145

Refaktoryzuj swój second.shskrypt w ten sposób:

function func1 {
   fun=$1
   book=$2
   printf "fun=%s,book=%s\n" "${fun}" "${book}"
}

function func2 {
   fun2=$1
   book2=$2
   printf "fun2=%s,book2=%s\n" "${fun2}" "${book2}"
}

Następnie wywołaj te funkcje ze skryptu w first.shnastępujący sposób:

source ./second.sh
func1 love horror
func2 ball mystery

WYNIK:

fun=love,book=horror
fun2=ball,book2=mystery
anubhava
źródło
12
Aby uniknąć niezamierzonych efektów ubocznych, uważaj, że sourcepolecenie faktycznie uruchomi skrypt przekazany jako argument.
dvlcube
43

Nie możesz bezpośrednio wywołać funkcji w innym skrypcie powłoki.

Możesz przenieść definicje funkcji do oddzielnego pliku, a następnie załadować je do skryptu za pomocą .polecenia, na przykład:

. /path/to/functions.sh

Będzie to interpretowane functions.shtak, jakby w tym momencie zawartość była faktycznie obecna w pliku. Jest to powszechny mechanizm implementacji współdzielonych bibliotek funkcji powłoki.

larsks
źródło
3
Czy to nie to samo, co zaakceptowana odpowiedź, ponieważ .jest to alias dla source?
ajsharma
9
Cóż, odpowiedziałem pierwszy, więc technicznie przyjęta odpowiedź jest taka sama jak ta :). Ponadto, chociaż w wielu powłokach sourcejest aliasem dla ., nie zawsze tak jest. Na przykład dashpakiet na Debianie, który zapewnia /bin/sh, nie ma sourcepolecenia.
larsks 22.08.18
sourcepolecenie nie działało w Ubuntu @ajsharma. Odniesienie: nie znaleziono polecenia źródła w powłoce sh
rajeshmag
tak dziwne, że ten komentarz nie jest uznawany za najwyższy? To jest poprawna składnia #! / Bin / sh, a druga będzie działać tylko w bashu.
xddq
20

Problem

Obecnie akceptowana odpowiedź działa tylko pod ważnymi warunkami. Dany...

/foo/bar/first.sh:

function func1 {  
   echo "Hello $1"
}

i

/foo/bar/second.sh:

#!/bin/bash

source ./first.sh
func1 World

działa to tylko wtedy, gdy first.shjest wykonywany z tego samego katalogu, w którym first.shznajduje się. To znaczy. jeśli bieżącą ścieżką roboczą powłoki jest /foo, próba uruchomienia polecenia

cd /foo
./bar/second.sh

błąd wydruków:

/foo/bar/second.sh: line 4: func1: command not found

Dzieje się tak, ponieważ source ./first.shjest on względny w stosunku do bieżącej ścieżki roboczej, a nie ścieżki do skryptu. Stąd jednym rozwiązaniem może być użycie podpowłoki i uruchomienie

(cd /foo/bar; ./second.sh)

Bardziej ogólne rozwiązanie

Dany...

/foo/bar/first.sh:

function func1 {  
   echo "Hello $1"
}

i

/foo/bar/second.sh:

#!/bin/bash

source $(dirname "$0")/first.sh

func1 World

następnie

cd /foo
./bar/second.sh

wydruki

Hello World

Jak to działa

  • $0 zwraca względną lub bezwzględną ścieżkę do wykonywanego skryptu
  • dirname zwraca ścieżkę względną do katalogu, w którym istnieje skrypt $ 0
  • $( dirname "$0" )dirname "$0"polecenie zwraca ścieżkę względną do katalogu wykonywanego skryptu, który jest następnie wykorzystywany jako argument dla sourcekomendy
  • w „second.sh”, /first.shpo prostu dodaje nazwę zaimportowanego skryptu powłoki
  • source ładuje zawartość określonego pliku do bieżącej powłoki
Patrik Stas
źródło
0

Jeśli zdefiniujesz

    #!/bin/bash
        fun1(){
          echo "Fun1 from file1 $1"
        }
fun1 Hello
. file2 
fun1 Hello
exit 0

w plik1 (chmod 750 plik1) i plik2

   fun1(){
      echo "Fun1 from file2 $1"
    }
    fun2(){
      echo "Fun1 from file1 $1"
    }

i uruchom ./file2 otrzymasz Fun1 z pliku1 Hello Fun1 z pliku2 Hello Surprise !!! Zastępujesz fun1 w pliku1 przez fun1 z pliku2 ... Aby tego nie robić, musisz

declare -f pr_fun1=$fun1
. file2
unset -f fun1
fun1=$pr_fun1
unset -f pr_fun1
fun1 Hello

zapisuje twoją poprzednią definicję dla fun1 i przywraca ją z poprzednią nazwą, usuwając niepotrzebną zaimportowaną. Za każdym razem, gdy importujesz funkcje z innego pliku, możesz pamiętać dwa aspekty:

  1. możesz nadpisać istniejące z tymi samymi nazwami (jeśli to, co chcesz, musisz je zachować, jak opisano powyżej)
  2. importuj całą zawartość pliku importu (także funkcje i zmienne globalne). Uważaj! To niebezpieczna procedura
Anatolij
źródło
-5
#vi function.sh

#!/bin/bash
f1() {
    echo "Hello $name"
}

f2() {
    echo "Enter your name: "
    read name
    f1
}
f2

#sh function.sh

Tutaj funkcja f2wywoła funkcjęf1

V.SANTOSH
źródło