Jak zdefiniować funkcję Bash, która może być używana przez różne skrypty

13

bashW moim ~/.bashrcpliku zdefiniowałem funkcję . To pozwala mi używać go w terminalach powłokowych. Jednak wydaje się, że nie istnieje, gdy wywołuję go ze skryptu.

Jak mogę zdefiniować bashfunkcję, która będzie używana także przez skrypty?

Onturenio
źródło
Ale mój .bash_profile w zasadzie czyta plik .basrc, więc spodziewałbym się, że wynik będzie taki sam, niezależnie od tego, czy użyję powłoki logowania lub bez logowania.
Onturenio
Czy używasz /bin/shlinii shebang?
Kevin

Odpowiedzi:

9

~/.bash_profilei ~/.bashrcnie są odczytywane przez skrypty, a funkcje nie są domyślnie eksportowane. Aby to zrobić, możesz użyć export -f:

$ 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 foomożna również wywołać w ~/.bash_profilecelu udostępnienia tej funkcji skryptom po zalogowaniu. Ostrzegam, że export -fnie jest przenośny.

Lepszym rozwiązaniem byłoby źródło pliku zawierającego funkcję . file. Jest to o wiele bardziej przenośne i nie zależy od skonfigurowania środowiska w określony sposób.

Chris Down
źródło
dlaczego po prostu nie zadeklarować funkcji jak function myFunction { ... }w ~/.bash_profilei jesteś gotowy?
amfibia
Jeśli dobrze zrozumiałem twoją odpowiedź (dotyczącą pozyskiwania pliku z funkcją), oznaczałoby to, że muszę jawnie pozyskiwać plik w każdym skrypcie, co jest dość denerwujące. Nie jest to wcale mniej skomplikowane niż zwykłe kopiowanie samej funkcji w każdym skrypcie. Oczywiście zapisałbym kilka wierszy, ale to wszystko. Jednak exportwydaje się , że rozwiązanie działa poprawnie. Dzięki.
Onturenio
@foampile, właśnie to zrobiłem i nie działa podczas wywoływania funkcji ze skryptu.
Onturenio
1
@Onturenio: druga proponowana metoda @ chris-down jest rzeczywiście lepsza: 1) Kiedy ktoś czyta skrypt, ma świadomość, że potrzebuje on jakiejś foofunkcji z file2) Możesz lepiej kontrolować jego zawartość fileniż upewnić się, że wywołująca powłoka nie zmieniło się fooprzed wywołaniem skryptu. Możesz na przykład dodać kontrole bezpieczeństwa, fileaby upewnić się, że nie są naruszone. (niełatwe, ale możliwe). (cóż, możesz również wykonać te kontrole zdefiniowanej funkcji foo ... ale dostajesz mój dryf ^^ Myślę, że metoda 2 jest czystsza.) 3) filebędzie zawierała tylko to, co jest potrzebne, a nie więcej.
Olivier Dulac
8

.bashrcjest odczytywany tylko przez interaktywne powłoki. (Faktycznie, to nadmierne uproszczenie: bash jest nietypowy pod tym względem atakujących nie czyta. .bashrcCzy jest to powłoka logowania, interaktywne czy nie i nie ma wyjątku nawet wyjątku. Jeśli proces nadrzędny Bash jest rshdlub sshd, a następnie bash czyta .bashrc, czy to interaktywne czy nie.)

Umieść definicje funkcji w pliku w znanym miejscu i użyj wbudowanej .(także pisowni source) wbudowanej, aby dołączyć ten plik do skryptu.

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

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

Jeśli chcesz, możesz śledzić funkcję automatycznego ładowania ksh. Umieść każdą definicję funkcji w pliku o tej samej nazwie co funkcja. Wyświetl katalogi zawierające definicje funkcji w FPATHzmiennej (lista katalogów oddzielona dwukropkami). Oto przybliżone przybliżenie ksh, autoloadktóre faktycznie ładuje funkcję natychmiast zamiast na żądanie:

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- przestań być zły”
źródło
+1 za automatyczne ładowanie, chociaż zalecam korzystanie z tych, które są dostarczane z bash. Najnowsza obsługuje leniwe ładowanie.
Rozgwiazda
0

Czy potrzebujemy funkcję? Jeśli nie, rozważ wyciągnięcie logiki do osobnego, samodzielnego skryptu Bash w swoim $PATH. Na przykład miałem to w moim ~/.bashrc:

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

~/binjest w mojej $PATH, więc utworzyłem ~/bin/wanipz następującą zawartością:

#!/bin/bash

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

I pobiegł, chmod 0755 ~/bin/wanipaby był wykonywalny. Teraz mogę wykonać wanipz innych skryptów.

Lubię mieć wanipw samodzielnym skrypcie Bash. Przypomina mi, że chcę, aby ta logika była ogólnie dostępna (poza tym w mojej bieżącej interaktywnej sesji Bash). Skrypt ładnie zawiera logikę i dokumentację.

Adam Monsen
źródło