Linux 命令行與 shell 腳本編程大全 5 理解 shell

了解子 shell 和 父 shell 之間的關(guān)系以及一些命令

更多精彩

5.1 shell 的類型

  1. Linux 中,用戶使用的 shell 類型,被配置在 /etc/passwd 文件中,通常都是 bash shell
  2. 除了 bash shell ,CentOS 中一般還內(nèi)置了 tcsh shell 、dash shell 、ash shell、tcsh shell
  3. 查看當(dāng)前系統(tǒng)是否內(nèi)置了上述 shell 類型,可以通過如下方式
    • 可以看到,在下圖的 CentOS 環(huán)境中,只存在 bash shelldash shell
  4. 但在 macOS 環(huán)境中,除了 ash shell 沒有內(nèi)置,其他的幾種類型都可以找到

5.1.1 默認(rèn)的系統(tǒng) shell

  1. 在用戶配置文件與用戶綁定的 shell 會(huì)在系統(tǒng)啟動(dòng)時(shí)運(yùn)行
  2. 但除了啟動(dòng)用戶 shell 之外,還會(huì)啟動(dòng)一個(gè)系統(tǒng) shell ,通常被指定為 /bin/sh ,如下圖
    • 但是可以看到,/bin/sh 只是 bash shell 的軟鏈接
    • 不過不是所有的系統(tǒng)的默認(rèn)系統(tǒng) shell 都指向 bash shell ,Ubuntu 通常會(huì)指向 dash shell

5.2 shell 的父子關(guān)系

  1. 父 shell 是指用于登錄系統(tǒng)的默認(rèn) shell
  2. 子 shell 則是在 父 shell 環(huán)境中創(chuàng)建的其他 shell
  3. 使用 bash 命令可以在 父 shell 中創(chuàng)建 子 shell ,如下圖
    • ps -f 命令第一次執(zhí)行時(shí),只能獲取兩條進(jìn)程信息,-bash 則是當(dāng)前的 父 shell
    • 在執(zhí)行 bash 命令后,再次執(zhí)行 ps -f 命令則獲取到了三條進(jìn)程信息,bash 則是剛才通過執(zhí)行 bash 命令創(chuàng)建的 子 shell
    • bash 進(jìn)程的 PPID 和 -bash 進(jìn)程的 PID 一致,說明后者是前者的父級
  4. bash 命令提供了一些指令,如下圖
  5. 使用 exit 退出當(dāng)前 shell ,如下圖
    • 使用 bash 創(chuàng)建一個(gè) 子 shell
    • 執(zhí)行 exit ,再次執(zhí)行 ps -f ,之前創(chuàng)建的 子 shell 進(jìn)程就不存在了
  6. 子 shell 并不是真正的多進(jìn)程處理,層級過多的 子 shell 會(huì)帶來更多的系統(tǒng)花銷,拖慢處理速度

5.2.1 進(jìn)程列表

  1. 在介紹 進(jìn)程列表 之前,需要先了解 命令列表
  2. 命令列表 是在多個(gè)命令之間通過分號分隔,讓一行中的命令可以依次執(zhí)行,如下圖
    • 可以看到,命令被依次執(zhí)行并輸出了結(jié)果


  3. 命令列表 想要進(jìn)化成 進(jìn)程列表 ,只需要在這些命令兩側(cè)加上括號即可,如下圖

5.2.1.1 命令列表和進(jìn)程列表的區(qū)別

  1. 那么你可能會(huì)問,只是加了括號,但輸出結(jié)果一致,這兩個(gè)列表的區(qū)別在哪
  2. 區(qū)別在于:命令列表 是直接執(zhí)行這些命令串
  3. 進(jìn)程列表 會(huì)創(chuàng)建一個(gè) 子 shell 開執(zhí)行這些命令,執(zhí)行完畢后 子 shell 也會(huì)隨之結(jié)束
  4. 使用 echo $BASH_SUBSHELL 命令可以更清晰的知道命令在執(zhí)行時(shí),是否存在 子 shell ,如下圖
    • 如果不存在,會(huì)返回 0 ,否則就是存在
    • 返回?cái)?shù)字的表達(dá)意思是 進(jìn)程列表 的嵌套層級

5.2.2 別出心裁的子 shell 用法

5.2.2.1 & 命令探索后臺(tái)模式

  1. 在后臺(tái)模式中執(zhí)行命令可以在處理命令的同時(shí)讓出 CLI ,以供他用
  2. 在待執(zhí)行命令的末尾添加字符 & ,可以讓該命令在后臺(tái)執(zhí)行,如下圖
    • sleep 5 命令表示當(dāng)前線程會(huì)等待 5 秒,如果直接執(zhí)行,當(dāng)前命令行會(huì)在 5 秒后才能繼續(xù)接收輸入
    • sleep 5 & 命令執(zhí)行后則會(huì)立即返回一個(gè)后臺(tái)任務(wù) ID ,以及該進(jìn)程的 PID ,當(dāng)前命令行也可以立即接收新的輸入
    • 需要注意的是 macOS 在命令執(zhí)行完畢后,會(huì)自動(dòng)輸出執(zhí)行結(jié)果,如下圖
    • 但 CentOS 不會(huì)自動(dòng)輸出執(zhí)行結(jié)果,需要再次執(zhí)行 jobs 命令,才可以看到執(zhí)行結(jié)果

5.2.2.2 jobs 命令查看后臺(tái)進(jìn)程

  1. 使用 jobs 命令可以顯示當(dāng)前運(yùn)行在后臺(tái)模式中的所有用戶的進(jìn)程信息
  2. 使用 jobs -l 則可以更詳細(xì)的顯示進(jìn)程信息,如下圖
    • jobs 命令會(huì)顯示后臺(tái)進(jìn)程的任務(wù) ID 、PID 、進(jìn)程狀態(tài)、進(jìn)程命令
    • 同時(shí)當(dāng)后臺(tái)進(jìn)程執(zhí)行完畢后,也就無法通過 jobs 查看對應(yīng)進(jìn)程信息

5.2.2.3 將進(jìn)程列表置入后臺(tái)

  1. 進(jìn)程列表 置入后臺(tái)運(yùn)行的好處在于:既可以在子 shell 中執(zhí)行復(fù)雜的處理工作,又不會(huì)占用當(dāng)前的 shell 窗口 ,如下圖

5.2.2.4 coproc 命令實(shí)現(xiàn)協(xié)程

  1. 協(xié)程 是指在后臺(tái)生成一個(gè) 子 shell ,并在這個(gè) 子 shell 中執(zhí)行命令
  2. 使用 coproc 命令可以實(shí)現(xiàn)協(xié)程,如下圖
    • 可以看到,使用 jobs 命令查看到的進(jìn)程命令名稱最后有一個(gè) & 符號,說明這也是一個(gè)后臺(tái)進(jìn)程
  3. 上圖中大寫的 COPROC 是在使用 coproc 命令時(shí)指定的默認(rèn)協(xié)程名稱
  4. 這個(gè)名稱是可以自定義的,如下圖
    • 完整的語法是 coproc coprocName { command; }
    • 命令中的花括號、空格、分號缺一不可,語法格式非常嚴(yán)格


5.3 理解 shell 的內(nèi)建命令

5.3.1 外部命令

  1. Linux 中存在 內(nèi)建命令外部命令 ,可以先理解一下 外部命令
  2. 外部命令 也被稱為 文件系統(tǒng)命令 ,不是 shell 程序的一部分
  3. 外部命令 通常被放置在 /bin 、/usr/bin 、/sbin 、/usr/sbin
  4. 外部命令 在執(zhí)行時(shí),會(huì)創(chuàng)建一個(gè)子進(jìn)程,在子進(jìn)程中執(zhí)行該命令,這個(gè)行為被稱為 衍生( Forking )

5.3.1.1 which 命令和 type 命令查看命令歸屬

  1. 使用 which 命令和 type 命令可以查看指定命令是屬于 外部命令 ,還是 內(nèi)建命令 ,如下圖
    • ps 命令位于 /bin 中,說明 ps 命令就是 外部命令

5.3.2 內(nèi)建命令

  1. 內(nèi)建命令外部命令 的區(qū)別在于,內(nèi)建命令 不需要使用子進(jìn)程來執(zhí)行命令
  2. 內(nèi)建命令 和 shell 是一體的,作為 shell 工具的組成部分而存在
  3. 內(nèi)建命令 因?yàn)椴恍枰ㄟ^衍生行為來執(zhí)行,所以執(zhí)行速度會(huì)更快、效率更高
  4. 使用 which 命令和 type 命令也可以查看該命令是否屬于 內(nèi)建命令 ,如下圖
    • 可以看到,cd exit pwd 命令都屬于 內(nèi)建命令

5.3.2.1 type -a 命令查看命令的多種實(shí)現(xiàn)

  1. 有些命令存在多種實(shí)現(xiàn),使用 type -a 可以將該命令的全部實(shí)現(xiàn)列舉出來,如下圖
    • 可以看到,pwd echo 命令既是 內(nèi)建命令 ,也在 /bin 目錄中有一份實(shí)現(xiàn)

5.3.2.2 history 命令查看使用過的歷史命令

  1. 首先 history 命令是一個(gè) 內(nèi)建命令
  2. 可以通過 history 命令查看之前使用過的命令,如下圖
    • 在 CentOS 中,history 命令默認(rèn)最多可以存儲(chǔ) 1000 條歷史命令,但這個(gè)值可以通過 HISTSIZE 的環(huán)境變量進(jìn)行修改
    • 下圖中只列出了 6 條數(shù)據(jù),是因?yàn)闉榱朔奖泔@示,使用 history -c 命令刪除了之前的所有歷史數(shù)據(jù)

5.3.2.3 !! 命令直接執(zhí)行最近一條歷史命令

  1. 使用 !! 命令可以直接在新的一行顯示出上一條剛剛執(zhí)行過的命令,如下圖
    • !! 命令執(zhí)行之后,在下一行出現(xiàn)的 pwd 命令不是手動(dòng)輸入的,而是由 !! 命令呼出的
    • 呼出的命名不會(huì)直接執(zhí)行,只是顯示出來,需要手動(dòng)按回車鍵,才能再次執(zhí)行該命令


5.3.2.4 在 .bash_history 文件中查看命令歷史記錄

  1. 使用 history 命令查看的命令歷史記錄,被存放在根目錄的 .bash_history 文件中
  2. 需要注意的是,命令的歷史記錄并不是直接存放到該文件,而是先存放到內(nèi)存中,當(dāng) shell 退出時(shí),才被寫入到該文件
  3. 想要強(qiáng)制將命令歷史記錄寫入文件中,可以使用 history -a 命令

5.3.2.5 alias 命令實(shí)現(xiàn)為命令指定別名

  1. alias 命令也是一個(gè) 內(nèi)建命令
  2. 需要注意的是,直接使用命令創(chuàng)建的別名,只能在當(dāng)前會(huì)話生效,無法做到全局生效
    • 想要全局生效,則需要將別名寫入配置文件中,后續(xù)章節(jié)會(huì)有介紹
  3. 使用 alias 命令可以為某個(gè)復(fù)雜的命令指定一個(gè)簡單的別名,從而將調(diào)用命令的輸入減少到最低,如下圖
    • 可以看到,通過 alias 命令將 ls -al 命令指向 ll 命令
    • 之后再輸出 ll 命令,就可以得到和 ls -al 命令一樣的結(jié)果

5.3.2.6 alias -p 命令查看當(dāng)前有多少命令別名

  1. 使用 alias -p 命令可以列出當(dāng)前系統(tǒng)中存在哪些命令別名可以使用,如下圖
  2. 上圖是 CentOS 的效果,如果是 macOS ,無法使用 alias -p 命令,直接使用 alias 命令,不加任何后綴即可

5.4 小結(jié)

  1. shell 之間存在父子級關(guān)系
  2. 使用 bash 命令可以創(chuàng)建 子 shell
  3. 使用 exit 命令可以退出 子 shell
  4. 使用 & 命令可以將命令置入后臺(tái)
  5. 使用 coproc 命令可以在子進(jìn)程中執(zhí)行命令
  6. 命令列表 是指在多個(gè)命令之間添加分號,可以依次執(zhí)行命令
  7. 進(jìn)程列表 是指在 命令列表 外部添加一對括號,可以將這些命令在子進(jìn)程中執(zhí)行
  8. 使用 history 命令可以查看命令歷史記錄
  9. 使用 !! 命令可以快速呼出最近依次的命令歷史記錄
  10. 使用 alias 命令可以給長命令指定短別名
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容