前言
這是一個經(jīng)常在面試時被問到的一個問題,對于剛剛接觸shell的初學(xué)者來說,確實(shí)不太好搞明白這三者的區(qū)別,下面我通過兩個腳本來幫助你理解它們。
前置知識點(diǎn)
1)我們所執(zhí)行的任何程序,都是由父進(jìn)程(parent process)所產(chǎn)生出來的一個子進(jìn)程(child process),子進(jìn)程在結(jié)束后,將返回到父進(jìn)程去。此現(xiàn)像在Linux系統(tǒng)中被稱為fork。當(dāng)子進(jìn)程被產(chǎn)生的時候,將會從父進(jìn)程那里獲得一定的資源分配、以及繼承父進(jìn)程的環(huán)境( 如環(huán)境變量)。
2)環(huán)境變量大體可以分為三類:
- 內(nèi)置變量:系統(tǒng)提供,不用定義,不能修改,比如$#,$?,$*,$0等
- 環(huán)境變量:系統(tǒng)提供,不用定義,可以修改,當(dāng)前進(jìn)程及其子進(jìn)程中使用,比如PATH,PWD,SHELL等
-
用戶變量(本地變量):用戶定義,可以修改,在當(dāng)前進(jìn)程使用,比如var=123等
3)環(huán)境變量只能從父進(jìn)程到子進(jìn)程單向繼承。換句話說:在子進(jìn)程中的環(huán)境如何變更,均不會影響父進(jìn)程的環(huán)境。
4)先準(zhǔn)備兩個示例腳本:
vi 1.sh ##內(nèi)容如下
#!/bin/bash
A=aminglinux
echo "PID for 1.sh before exec/source/fork:$$"
export A
echo "1.sh: $A is $A"
case $1 in
fork)
echo "using fork"
bash 2.sh
;;
source)
echo "using source"
source 2.sh
;;
exec)
echo "using exec"
exec ./2.sh
;;
*)
echo "using fork"
bash 2.sh
;;
esac
echo "PID for 1.sh after exec/source/fork:$$"
echo"1.sh:$Ais$A"
vi 2.sh ##內(nèi)容如下
#!/bin/bash
echo "PID for 2.sh: $$"
echo "2.sh get $A=$A from 1.sh"
A=ops
export A
echo "2.sh: $A is $A"
給兩個腳本執(zhí)行權(quán)限
chmod +x 1.sh 2.sh
Fork
Fork,字面上就是派生的意思,在當(dāng)前shell中(可以是腳本,也可以是命令行終端)去執(zhí)行一個bash命令,那么就會派生一個sub-shell,也就是所謂的子shell。這個過程就是fork。Fork模式下,子shell會繼承父shell的環(huán)境變量、用戶變量,當(dāng)子shell結(jié)束時,子shell里面產(chǎn)生的環(huán)境變量并不會帶到父shell中。通過執(zhí)行示例腳本,來驗(yàn)證上面的結(jié)論:
bash 1.sh fork
1)1.sh的PID為15242也就是父shell的PID,而2.sh的PID為15243,這個是子shell的PID。2)在1.sh里定義了變量A,值為aminglinux,然后fork了一個子shell去執(zhí)行了2.sh,在2.sh里變量A的值是ops,但是當(dāng)2.sh執(zhí)行完后,再回到1.sh,變量A的值依然是aminglinux。
Source
Source模式下,子shell執(zhí)行時獲取的環(huán)境變量會會影響到父shell。與fork的區(qū)別在于,不會額外打開一個sub-shell來執(zhí)行被調(diào)用的腳本,而是在同一個shell中執(zhí)行。所以,被調(diào)用的腳本中聲明的變量和環(huán)境變量, 都可以在主腳本中得到和使用。
下面來執(zhí)行下示例腳本:
bash 1.sh source
1)無論1.sh還是2.sh,PID都是17164,這說明source并不會開啟sub-shell,而是和父shell使用了同一個進(jìn)程。
2)source 2.sh后,變量A的值變成了ops,而后也被帶到了1.sh里。
Exec
Exec模式下,一旦執(zhí)行了子shell,就不會再去執(zhí)行父shell了。它與fork不同,不需要新開一個sub-shell來執(zhí)行被調(diào)用的腳本,被調(diào)用的腳本與父shell在同一個shell內(nèi)執(zhí)行,這個特性和source一樣。但是使用exec調(diào)用一個新腳本后, 父shell中exec之后的內(nèi)容就不會再執(zhí)行了。
我們來看示例腳本執(zhí)行結(jié)果:
bash 1.sh exec
1)1.sh和2.sh的PID都是18633,這說明exec和source一樣,并不會開啟sub-shell,而是和父shell使用了同一個進(jìn)程。
2)exec調(diào)用完2.sh之后,腳本就結(jié)束了,沒有再繼續(xù),這是exec的特性!
總結(jié)
- source命令: 不創(chuàng)建子進(jìn)程,在當(dāng)前Shell進(jìn)程中執(zhí)行腳本,會將新的環(huán)境變量傳遞到當(dāng)前shell來。
- exec命令: 不創(chuàng)建子進(jìn)程, 在當(dāng)前Shell進(jìn)程中執(zhí)行腳本,父腳本中exec行之后的內(nèi)容不會執(zhí)行。
- fork屬于系統(tǒng)調(diào)用, 會創(chuàng)建一個子進(jìn)程, 父進(jìn)程會阻塞等待子進(jìn)程執(zhí)行結(jié)束, 然后繼續(xù)往下執(zhí)行,子進(jìn)程里的環(huán)境變量不影響父進(jìn)程。
審核編輯 :李倩
-
變量
+關(guān)注
關(guān)注
0文章
613瀏覽量
28408 -
Shell
+關(guān)注
關(guān)注
1文章
366瀏覽量
23412 -
腳本
+關(guān)注
關(guān)注
1文章
391瀏覽量
14889
原文標(biāo)題:通過一個腳本搞懂fork、source和exec
文章出處:【微信號:aming_linux,微信公眾號:阿銘linux】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論