前些天在CU上討論一個統計正在執行的指令碼數量的問題過程中,發現自己對於shell如何執行命令方面瞭解還是甚少,慚愧慚愧...期間得到waker兄的指點,在此表示感謝!他的說法除了個別地方不太準確外,基本上是正確的。這些天抽時間找了些資料研究了一下,又學到了不少!這裡把我的一點心得以問答的形式貼出來,供大家參考。小弟才疏學淺,錯誤的地方一定很多,歡迎大家拍磚、指正!
Q1: shell如何執行“簡單”命令?
A: 這裡的簡單命令和bash參考手冊裡的含義相同,形式上一般是:命令的名稱加上它的參數。有三種不同的簡單命令:
1.內建命令(builtin)
是shell解釋程式內建的,有shell直接執行,不需要派生新的進程。有一些內部命令可以用來改變當前的shell環境,如:
cd /path
var=value
read var
export var
...
2.外部命令("external command" or "disk command")
二進位可執行檔,需要由磁碟裝入記憶體執行。會派生新的進程,shell解釋程式會調用fork自身的一個拷貝,然後用exec系列函數來執行外部命令,然後外部命令就取代了先前fork的子shell。
3.shell指令碼(script)
shell解釋程式會fork+exec執行這個指令碼命令,在exec調用中核心會檢查指令碼的第一行(如:#!/bin/sh),找到用來執行指令碼的解釋程式,然後裝入這個解釋程式,由它解釋執行指令碼程式。解釋程式可能有很多種,各種shell(Bourne shell,Korn shell cshell,rc及其變體ash,dash,bash,zshell,pdksh,tcsh,es...),awk,tcl/tk,expect,perl,python,等等。在此解釋程式顯然是當前shell的子進程。如果這個解釋程式與當前使用的shell是同一種shell,比如都是bash,那麼它就是當前shell的子shell,指令碼中的命令都是在子shell環境中執行的,不會影響當前shell的環境。
Q2: shell指令碼是否作為單獨的一個進程執行?
A: 不是,shell指令碼本身不能作為一個進程。如上面講的,shell指令碼由一個shell解釋程式來解釋、運行其中的命令。這個shell解釋程式是單獨的一個進程,指令碼中的外部命令也都作為獨立進程依次被運行。這也就是為什麼ps不能找到正在啟動並執行指令碼的名字的原因了。作為一個替代方案,你可以這樣呼叫指令碼:
sh script-name
這時shell解釋程式“sh”作為一個外部命令被顯式地調用,而script-name作為該命令的命令列參數可以被我們ps到。
另外,如果你的系統上有pidof命令可用,它倒是可以找出shell指令碼進程(實際上應該是執行shell指令碼的子shell進程)的進程ID:
pidof -x script-name