1. 程式人生 > >在 Shell 指令碼中呼叫另一個 Shell 指令碼的三種方式

在 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

execfork 不同,不需要新開一個子 Shell 來執行被呼叫的指令碼. 被呼叫的指令碼與父指令碼在同一個 Shell 內執行。但是使用 exec 呼叫一個新指令碼以後, 父指令碼中 exec 行之後的內容就不會再執行了。這是 execsource 的區別.

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

fork 方式可以看出,兩個指令碼都執行了,執行順序為1-2-1,從兩者的PID值(1.sh PID=82266, 2.sh PID=82267),可以看出,兩個指令碼是分成兩個程序執行的。

exec

exec

exec 方式執行的結果是,2.sh 執行完成後,不再回到 1.sh。執行順序為 1-2。從pid值看,兩者是在同一程序 PID=82287 中執行的。

source

source

source方式的結果是兩者在同一程序裡執行。該方式相當於把兩個指令碼先合併再執行。

Command Explanation
fork 新開一個子 Shell 執行,子 Shell 可以從父 Shell 繼承環境變數,但是子 Shell 中的環境變數不會帶回給父 Shell。
exec 在同一個 Shell 內執行,但是父指令碼中 exec 行之後的內容就不會再執行了
source 在同一個 Shell 中執行,在被呼叫的指令碼中宣告的變數和環境變數, 都可以在主指令碼中進行獲取和使用,相當於合併兩個指令碼在執行。