Shell:子shell概念
阿新 • • 發佈:2020-12-10
> Blog:[部落格園](https://www.cnblogs.com/Rohn/) [個人](https://k8sdev.com/)
[toc]
## shell環境
每個shell程序有一個自己的執行環境,不同的Shell程序有不同的Shell環境。Shell解析命令列、呼叫命令列的過程都在這個環境中完成。
呼叫shell程式時,會讀取配置檔案來初始化Shell環境。
讀取配置檔案情況分為兩種:
- 使用者登入啟動的shell
![image-20200722201723821](https://rohn-web.oss-cn-hangzhou.aliyuncs.com/img/blog/image-20200722201723821.png?x-oss-process=style/cnblog)
- 非使用者登入啟動的shell
![image-20200722202245669](https://rohn-web.oss-cn-hangzhou.aliyuncs.com/img/blog/image-20200722202245669.png?x-oss-process=style/cnblog)
## 什麼是子shell
所謂子shell,即從當前shell環境中新開了一個shell環境,這個新開的shell環境就是子shell,而開啟子shell的環境稱為該子shell的父shell。
子Shell的本質可以理解為Shell的子程序,子程序的概念是由父程序的概念引申而來的,在Linux系統中,系統執行的應用程式幾乎都是從`init`(pid為1的程序)程序派生而來的,所有這些應用程式都可以視為init程序的子程序,而`init`則為它們的父程序。通過執行`pstree -a`命令就可以看到`init`及系統中其他程序的程序樹資訊:
```bash
[root@test ~]# pstree -a
systemd --switched-root --system --deserialize 22
├─NetworkManager --no-daemon
│ └─2*[{NetworkManager}]
├─VGAuthService -s
├─agetty --noclear tty1 linux
├─auditd
│ └─{auditd}
├─chronyd
├─crond -n
├─dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation
├─irqbalance --foreground
├─lvmetad -f
├─master -w
│ ├─pickup -l -t unix -u
│ └─qmgr -l -t unix -u
├─polkitd --no-debug
│ └─6*[{polkitd}]
├─rsyslogd -n
│ └─2*[{rsyslogd}]
├─sshd -D
│ └─sshd
│ └─bash
│ └─pstree -a
├─systemd-journal
├─systemd-logind
├─systemd-udevd
├─tuned -Es /usr/sbin/tuned -l -P
│ └─4*[{tuned}]
└─vmtoolsd
└─2*[{vmtoolsd}]
```
> Tips:若無pstree命令,請執行`yum -y install psmisc`安裝。
對於Shell的子程序來說,它是一個從父級Shell程序派生而來的新的Shell程序,我們將這種新的Shell程序稱為這個**父級Shell的子Shell**。
Shell指令碼是從上至下、從左至右依次執行每一行的命令及語句的,即執行完一個命令之後再執行下一個。如果在Shell指令碼中遇到子指令碼(即指令碼巢狀),就會先執行子指令碼的內容,完成後再返回父指令碼繼續執行父指令碼內後續的命令及語句。
子shell會從父shell中繼承很多環境,如變數、命令全路徑、檔案描述符、當前工作目錄、陷阱等等,但子shell有很多種型別,不同型別的子shell繼承的環境不相同。可以使用`$BASH_SUBSHELL`變數來檢視從當前程序開始的子shell層數,`$BASHPID`檢視當前所處BASH的PID,這不同於特殊變數`$$`值,因為`$$`在大多數情況下都會從父shell中繼承。
> 注意:子 Shell 雖然能使用父 Shell 的的一切,但是如果子 Shell 對資料做了修改,比如修改了全域性變數,那麼這種修改只能停留在子 Shell,無法傳遞給父 Shell。不管是子程序還是子 Shell,都是“傳子不傳父”。
## 子shell的分類
大致分為兩類:
- sub shell:通過程序替換`<(cmd),>(cmd)`、命令替換`$(cmd)`、`(cmd)`、`|`或者`$`隱式生成的子shell。因為父shell是通過`fork`建立sub shell,因此子shell會從父shell中繼承很多環境,如變數、命令全路徑、檔案描述符、當前工作目錄、陷阱等等;
- child shell:通過以可執行檔案的方式執行shell指令碼或直接在當前shell中啟動shell直譯器的方式得到的子shell。父shell通過`fork-exec`的方式建立子shell,導致父shell和子shell除了維持“父子關係”外,沒有其他關聯。
> 註釋:使用 fork() 函式可以建立一個子程序;除了 PID(程序ID)等極少的引數不同外,子程序的一切都來自父程序,包括程式碼、資料、堆疊、開啟的檔案等,就連程式碼的執行位置(狀態)都是一