在 Shell 指令碼中呼叫另一個 Shell 指令碼的三種方式
先來說一下主要以下有幾種方式:
- fork: 如果指令碼有執行許可權的話,
path/to/foo.sh
。如果沒有,sh path/to/foo.sh
。 - exec:
exec path/to/foo.sh
- source:
source path/to/foo.sh
fork
fork
是最普通的, 就是直接在腳本里面用 path/to/foo.sh
來呼叫
foo.sh 這個指令碼,比如如果是 foo.sh 在當前目錄下,就是 ./foo.sh
。執行的時候 terminal 會新開一個子 Shell 執行指令碼 foo.sh,子 Shell 執行的時候, 父 Shell 還在。子 Shell 執行完畢後返回父 Shell。 子 Shell 從父 Shell 繼承環境變數,但是子 Shell 中的環境變數不會帶回父 Shell。
exec
exec
與 fork
不同,不需要新開一個子 Shell 來執行被呼叫的指令碼. 被呼叫的指令碼與父指令碼在同一個 Shell 內執行。但是使用 exec
呼叫一個新指令碼以後, 父指令碼中 exec
行之後的內容就不會再執行了。這是 exec
和 source
的區別.
source
與 fork
的區別是不新開一個子 Shell 來執行被呼叫的指令碼,而是在同一個 Shell 中執行. 所以被呼叫的指令碼中宣告的變數和環境變數, 都可以在主指令碼中進行獲取和使用。
其實從命名上可以感知到其中的細微區別,下面通過兩個指令碼來體會三種呼叫方式的不同:
第一個指令碼,我們命名為 1.sh
#!/usr/bin/env bash
A=1
echo "before exec/source/fork: PID for 1.sh = $$"
export A
echo "In 1.sh: variable A=$A"
case $1 in
--exec)
echo -e "==> using exec…\n"
exec ./2.sh ;;
--source)
echo -e "==> using source…\n"
. ./2 .sh ;;
*)
echo -e "==> using fork by default…\n"
./2.sh ;;
esac
echo "after exec/source/fork: PID for 1.sh = $$"
echo -e "In 1.sh: variable A=$A\n"
第二個指令碼,我們命名為 2.sh
:
#!/usr/bin/env bash
echo "PID for 2.sh = $$"
echo "In 2.sh get variable A=$A from 1.sh"
A=2
export A
echo -e "In 2.sh: variable A=$A\n"
注:這兩個指令碼中的引數 $$
用於返回指令碼的 PID , 也就是程序 ID。這個例子是想通過顯示 PID 判斷兩個指令碼是分開執行還是同一程序裡執行,也就是是否有新開子 Shell。當執行完指令碼 2.sh
後,指令碼 1.sh
後面的內容是否還執行。
chmod +x 1.sh 2.sh
給兩個指令碼加上可執行許可權後執行情況:
fork
fork
方式可以看出,兩個指令碼都執行了,執行順序為1-2-1,從兩者的PID值(1.sh PID=82266, 2.sh PID=82267),可以看出,兩個指令碼是分成兩個程序執行的。
exec
exec
方式執行的結果是,2.sh 執行完成後,不再回到 1.sh。執行順序為 1-2。從pid值看,兩者是在同一程序 PID=82287 中執行的。
source
source方式的結果是兩者在同一程序裡執行。該方式相當於把兩個指令碼先合併再執行。
Command | Explanation |
---|---|
fork | 新開一個子 Shell 執行,子 Shell 可以從父 Shell 繼承環境變數,但是子 Shell 中的環境變數不會帶回給父 Shell。 |
exec | 在同一個 Shell 內執行,但是父指令碼中 exec 行之後的內容就不會再執行了 |
source | 在同一個 Shell 中執行,在被呼叫的指令碼中宣告的變數和環境變數, 都可以在主指令碼中進行獲取和使用,相當於合併兩個指令碼在執行。 |