Jak wywołać jeden skrypt powłoki z innego skryptu powłoki?

737

Mam dwa skrypty powłoki a.shi b.sh.

Jak mogę dzwonić b.shz poziomu skryptu powłoki a.sh?

Praveen
źródło
8
Czy możesz podać kilka szczegółów: który system operacyjny i jaką powłokę lub czy po prostu mówisz o tym problemie w zasadzie? Przykładowy kod byłby również pomocny.
jsalonen,
14
To nie jest tak naprawdę konkretne pytanie, ani nie pokazuje wcześniejszego wysiłku w celu rozwiązania problemu.
Kris,
1
Jednym z moich problemów było to, że b.shnie miał uprawnień do wykonywania. Warto sprawdzić.
seth10
Dołącz ./przed nazwą skryptu, zamiast tego: b.shużyj:./b.sh
Benny
1
Jeśli ktoś nadal otrzymuje No such file or directorybłąd stackoverflow.com/a/2920431/1356559
Amr Lotfy

Odpowiedzi:

957

Można to zrobić na kilka różnych sposobów:

  1. Ustaw drugi skrypt jako wykonywalny, dodaj #!/bin/bashwiersz u góry i ścieżkę do pliku do zmiennej środowiskowej $ PATH. Następnie możesz nazwać to normalnym poleceniem;

  2. Lub wywołaj to za pomocą sourcepolecenia (alias jest .) w następujący sposób source /path/to/script:;

  3. Lub użyj bashpolecenia, aby go wykonać: /bin/bash /path/to/script;

Pierwsza i trzecia metoda wykonują skrypt jako inny proces, więc zmienne i funkcje w drugim skrypcie nie będą dostępne.
Druga metoda wykonuje skrypt w procesie pierwszego skryptu i pobiera zmienne i funkcje z drugiego skryptu, dzięki czemu można je wykorzystać ze skryptu wywołującego.

W drugiej metodzie, jeśli używasz exitw drugim skrypcie, spowoduje to również zamknięcie pierwszego skryptu. Co nie nastąpi w pierwszej i trzeciej metodzie.

Jakiś programista
źródło
30
pamiętaj, chmod a+x /path/to/filebo inaczej nie będzie wykonywalny. Dotyczy tylko metody ./script.
Nathan Lilienthal
3
Pamiętaj, aby zmienić format / kodowanie plików wykonywalnych w Uniksie, jeśli są one tworzone w DOS, a następnie przesyłane do środowiska Unix -> dos2unix <nazwa skryptu>
Abhishek Chatterjee
3
@cecemel Pierwszym i trzecim sposobem może być „asynchronizacja” przy użyciu normalnej składni w tle.
Jakiś programista koleś
16
Problem sourcepolega na tym, że exitinstrukcja w wywoływanym skrypcie również opuści twój ...
Ohad Schneider
18
@ user528025 .nie jest pseudonimem source, ale odwrotnie. sourcejest rozszerzeniem bash, podczas gdy .działa w dowolnej powłoce kompatybilnej z POSIX.
Score_Under
207

Spójrz na to.

#!/bin/bash
echo "This script is about to run another script."
sh ./script.sh
echo "This script has just run another script."
Budha
źródło
4
Zakłada się, że skrypt.sh znajduje się w tym samym katalogu, co uruchomiony skrypt. Jeśli chcesz zadzwonić do skryptu gdzie indziej, powiedziałbyśsh <path to script>/script.sh
Morgan Kenyon
32
To również używa dwóch powłok bashi sh. Nawet kiedy shtak naprawdę bashnie zachowuje się tak samo. Jeśli używasz, #!/bin/bashto prawdopodobnie chcesz użyć bash script.sh(lub po prostu ./script.shużyć skrótu tego skryptu).
Martin Tournoij
1
chmod +xWystąpił błąd odmowy uzyskania dostępu, nawet gdy ustawiłem na plik .sh. Jakieś sugestie?
Pogoda w Isaac
@isaacweathers spróbuj chmod 777
Janac Meena
114

Można to zrobić na kilka sposobów. Terminal do wykonania skryptu:

#!/bin/bash
SCRIPT_PATH="/path/to/script.sh"

# Here you execute your script
"$SCRIPT_PATH"

# or
. "$SCRIPT_PATH"

# or
source "$SCRIPT_PATH"

# or
bash "$SCRIPT_PATH"

# or
eval '"$SCRIPT_PATH"'

# or
OUTPUT=$("$SCRIPT_PATH")
echo $OUTPUT

# or
OUTPUT=`"$SCRIPT_PATH"`
echo $OUTPUT

# or
("$SCRIPT_PATH")

# or
(exec "$SCRIPT_PATH")

Wszystko to jest poprawne dla ścieżki ze spacjami !!!

Andrei Krasutski
źródło
41
Jakie są ich różnice? Dlaczego jeden, dlaczego inny?
rakietowiec
. Preferowane jest „$ SCRIPT_PATH”
Harry Mumford-Turner
1
Mogę tylko dodać, że nie wszystkie są równoważne, np. Sh „$ SCRIPT_PATH” i bash „$ SCRIPT_PATH” nie będą uruchamiać skryptu #! / Usr / bin / expect, a jedynie „$ SCRIPT_PATH”.
Tahlor
58

Odpowiedź, której szukałem:

( exec "path/to/script" )

Jak wspomniano, execzastępuje powłokę bez tworzenia nowego procesu. Jednakże , możemy umieścić go w podpowłoce, która odbywa się za pomocą nawiasów.

EDYCJA: Właściwie ( "path/to/script" )to wystarczy.

Maxim Chetrusca
źródło
11
To wydaje się dość skomplikowane. Dlaczego nie po prostu to nazwać /path/to/script? Nie widzę tu wcale potrzeby exec?
Martin Tournoij
Podpowłoka również nie jest potrzebna, ponieważ nie jesteś execing.
Karel Vlk
6
jak wykonasz ten skrypt z argumentami?
Bhargav
Jeśli chcesz nadal przechwytywać dane wyjściowe skryptu, spróbuj $ (source "ścieżka / do / skryptu")
cmcginty
@Bhargav skorzystaj z tego linku stackoverflow.com/questions/14302389/…
tpbafk
16

Zależy od. W skrócie ... Jeśli chcesz załadować zmienne na bieżącej konsoli i wykonać, możesz użyć source myshellfile.shswojego kodu. Przykład:

!#/bin/bash
set -x
echo "This is an example of run another INTO this session."
source my_lib_of_variables_and_functions.sh
echo "The function internal_function() is defined into my lib."
returned_value=internal_function()
echo $this_is_an_internal_variable

set +x

Jeśli chcesz tylko wykonać plik, a jedyne, co Cię interesuje, to wynik, możesz:

!#/bin/bash
set -x
./executing_only.sh
sh i_can_execute_this_way_too.sh
bash or_this_way.sh
set +x

Mam nadzieję, że ci pomoże. Dzięki.

Douglas Bonafé
źródło
2
Zauważ, że sourcejest to funkcja specyficzna dla bash. Standardowa powłoka Bourne'a ma tylko .(np . other_script.sh.).
Martin Tournoij
15

Możesz użyć /bin/shdo wywołania lub wykonania innego skryptu (za pomocą własnego skryptu):

 # cat showdate.sh
 #!/bin/bash
 echo "Date is: `date`"

 # cat mainscript.sh
 #!/bin/bash
 echo "You are login as: `whoami`"
 echo "`/bin/sh ./showdate.sh`" # exact path for the script file

Dane wyjściowe będą:

 # ./mainscript.sh
 You are login as: root
 Date is: Thu Oct 17 02:56:36 EDT 2013
Ranjithkumar T.
źródło
1
Z pewnością będzie to działało showdate.shpod / bin / sh zamiast / bin / bash?
Chris Watts
próbowałem z „ /bin/sh ./showdate.sh”, „ /bin/bash ./showdate.sh”, „ ./showdate.sh” i uruchomiłem plik: maincript.sh i uzyskałem ten sam wynik.
Ranjithkumar T
10

Po prostu dodaj w linii wszystko, co wpisałeś w terminalu, aby wykonać skrypt!
na przykład:

#!bin/bash
./myscript.sh &

jeśli skrypt, który ma zostać wykonany, nie znajduje się w tym samym katalogu, po prostu użyj pełnej ścieżki skryptu.
np .: `/ home / user / script-directory /./ myscript.sh &

Zaraz
źródło
@Carpetsmoker &dla zadania w tle
Andrei Krasutski
9

Najpierw musisz dołączyć plik, do którego dzwonisz:

#!/bin/bash
. includes/included_file.sh

następnie wywołujesz swoją funkcję w ten sposób:

#!/bin/bash
my_called_function
Ghazi Triki
źródło
9

Proste źródło pomoże ci. Dla np.

#!/bin/bash
echo "My shell_1"
source my_script1.sh
echo "Back in shell_1"
Nitin Jawarkar
źródło
9

Jeśli masz inny plik w tym samym katalogu, możesz albo:

bash another_script.sh

lub

source another_script.sh

lub

. another_script.sh

Gdy używasz bashzamiast source, skrypt nie może zmienić środowiska skryptu nadrzędnego. .Komenda jest standardem POSIX, gdy sourcepolecenie jest bardziej czytelny bash synonimem .(wolę sourceponad .). Jeśli skrypt znajduje się w innym miejscu, podaj ścieżkę do tego skryptu. Powinna działać zarówno ścieżka względna, jak i pełna.

Shital Shah
źródło
5

Najlepsza odpowiedź sugeruje dodanie #!/bin/bashwiersza do pierwszego wiersza wywoływanego skryptu. Ale nawet jeśli dodasz shebang, uruchomienie skryptu w podpowłoce i przechwycenie danych wyjściowych jest znacznie szybsze *

$(source SCRIPT_NAME)

Działa to, gdy chcesz nadal uruchamiać ten sam interpreter (np. Z bash na inny skrypt bash) i zapewnia, że ​​linia shebang skryptu nie zostanie wykonana.

Na przykład:

#!/bin/bash
SUB_SCRIPT=$(mktemp)
echo "#!/bin/bash" > $SUB_SCRIPT
echo 'echo $1' >> $SUB_SCRIPT
chmod +x $SUB_SCRIPT
if [[ $1 == "--source" ]]; then
  for X in $(seq 100); do
    MODE=$(source $SUB_SCRIPT "source on")
  done
else
  for X in $(seq 100); do
    MODE=$($SUB_SCRIPT "source off")
  done
fi
echo $MODE
rm $SUB_SCRIPT

Wynik:

~ ❯❯❯ time ./test.sh
source off
./test.sh  0.15s user 0.16s system 87% cpu 0.360 total

~ ❯❯❯ time ./test.sh --source
source on
./test.sh --source  0.05s user 0.06s system 95% cpu 0.114 total

* Na przykład, gdy na urządzeniu działają narzędzia antywirusowe lub narzędzia zabezpieczające, wykonanie nowego procesu może zająć dodatkowe 100 ms.

cmcginty
źródło
4
pathToShell="/home/praveen/"   
chmod a+x $pathToShell"myShell.sh"
sh $pathToShell"myShell.sh"
Abdennour TOUMI
źródło
4
 #!/bin/bash

 # Here you define the absolute path of your script

 scriptPath="/home/user/pathScript/"

 # Name of your script

 scriptName="myscript.sh"

 # Here you execute your script

 $scriptPath/$scriptName

 # Result of script execution

 result=$?
Valero
źródło
1
niepoprawna scriptPathnazwa folderu lub pliku scriptNameze spacjami
Andrei Krasutski
3

Załóżmy, że nowy plik to „/ home / satya / app / app_specific_env”, a zawartość pliku jest następująca

#!bin/bash

export FAV_NUMBER="2211"

Dołącz to odniesienie do pliku ~ / .bashrc

source /home/satya/app/app_specific_env

Po każdym ponownym uruchomieniu komputera lub ponownym uruchomieniu spróbuj echo $FAV_NUMBERw terminalu. To wyświetli wartość.

Na wszelki wypadek, jeśli chcesz zobaczyć efekt od razu, source ~/.bashrcw wierszu poleceń.

Satya Kalluri
źródło
3
chmod a+x /path/to/file-to-be-executed

To była jedyna rzecz, której potrzebowałem. Gdy skrypt, który ma zostać wykonany, jest wykonywalny w ten sposób, (przynajmniej w moim przypadku) nie potrzebujesz żadnych dodatkowych operacji, takich jak shlub ./podczas wywoływania skryptu.

Dzięki komentarzowi @Nathan Lilienthal

Asqan
źródło
1

Występują problemy z importowaniem funkcji z innego pliku.
Po pierwsze : nie musisz wykonywać tego pliku wykonywalnego. Lepiej tego nie robić! poprostu dodaj

. file

aby zaimportować wszystkie funkcje. Wszystkie będą wyglądały tak, jakby zostały zdefiniowane w twoim pliku.
Po drugie : możesz zdefiniować funkcję o tej samej nazwie. Zostanie nadpisany. To jest złe. Możesz tak zadeklarować

declare -f new_function_name=old_function_name 

i dopiero potem importuj. Możesz więc wywołać starą funkcję pod nową nazwą.
Po trzecie : możesz importować tylko pełną listę funkcji zdefiniowanych w pliku. Jeśli niektóre nie są potrzebne, możesz je rozbroić. Ale jeśli przepiszesz swoje funkcje po rozbrojeniu, zostaną utracone. Ale jeśli ustawisz odniesienie do niego, jak opisano powyżej, możesz przywrócić po rozbrojeniu o tej samej nazwie.
WreszcieWspólna procedura importu jest niebezpieczna i nie taka prosta. Bądź ostrożny! Możesz napisać skrypt, aby zrobić to łatwiej i bezpieczniej. Jeśli używasz tylko części funkcji (nie wszystkich), lepiej podziel je na różne pliki. Niestety ta technika nie sprawdziła się w bashu. Na przykład w Pythonie i niektórych innych językach skryptowych jest to łatwe i bezpieczne. Możliwe jest częściowe importowanie tylko potrzebnych funkcji o własnych nazwach. Wszyscy chcemy, aby w następnych wersjach Busha wykonano tę samą funkcjonalność. Ale teraz musimy napisać wiele dodatkowych dorszy, aby zrobić to, co chcesz.

Anatolij
źródło
(Witamy w SO!) Ponieważ użytkownik Praveen był ostatnio widziany w 2011 roku, z pewnością trudno będzie ustalić, czy chodzi o to, jak sprawić, aby powłoka wykonująca a.sh wykonała b.sh (i kontynuowała wykonywanie a.sh, jeśli nie nakazał inaczej ), albo dosłownie wezwanie B.SH . (Mój moduł sprawdzania pisowni nie łapie bush versions.) (Czy masz kogoś, do kogo możesz się zwrócić, aby pomóc Ci w nauce gramatyki angielskiej? (Czasami chciałbym mieć.))
Greybeard
0

Użyj backticksa.

$ ./script-that-consumes-argument.sh `sh script-that-produces-argument.sh`

Następnie pobierz wynik skryptu producenta jako argument skryptu konsumenta.

dacabdi
źródło