『忘了再學』Shell基礎 — 10、Bash中的特殊符號(二)

繁華似錦Fighting發表於2022-04-11

提示:本篇文章接上一篇文章,主要說說()小括號和{}大括號的區別與使用。

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檢視系統程式。
    image
  • 執行bash命令,開啟一個新的Shell,並再次檢視系統程式。
    image
    可以看到上圖中,第二個程式的父id是第一個程式,所以第二個程式的bash是子Shell。
  • 退出子Shell,並再次檢視系統程式。
    image
    可以看到子Shell程式結束,消失了。

(3)檢視父子Shell的關係

我們可以通過pstree命令(檢視程式樹),來檢視父子Shell的關係。

在Red Hat 6 中,所有的程式都是init程式的子程式。如下圖:

image

我們可以看到在init程式下,開啟了一個sshd的程式,這個程式就是遠端登陸程式。我們執行過一次遠端登陸sshd,和開啟bash功能,在此bash下執行過一次pstree命令。

在當前Shell中,再執行一邊bash命令,再次執行pstree命令(檢視程式樹)。
如下圖:

image

我們可以從上圖中看到,我在第一個bash下,又開啟了一個新的bash,在新bash中執行了pstree命令。

所以說第一個bash是父(也就是父Shell),第二個bash是子(也就是子Shell)。

(4)父子Shell的關係擴充。

父Shell可以建立子Shell,在子Shell中還可以建立自己的子Shell。

它們的關係如下圖所示:

image

下面來演示下這個關係圖的Shell建立,和它們之前的關係層次。

下圖中又建立了二個子Shell,總共三個子Shell。依次是子Shell, 孫Shell, 曾孫Shell。

image

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

image

注意:生成子Shell的成本不低,而且速度還慢,建立巢狀的子Shell去處理命令程式效能更為嚴重。

通過輸入exit命令能有條不絮的退出子Shell,例如上面的三個子Shell, 首先從曾孫Shell退出。
如下圖所示:

image

注意:當沒有了子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、[]中括號

[]:用於變數的測試。(之後詳解講解)

相關文章