認識命令行:Shell 類型、命令差異 | Sub Shell 關係 | Builtin 命令

認識命令行:Shell 類型、命令差異 | Sub Shell 關係 | Builtin 命令

Overview of Content

探索命令行界面,從基礎入門到高級應用,了解各種 Shell 類型、命令的差異以及多 Shell 關係(Shell and sub shell),我們分為以下小節來介紹

  • 進入/認識命令行:深入探索控制台終端和圖形介面終端,讓您全面了解命令行的入口和使用方式
  • Shell 類型:辨別並介紹常見的 Shell 類型,幫助您選擇最適合自己需求的 Shell
  • 命令的差異:分析內建命令和外部命令的差異,並探討它們的使用場景和效果
  • 多Shell關係:更進階的瞭解 Sub Shell (子Shell) 的概念,掌握進程列表、前後景執行和創建 Sub Shell 的技巧
  • Builtin Shell 應用:探索內建命令的應用,包括歷史命令和命令別名,提高命令行操作效率

個人程式分享時比較注重「縮排」,所以可能不適合手機的排版閱讀,建議切換至「電腦版」、「平板版」視窗看 😀

寫文章分享不易,如有引用參考請詳註出處,如有指導、意見歡迎留言(如果覺得寫得好也請給我一些支持),感謝 😀


認識命令行 CLI

在 Linux 四大組件的圖型化桌面出現之前,要與系統通訊的手段就只有 Shell 命令行 (CLI, Command line interface),命令行大多是文本或是簡單的圖形

控制台終端

● 進入控制台終端 CLI 的方式是一種讓 Linux 系統「退出圖型化桌面」模式,進入文本模式的模式(在 CLI 模式下只會有簡單的文本,沒有圖形介面);這種模式也稱為 控制台終端

● Linux 發行版中,在系統啟動時就會啟動 5~6 個虛擬控制台

虛擬控制台終端是沒有 GUI(out the GUI) 的 CLI 終端(控制台終端)

● 那 啞終端 是什麼?

沒有 GUI 系統,只有簡單的通訊線、螢幕、鍵盤連接到 Unix 系統上,並與其通訊,透過下指令 & 查看輸出結果來達到目的

所以控制台中端可以算是啞終端的一種形式

● Linux 系統在啟動時會創建多個 Linux 控制台終端,之後就會自動幫我們切換到圖形化終端介面(GUI CLI)

graph TB 系統啟動 --> 控制台終端 --> 圖形化終端 subgraph 控制台終端 vc1(虛擬控制台 1) vc2(虛擬控制台 2) vc3(虛擬控制台 3) vc4(虛擬控制台 4) vc5(虛擬控制台 5) end

A. 通常要切換回控制台終端可以用以下快捷鍵

Ctrl + Alt + F1~F7(要試試看,在其中一個)

tty 是啥

螢幕上見到的關鍵字 tty 代表的是 teletypewriter (電傳打字機) ,但不是每個 Linux 發行版上都會在登入介面上顯示虛擬控制台 tty 號

這 Unix 設備中看到的tty/*pts/*tty 都是終端設備,這種設備就是典型的 非硬體設備,是透過記憶體模擬出來的設備

就是軟體模擬出來的假設備(假硬體)

B. 在圖形界面終端也可以透過指令來,進入文字模式的控制台,指令如下


## sudo chvt <終端台>

## 開啟一號控制台終端
sudo chvt 1  

控制台終端 getty & login

getty 是一個 Linux 系統中的程序,它是一種用於終端的登錄程序。它通常在 Linux 系統啟動時被初始化,並負責為每個終端設備提供登錄界面

"getty" 是 "get tty" 的縮寫,它接受用戶的用戶名和密碼,並驗證登錄憑據

● 它的主要作用是與終端設備進行通信,並提供用戶登錄的功能。一旦用戶成功登錄,getty 會將用戶的登錄會話交給 shell 進程處理

getty 是為控制台終端(純終端)服務,還是為圖形化終端服務?

getty 是為控制台終端(純終端)服務,並在控制台中呼叫 login 程式,登入成功後才呼叫 Shell

在 Linux 系統中,getty 通常與其他程序(如 init 或 systemd)一起使用,以提供完整的登錄和會話管理功能

圖形介面終端

● 透過 Linux 圖形化界面也可以進入終端;這種模式稱為 終端仿真包(模擬控制台終端);終端仿真包只是 Linux 圖形化介面其中一個元素

圖形化終端由以下解個重點部分組成

圖形化角色常見的產品簡介
客戶端(GUI Client)圖形化終端仿真、桌面環境、遊覽器請求圖型化服務的應用
顯示服務器(GUI Server)Mir、Wayland Compositor、Xserver負責管理顯示、輸入設備(鍵盤滑鼠觸控... 等等)
窗口管理器Compiz、Metacity、Kwin為每個窗口建立邊框、拖曳... 等等基本功能
部件Athenal(Xaw)、X Intrinsics客戶端添加菜單 & 外部功能

● 圖形化終端仿真器:in the GUI 的 CLI 終端(圖形化終端)

Ubuntu 圖形化終端介面 (下圖黑色視窗)

Shell 類型

不同種類型的 Shell 會有不同特色(或是使用限制、規範)

在腳本中會宣告在最前面(#! 符號,又稱為 shenang),用來說明該腳本要使用哪個 Shell 解釋

常見的 Shell 解釋器

● 透過 /etc/passwd 可以知道每一個用戶的 shell 類型,不同的用戶類型可能會使用不同的 Shell 解釋器(別的小節會說明),而常見的 Shell 解釋器就是 bash

當然,除了 bash 之外,還有另外幾種常見的 bash,如下表所示

Shell 類型特性補充
Bourne shellUnix 版本的 Shell-
bash shellGNU 模仿 Bourne shell 的產品,這是最常見的 Shell (默認 Shell)-
ash運行在內存受限的輕量級 Shell (與 bash shell 相容)Debian 版本
korn支持浮點數、高級編程特性 (與 Bourne shell 相容)-
tcsh擁有 C 語言特性的 ShellCentOS 使用,來源於最初的 C shell;CentOS 中是軟連結,連接 tcsh
zsh結合多個 Shell 特性(bash shell, korn, tcsh...)-

進一步認識 Shell

shell 的意思是命令行界面(也可以理解為 shell 是執行命令行的應用程式)

Unix 系統中有很多重要的部份其實都是 shell 腳本

● Unix 中的 Shell 有為很多種,它們都是 基於 Bourne shell (/bin/sh),這是貝爾實驗室開發的標準 Shell

● Linux 常用的則是 Bourne again shell,也就是 Bash shell

你的帳戶使用哪個 Shell?

● 查看 /etc/passwd 文件,並找到自己的帳戶名稱,查看最後一個欄位,該欄位就是這個帳戶預設使用的 Shell


tail /etc/passwd

查看 Bash 指令:man 手冊 / info / help

man 指令用來查看 Linux 系統上的手冊,其格式如下


## 格式 man <command>

## 查看 man 這個指令的操作手冊
man man

按下 q 就會退出說明手冊

man 手冊的 DESCRIPTION 部份是很好的介紹,使用新指令時最好讀一下

man 指令常用 options

options說明
-k使用關鍵字找尋對應指令

## 查看 hostname 相關指令

man -k hostname

可以看到列出的列表中,後面有一個括號,中間對應的數字代表了這個命令在 man 手冊中的哪個位置(區);不同數字可以概述該指令的是屬於哪個部份的功能,區對應的號碼、功能如下表所示

區域號說明
1可執行程式 or shell
2系統調用
3Library 調用
4特殊文件
5文件格式與約定
6遊戲
7概覽、約定與雜項
8超級用戶、系統管理員命令
9內核歷程

## 進入區號 5 的說明

man 5 hostname

● 其他兩個 info, help 指令也可以拿來查看指令的操作


## info <指令>
info hostname

## <指令> --help
hostname --help

● 並非每一個命令都會有 maninfohelp 功能,需要查詢的時候可以都試試看

認識指令錯誤訊息

● 當指令出錯時,Shell 會回覆一個「錯誤訊息」,而這個些錯訊息也保含了重要資訊;以下是一個標準錯誤訊息


# 錯誤訊息

ls: cannot access /qq123: No such file or directory

錯誤訊息以 : 符號個別分開,說明如下表所示

錯誤訊息說明說明
ls錯誤命令ls 這個指令執行時發生錯誤
cannot access /qq123檔案路徑無法訪問 /qq123 這個檔案
No such file or directory具體錯誤訊息沒有這個檔案或是資料夾

「警告訊息」、「錯誤訊息」一樣嗎

「警告訊息」、「錯誤訊息」是兩種不同的訊息;出現警告訊息程式仍可運作(只是提示你哪裡出現問題),但出現錯誤訊息時指令就會停止

● 其中常見的具體錯誤訊息如下表

錯誤訊息說明補充
No such file or directory存取不存在的檔案或目錄Unix I/O 系統對檔案、目錄不做區分
File exists創建檔案或目錄,但已有相同名稱的存在-
Not a directory, Is a directory錯把目錄當成檔案來存取操作-
No space left on device硬碟空間不存-
Permission denied權限錯誤-
Operation not permitted當我們試圖中止一個無權中止的程序時-
Segmentation fault, Bus error程式嘗試存取無權存取的記憶體空間時,系統會中止該操作Segmentation fault 程式異常、Bus error 代表存取記憶體有問題

Shell 標準輸入輸出

● Unix 程序使用 I/O 資料流來讀寫資料,輸入流可以是從檔案、設備、終端... 等等來源,而 輸出流也可以將數據輸出到檔案、設備、終端... 等目的

標準輸入(Standard input

可以透過 cat 命令來測試,輸入 cat 命令後(並不指定讀取檔案),它就會讀取使用者的資料數據輸入,這樣 cat 命令就變成了標準輸入

標準輸出(Standard output

核心會為每個應用程序提供一個標準輸出流,讓他們輸出資料(並不一定會輸出到螢幕上,也可以輸出到裝置、文件)

命令的差異:內、外命令

內建、外部命令的操作方式不同,可以透過 type 判斷命令是內部還是外部的

builtin 內建命令:直接啟動

● 內建命令 不需要 啟動子進程就可以運行內建命令,我們同樣可以使用 type 命令去判斷指定的命令是否是內建命令(內建命令會顯示 builtin


type cd 

type exit

● 命令可能會重複(內部、外部使用同一個命令),這時就可以使用 type -a <命令>


## 查看所有的 echo 命令

type -a echo

如果需要指定某個命令,那就需要寫出那個命令的具體位置;(eg. /bin/pwd)

外部命令:另外啟動

● 外部命令在執行時會 產生一個「新的子進程」去運行外部命令,這個行為稱為 forking,透過複製當前進程來執行新命令


## 當前進程啟動另一個子進程
## 子進程運行 `ps -f

ps -f

從下圖中,我們可以看到執行 ps -f 命令後 PID 為 171809,與本來 Bash 的 PID 不同(原來 Bash 的 PID 為 169156

graph LR b1(Bash 169156) --> |複製進程| forking --> b2(Bash 171809) --> |執行命令| ps(ps -f) ps -.-> |進程結束| b1

● 外部命令也被稱為 文件系統命令(存於 bash shell 之外的命令),外部命令通常放至於 bin/usr/binsbin/usr/sbin 資料夾中

外部令令可以透過 which(外部命令)、type(內部命令)命令 找到對應位置


which ps 

type ps

多 shell 關係:Shell & Sub shell

在使用 Shell 時會有父子概念(也可以想成階層概念),不同的階層會有可以相互訪問、資料是否可共享的特性,對於學習 Shell 時也是相當重要的概念

啟動子 shell:Sub shell

● 你可以透過一個已經啟動的 shell,在內部在啟動另外一個 shell,這個啟動的 shell 就是父子關係,概念圖如下

graph TB subgraph 父Shell 子Shell end

## 啟動新 shell(子)
shell

## 查看當前用戶啟動的進程
ps -f

父子 shell 的 PID 就不同 (可以透過 ps 命令查看)

上圖的父子 Shell 關係如下 (進程 ID 是 PID,其父進程 ID 就是 PPID)

● 可以透過 ps --forest 命令看到簡單的父子關係「圖形、階層輸出」;--forest 選項並非每個 Shell 都有,可以透過 man ps 查看

進程列表:create sub shell

● 進程列表是一種 命令分組(command grouping,透過將命令 使用括號 () 包裹來達到讓括號內的命令運行在另一個子進程 (sub process)

A. 一般下達命令:一行中下達多個命令,預設每個外部指令都會 fork 啟動,但 不會啟動一個 sub shell 運行

一般下達命令範例如下


## 在一行中下達多個命令,**命令之間使用 `;` 區分**

ps -f ; ls ; pwd ; ps -f

下圖中,對應到上面要執行的指令,這些指令會 forking PID 14002 shell

graph LR Shell 命令 --> |forking| Shell

B. 進程列表下達命令:使用括號 () 啟動 sub shell,運行括號內的命令

進程列表下達命令令範例如下


(ps -f ; ls ; pwd ; ps -f)

下圖中,對應到範例括號內的命令,會 forking PID 14066 sub shell,也就是說指令 forking 的來源是 sub shell,而不是原來的 Shell

graph LR subgraph 父Shell 子Shell end 命令 --> |forking| 子Shell

● 另一種命令分組是使用花括號 {} + ; 配合使用,但這種方式就 不會 啟動一個 sub shell (子 Shell),格式如下


{ command; }

操控 Shell 前後景執行:jobs 使用

啟動背景命令

命令功能
fg [%n]切換 Shell 到前景;n 是任務編號
bg [%n]切換 Shell 到背景(ctrl + z 是掛起、休眠,兩者功能不同);n 是任務編號
jobs查看所有背景任務

A. 啟動 Shell 背景命令:一般 Shell 切換到背景,只需要在命令的後面 & 即可


sleep 10 &

ps -f

切換到背景後會返回一串數字,那些數字就是切換到背景運作的 Shell 的 PID

B. 查看背景 Shell:使用 jobs 命令就可以查看到任務編號,之後可以透過這個編號讓指定任務運行在前景或是背景


jobs 

## 列出 PID
jobs -l

reference link

C. 切換前後景:切換 sleep 任務到背景,再切換到前景


sleep 100

## 接著按 `ctrl` + `Z` 掛起

## 切換到背景運行
bg %1

## 查任所有任務
jobs

## 切換到前景運行
fg %1

判斷 SubShell

● Ubuntu 中可以 使用 BASH_SUBSHELL 關鍵字 (變量) 來判端當前 Shell 是否是子Shell(Sub Shell)

A. 無 subshell 的狀況下會回應 0,代表頂層 Shell


echo $BASH_SUBSHELL

B. 透過進程列表創建 sub shell


($echo BASH_SUBSHELL ; sleep 100 ; )&

如下圖,我們看到使用進程列表(小擴號 () 符號)並打印 BASH_SUBSHELL 變量,就可以看到當前的 Sub shell 階層

創建 SubShell:協程 coproc

● 除了使用進程列表之外,也可以 透過 coproc 命令將接下來要下達的命令切換到 sub shell


coproc sleep 100

ps 

ps -l

coproc 命令的另一個特點在於,可以對 sub shell 設定指定名稱,這可以讓你的 Shell 更有可讀性;格式如下

coproc <名稱> { [指令] ; }

範例如下:以下啟動一個名為 MyJob 的協程,在使用 jobs 命令查看


corproc MyJob { sleep 100 ; }

jobs -l

如下圖,我們可以看到 Sub shell 的名稱確實顯示 MyJob


Builtin Shell 應用

歷史命令 History

history 可以查看下達 Shell 命令的歷史


history | tail

history 額外命令說明
!!執行上一個命令
!<命令編號>執行指定歷史命令
history -a對 .bash_history 寫入命令(命令不會立刻被寫入,所以必須透過 -a 命令去強至寫入)

.bash_history 會儲存用戶輸入的所有命令


cat .bash_history | tail

命令別名 alias

● 有時候命令太常會不方便記憶,這時我們就可以使用 alias 來對命令簡化(別名)


## 取別名
lll='ls -laF'

## 下達命令
lll

格式:<別名>=<原命令>

別名的功能只存在於當前 Shell 中,另起一個 Shell 就無法使用已經設定好的別名

● 可以透過 alias -p 查看所有可使用的別名


alias -p


更多 Linux Shell 知識

探索 Debian 系統上的套件管理系統(PKMS 概念)| 套件倉庫

Linux 環境、服務:用戶、權限管理

Linux 環境、服務、管理

在這個主題中,你可以探索各種 Linux 環境、服務和管理相關的重要概念…

了解 Linux 組成:內核責任、GNU 工具、桌面環境 | 基礎版到發行版

在這裡,你將了解 Linux 系統的基本組成部分,包括內核、GNU 工具和桌面環境,並了解不同 Linux 發行版之間的差異

探索 X Window 服務與桌面環境:Linux 視窗 XWindow 服務、D-Bus 機制

這裡探討了 Linux 系統中 X Window 服務和 D-Bus 機制的工作原理,讓你深入了解桌面環境的背後運作方式

Linux 系統管理入門:安全性、用戶管理與權限設定指南

在這個指南中,你將學習如何管理 Linux 系統,包括安全性、用戶管理和權限設定,以確保系統的安全和有效運作

認識身份驗證與權限管理:UNIX UID、使用者驗證與 PAM | PAM 設定

這裡介紹了 UNIX 系統中的身份驗證機制和權限管理方式,包括 UNIX UID、使用者驗證和 PAM(Pluggable Authentication Modules)設定

Linux Shell 相關知識

Linux Shell 相關知識

這個主題涵蓋了各種與 Linux Shell 相關的知識,從基礎到進階都有…

Shell 基礎知識:包括 Shell 的基礎使用以及差異,還有變數以及計算

認識命令行:Shell 類型、命令差異 | Sub Shell 關係 | Builtin 命令

這裡介紹了命令行中不同類型的 Shell,以及各種 Shell 命令之間的區別和內建命令的用法

Shell 全局及區域變數、特殊變數及環境變數 | Shell 啟動順序 | Array 變數

學習如何在 Shell 中使用全局變數、特殊變數和環境變數,以及如何設置和管理這些變數

探索腳本與命令:Shell 腳本的必備相關知識 | 腳本的數學運算

這裡介紹了 Shell 腳本的基本知識和常用技巧,包括如何執行腳本和進行數學運算

Shell 結構化

Shell 腳本程式中的條件語句和高級特性 | Shell 結構化 & 判斷

該篇文章是介紹結構化腳本的基礎以及特殊的高級技巧,轉著於腳本中的邏輯判斷

掌握 Bash 腳本中的迴圈與循環控制技巧 | Shell 結構化 & 循環

接著是腳本中的循環與控制的技巧,它可以讓我們在 Shell 腳本中有更多的判斷與技巧

探索 Shell 函數與腳本庫 | Shell 結構化 & 函數

這裡你將會學在到結構化腳本的重要技巧「函數」,它可以讓你建立可重複利用的腳本,以節省我們之後開發的時間

Shell 掌握參數處理與用戶輸入技巧 | Shell 結構化 &輸入互動

不可互動的腳本有時候相對無趣,這篇文章有分享如何讓腳本與使用者產生交互互動,並依照使用者輸入的參數做讀取

Shell script 進階

Shell 命令輸入與輸出指南:掌握標準文件描述符與重定向 | 臨時文件

掌控 Shell、指令的輸出輸入是成為進階使用 CLI 之人必經的一課,透過這篇文章可以了解到輸出輸入、臨時文件等等資訊

探索 Linux 訊號與後台進程管理:安排定期啟動腳本 | 運行時啟動腳本

信號可以算是 Shell 腳本與 Linux 系統之間的通訊方式,透過這個文章,我們可以了解到信號與 Shell 腳本的安排時間

Linux 硬體規劃:檔案系統、分區

Linux 硬體規劃:檔案系統、分區

最後,這個主題涵蓋了 Linux 系統中硬體結構相關的重要概念…

Shell 文件和目錄操作的常用命令和技巧 | 尋找檔案

這裡介紹了 Shell 中常用的文件和目錄操作命令,包括如何尋找文件和管理文件系統

深入探索 Linux 文件系統與硬體管理 | 分區、檔案系統、邏輯卷 | inode

學習如何管理 Linux 文件系統,包括分區、文件系統和邏輯卷等相關概念,以及文件系統中的 inode 機制

理解 Unix/Linux 設備偵測、建立 | 認識與使用 udevd | SCSI 與 Linux 核心

這裡介紹了 Unix/Linux 系統中的設備偵測和管理,包括如何使用 udevd 和 SCSI 相關的 Linux 核心知識


Leave a Comment

Comments

No comments yet. Why don’t you start the discussion?

發表迴響