『忘了再學』Shell基礎 — 10、Bash中的特殊符號(二)
- 2022 年 4 月 11 日
- 筆記
- 高級測試技能 - Shell基礎
提示:本篇文章接上一篇文章,主要說說
()小括弧和{}大括弧的區別與使用。
8、()小括弧
():用於一串命令執行時,()中的命令會在子Shell中運行。(和下面大括弧一起說明)
9、{}大括弧
{}:用於一串命令執行時,{}中的命令會在當前Shell中執行。也可以用於變數變形與替換。
(1)父Shell和子Shell
在介紹小括弧和大括弧的區別之前,我們先要解釋一個概念,那就是父Shell和子Shell。
用戶登錄到Linux系統後,系統將啟動一個用戶Shell。在這個Shell中,可以使用Shell命令聲明變數,也可以創建並運行Shell腳本程式。運行Shell腳本程式時,系統將創建一個子Shell。此時,系統中將有兩個Shell,一個是登錄時系統啟動的Shell,另一個是系統為運行腳本程式創建的Shell。當一個腳本程式運行完畢,它的腳本Shell將終止,可以返回到執行該腳本之前的Shell。從這種意義上來 說,用戶可以有許多Shell,每個Shell都是由某個Shell(稱為父Shell)派生的。
在Linux系統中的默認Shell是bash,在bash中是可以調用新的bash的。在開啟遠程終端時候所啟動的默認的交互Shell就是父Shell,只需要直接執行bash命令,就會創建一個新的Shell,這個Shell就是子Shell。
執行下面命令:
[root@localhost ~]# bash
我們就開啟一個子Shell。
(2)區分父Shell子Shell
要區分是父Shell還是子Shell,需要使用前面所學的ps命令,查看進程命令來進行判斷。
- 執行
ps -f查看系統進程。

- 執行
bash命令,開啟一個新的Shell,並再次查看系統進程。

可以看到上圖中,第二個進程的父id是第一個進程,所以第二個進程的bash是子Shell。 - 退出子Shell,並再次查看系統進程。

可以看到子Shell進程結束,消失了。
(3)查看父子Shell的關係
我們可以通過pstree命令(查看進程樹),來查看父子Shell的關係。
在Red Hat 6 中,所有的進程都是init進程的子進程。如下圖:

我們可以看到在init進程下,開啟了一個sshd的進程,這個進程就是遠程登陸進程。我們執行過一次遠程登陸sshd,和開啟bash功能,在此bash下執行過一次pstree命令。
在當前Shell中,再執行一邊bash命令,再次執行pstree命令(查看進程樹)。
如下圖:

我們可以從上圖中看到,我在第一個bash下,又開啟了一個新的bash,在新bash中執行了pstree命令。
所以說第一個bash是父(也就是父Shell),第二個bash是子(也就是子Shell)。
(4)父子Shell的關係拓展。
父Shell可以創建子Shell,在子Shell中還可以創建自己的子Shell。
它們的關係如下圖所示:

下面來演示下這個關係圖的Shell創建,和它們之前的關係層次。
下圖中又創建了二個子Shell,總共三個子Shell。依次是子Shell, 孫Shell, 曾孫Shell。

下圖使用ps -f命令,通過PPID列出誰是誰的父進程。

注意:生成子Shell的成本不低,而且速度還慢,創建嵌套的子Shell去處理命令進程性能更為嚴重。
通過輸入exit命令能有條不絮的退出子Shell,例如上面的三個子Shell, 首先從曾孫Shell退出。
如下圖所示:

注意:當沒有了子Shell時,再輸入
exit命令,將退出控制台終端。
(5)小括弧和大括弧的區別
知道了父Shell和子Shell的關係,我們接著解釋小括弧和大括弧的區別。
小括弧和大括弧的主要區別在於,在Shell程式執行的時候,小括弧或者大括弧中的內容是在父Shell執行還是在子Shell中執行。
下面我們總結一下小括弧和大括弧的主要區別:
()中執行一串命令時,需要重新開一個子Shell進行執行。
在當前Shell中name=ss,當執行到()中命令的時候,會自動開啟一個子Shell,在子Shell中name的變數賦予了mm,當()中命令運行完,子Shell進程就結束了,進程消失。裡邊的變數都不會保存,並自動返回到父Shell中,也就是回歸到當前Shell,name的值還是原來Shell中賦予的ss值。
示例如下:#在父Shell中定義變數name的值是ss [root@localhost ~]# name=ss #如果用()括起來一串命令,這些命令都可以執行。 #給name變數重新賦值,但是這個值只在子Shell中生效 [root@localhost ~]#(name=mm;echo $name) mm #父Shell中name的值還是ss,而不是mm [root@localhost ~]# echo $name ss{ }中執行一串命令時,是在當前Shell執行。#用大括弧來進行串命令的執行時 #name變數的修改是直接在父Shell當中的 #注意大括弧的格式 [root@localhost ~]# { name=mm;echo $name; } mm #所以name變數的值已經被修改了 [root@localhost ~]# echo $name mm就相當於直接在當前Shell執行
{}中的語句,那麼不寫{}的結果是一樣的。()和{}都是把一串的命令放在括弧裡面,並且命令之間用;號隔開。()最後一個命令可以不用分號結尾。[root@localhost ~]# ( name=lm; echo $name ){}中最後一個命令要用分號結尾。[root@localhost ~]# { 空格 name=lm; echo $name; }{}中的第一個命令和左括弧之間必須要有一個空格。[root@localhost ~]# { 空格 name=lm; echo $name; }()里的各命令不必和括弧有空格。()和{}中,括弧裡面的某個命令的重定向隻影響該命令,但括弧外的重定向則影響到括弧里的所有命令。
說明:小括弧和大括弧不太好理解,用的也不是太多,能看懂即可,工作中用不用在你自己。
10、[]中括弧
[]:用於變數的測試。(之後詳解講解)





