轉:linux中fork, source和exec的差別
shell的指令可以分為内部指令和外部指令. 内部指令是由特殊的檔案格式.def實作的,如cd,ls等.而外部指令是通過系統調用或獨立程式實作的,如awk,sed. source和exec都是内部指令.
fork
使用 fork 方式運作 script 時, 就是讓 shell(parent process) 産生一個 child process 去執行該 script, 當 child process 結束後, 會傳回 parent process,但 parent process 的環境是不會因 child process 的改變而改變的.
source
使用 source 方式運作 script 時, 就是讓 script 在目前 process 内執行, 而不是産生一個 child process 來執行. 由于所有執行結果均于目前 process 内完成,若 script 的環境有所改變, 當然也會改變目前 process 環境了.
source ./my.sh 或 . ./my.sh
exec
使用 exec 方式運作script時, 它和 source 一樣, 也是讓 script 在目前process内執行, 但是 process 内的原代碼剩下部分将被終止. 同樣, process 内的環境随script 改變而改變.
結論:通常如果我們執行時,都是預設為fork的。大家可以通過pstree指令看看關于父子程序的關系。如上,如果想讓父程序得到子程序的環境變量,就是source方式了
* fork ( /directory/script.sh)
fork是最普通的, 就是直接在腳本裡面用/directory/script.sh來調用script.sh這個腳本.運作的時候開一個sub-shell執行調用的腳 本,sub-shell執行的時候, parent-shell還在。sub-shell執行完畢後傳回parent-shell. sub-shell從parent-shell繼承環境變量.但是sub-shell中的環境變量不會帶回parent-shell
* source (source /directory/script.sh)
與fork的差別是不新開一個sub-shell來執行被調用的腳本,而是在同一個shell中執行. 是以被調用的腳本中聲明的變量和環境變量, 都可以在主腳本中得到和使用.
* exec (exec /directory/script.sh)
exec與fork不同,不需要新開一個sub-shell來執行被調用的腳本. 被調用的腳本與父腳本在同一個shell内執行。但是使用exec調用一個新腳本以後, 父腳本中exec行之後的内容就不會再執行了。這是exec和source的差別
exp:
1.sh
代碼:
#!/bin/bash
A=B
echo "PID for 1.sh before exec/source/fork: $$"
export A
echo "1.sh: \$A is $A"
case $1 in
exec)
echo "using exec..."
exec ./2.sh ;;
source)
echo "using source..."
. ./2.sh ;;
*)
echo "using fork by default..."
./2.sh ;;
esac
echo "PID for 1.sh after exec/source/fork: $$"
echo "1.sh: \$A is $A"
2.sh
#!/bin/bash
echo "PID for 2.sh: $$"
echo "2.sh get \$A=$A from 1.sh"
A=C
export A
echo "2.sh: \$A is $A"
然後,分別跑如下參數來觀察結果:
$ ./1.sh fork
$ ./1.sh source
$ ./1.sh exec
#fork下主程序(PID:8523)環境變量為改變,并且子程序(PID:8524)執行完畢後回到主程序
[root@localhost ~]# ./1.sh fork
PID for 1.sh before exec/source/fork:8523
1.sh: $A is B
using fork by default...
PID for 2.sh: 8524
2.sh get $A=B from 1.sh
2.sh: $A is C
PID for 1.sh after exec/source/fork:8523
1.sh: $A is B
#source下程序環境變量改變,1.sh和2.sh的PID均為8530,表明在同一程序下執行
[root@localhost ~]# ./1.sh source
PID for 1.sh before exec/source/fork:8530
1.sh: $A is B
using source...
PID for 2.sh: 8530
2.sh get $A=B from 1.sh
2.sh: $A is C
PID for 1.sh after exec/source/fork:8530
1.sh: $A is C
#exec下環境變量改變;1.sh和2.sh的PID雖然一樣,但是執行2.sh完畢後,并沒有回到原程序中繼續執行剩餘代碼;可見主腳本在調用執行exec之後就退出了,餘下代碼也不會被執行了。
[root@localhost ~]# ./1.sh exec
PID for 1.sh before exec/source/fork:8534
1.sh: $A is B
using exec...
PID for 2.sh: 8534
2.sh get $A=B from 1.sh
2.sh: $A is C
***********************************************************
學習永遠不晚。——高爾基