1. 程式人生 > >Linux 從入門到了解

Linux 從入門到了解

一、常用操作以及概念

快捷鍵

  • Tab:命令和檔名補全;
  • Ctrl+C:中斷正在執行的程式;
  • Ctrl+D:結束鍵盤輸入(End Of File,EOF)

求助

1. --help

指令的基本用法與選項介紹。

2. man

man 是 manual 的縮寫,將指令的具體資訊顯示出來。

當執行man date時,有 DATE(1) 出現,其中的數字代表指令的型別,常用的數字及其型別如下:

代號 型別
1 使用者在 shell 環境中可以操作的指令或者可執行檔案
5 配置檔案
8 系統管理員可以使用的管理指令

3. info

info 與 man 類似,但是 info 將文件分成一個個頁面,每個頁面可以進行跳轉。

4. doc

/usr/share/doc 存放著軟體的一整套說明檔案。

關機

1. who

在關機前需要先使用 who 命令檢視有沒有其它使用者線上。

2. sync

為了加快對磁碟檔案的讀寫速度,位於記憶體中的檔案資料不會立即同步到磁碟上,因此關機之前需要先進行 sync 同步操作。

3. shutdown

# shutdown [-krhc] 時間 [資訊]
-k : 不會關機,只是傳送警告資訊,通知所有線上的使用者
-r : 將系統的服務停掉後就重新啟動
-h : 將系統的服務停掉後就立即關機
-c : 取消已經在進行的 shutdown 指令內容

PATH

可以在環境變數 PATH 中宣告可執行檔案的路徑,路徑之間用 : 分隔。

/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/dmtsai/.local/bin:/home/dmtsai/bin

sudo

sudo 允許一般使用者使用 root 可執行的命令,不過只有在 /etc/sudoers 配置檔案中新增的使用者才能使用該指令。

包管理工具

RPM 和 DPKG 為最常見的兩類軟體包管理工具:

  • RPM 全稱為 Redhat Package Manager,最早由 Red Hat 公司制定實施,隨後被 GNU 開源作業系統接受併成為很多 Linux 系統 (RHEL) 的既定軟體標準。
  • 與 RPM 進行競爭的是基於 Debian 作業系統 (Ubuntu) 的 DEB 軟體包管理工具 DPKG,全稱為 Debian Package,功能方面與 RPM 相似。

YUM 基於 RPM,具有依賴管理功能,並具有軟體升級的功能。

發行版

Linux 發行版是 Linux 核心及各種應用軟體的整合版本。

基於的包管理工具 商業發行版 社群發行版
RPM Red Hat Fedora / CentOS
DPKG Ubuntu Debian

VIM 三個模式

  • 一般指令模式(Command mode):VIM 的預設模式,可以用於移動遊標檢視內容;
  • 編輯模式(Insert mode):按下 “i” 等按鍵之後進入,可以對文字進行編輯;
  • 指令列模式(Bottom-line mode):按下 “:” 按鍵之後進入,用於儲存退出等操作。

在指令列模式下,有以下命令用於離開或者儲存檔案。

命令 作用
:w 寫入磁碟
:w! 當檔案為只讀時,強制寫入磁碟。到底能不能寫入,與使用者對該檔案的許可權有關
:q 離開
:q! 強制離開不儲存
:wq 寫入磁碟後離開
:wq! 強制寫入磁碟後離開

GNU

GNU 計劃,譯為革奴計劃,它的目標是建立一套完全自由的作業系統,稱為 GNU,其內容軟體完全以 GPL 方式釋出。其中 GPL 全稱為 GNU 通用公共許可協議,包含了以下內容:

  • 以任何目的執行此程式的自由;
  • 再複製的自由;
  • 改進此程式,並公開發布改進的自由。

開源協議

二、磁碟

磁碟介面

1. IDE

IDE(ATA)全稱 Advanced Technology Attachment,介面速度最大為 133MB/s,因為並口線的抗干擾性太差,且排線佔用空間較大,不利電腦內部散熱,已逐漸被 SATA 所取代。

2. SATA

SATA 全稱 Serial ATA,也就是使用串列埠的 ATA 介面,抗干擾性強,且對資料線的長度要求比 ATA 低很多,支援熱插拔等功能。SATA-II 的介面速度為 300MiB/s,而新的 SATA-III 標準可達到 600MiB/s 的傳輸速度。SATA 的資料線也比 ATA 的細得多,有利於機箱內的空氣流通,整理線材也比較方便。

3. SCSI

SCSI 全稱是 Small Computer System Interface(小型機系統介面),經歷多代的發展,從早期的 SCSI-II 到目前的 Ultra320 SCSI 以及 Fiber-Channel(光纖通道),介面型式也多種多樣。SCSI 硬碟廣為工作站級個人電腦以及伺服器所使用,因此會使用較為先進的技術,如碟片轉速 15000rpm 的高轉速,且傳輸時 CPU 佔用率較低,但是單價也比相同容量的 ATA 及 SATA 硬碟更加昂貴。

4. SAS

SAS(Serial Attached SCSI)是新一代的 SCSI 技術,和 SATA 硬碟相同,都是採取序列式技術以獲得更高的傳輸速度,可達到 6Gb/s。此外也透過縮小連線線改善系統內部空間等。

磁碟的檔名

Linux 中每個硬體都被當做一個檔案,包括磁碟。磁碟以磁碟介面型別進行命名,常見磁碟的檔名如下:

  • IDE 磁碟:/dev/hd[a-d]
  • SATA/SCSI/SAS 磁碟:/dev/sd[a-p]

其中檔名後面的序號的確定與系統檢測到磁碟的順序有關,而與磁碟所插入的插槽位置無關。

三、分割槽

分割槽表

磁碟分割槽表主要有兩種格式,一種是限制較多的 MBR 分割槽表,一種是較新且限制較少的 GPT 分割槽表。

1. MBR

MBR 中,第一個扇區最重要,裡面有主要開機記錄(Master boot record, MBR)及分割槽表(partition table),其中主要開機記錄佔 446 bytes,分割槽表佔 64 bytes。

分割槽表只有 64 bytes,最多隻能儲存 4 個分割槽,這 4 個分割槽為主分割槽(Primary)和擴充套件分割槽(Extended)。其中擴充套件分割槽只有一個,它使用其它扇區用記錄額外的分割槽表,因此通過擴充套件分割槽可以分出更多分割槽,這些分割槽稱為邏輯分割槽。

Linux 也把分割槽當成檔案,分割槽檔案的命名方式為:磁碟檔名 + 編號,例如 /dev/sda1。注意,邏輯分割槽的編號從 5 開始。

2. GPT

不同的磁碟有不同的扇區大小,例如 512 bytes 和最新磁碟的 4 k。GPT 為了相容所有磁碟,在定義扇區上使用邏輯區塊地址(Logical Block Address, LBA),LBA 預設大小為 512 bytes。

GPT 第 1 個區塊記錄了主要開機記錄(MBR),緊接著是 33 個區塊記錄分割槽資訊,並把最後的 33 個區塊用於對分割槽資訊進行備份。這 33 個區塊第一個為 GPT 表頭紀錄,這個部份紀錄了分割槽表本身的位置與大小和備份分割槽的位置,同時放置了分割槽表的校驗碼 (CRC32),作業系統可以根據這個校驗碼來判斷 GPT 是否正確。若有錯誤,可以使用備份分割槽進行恢復。

GPT 沒有擴充套件分割槽概念,都是主分割槽,每個 LAB 可以分 4 個分割槽,因此總共可以分 4 * 32 = 128 個分割槽。

MBR 不支援 2.2 TB 以上的硬碟,GPT 則最多支援到 233 TB = 8 ZB。

開機檢測程式

1. BIOS

BIOS(Basic Input/Output System,基本輸入輸出系統),它是一個韌體(嵌入在硬體中的軟體),BIOS 程式存放在斷電後內容不會丟失的只讀記憶體中。

BIOS 是開機的時候計算機執行的第一個程式,這個程式知道可以開機的磁碟,並讀取磁碟第一個扇區的主要開機記錄(MBR),由主要開機記錄(MBR)執行其中的開機管理程式,這個開機管理程式會載入作業系統的核心檔案。

主要開機記錄(MBR)中的開機管理程式提供以下功能:選單、載入核心檔案以及轉交其它開機管理程式。轉交這個功能可以用來實現了多重引導,只需要將另一個作業系統的開機管理程式安裝在其它分割槽的啟動扇區上,在啟動開機管理程式時,就可以通過選單選擇啟動當前的作業系統或者轉交給其它開機管理程式從而啟動另一個作業系統。

下圖中,第一扇區的主要開機記錄(MBR)中的開機管理程式提供了兩個選單:M1、M2,M1 指向了 Windows 作業系統,而 M2 指向其它分割槽的啟動扇區,裡面包含了另外一個開機管理程式,提供了一個指向 Linux 的選單。

安裝多重引導,最好先安裝 Windows 再安裝 Linux。因為安裝 Windows 時會覆蓋掉主要開機記錄(MBR),而 Linux 可以選擇將開機管理程式安裝在主要開機記錄(MBR)或者其它分割槽的啟動扇區,並且可以設定開機管理程式的選單。

2. UEFI

BIOS 不可以讀取 GPT 分割槽表,而 UEFI 可以。

四、檔案系統

分割槽與檔案系統

對分割槽進行格式化是為了在分割槽上建立檔案系統。一個分割槽通常只能格式化為一個檔案系統,但是磁碟陣列等技術可以將一個分割槽格式化為多個檔案系統。

組成

最主要的幾個組成部分如下:

  • inode:一個檔案佔用一個 inode,記錄檔案的屬性,同時記錄此檔案的內容所在的 block 編號;
  • block:記錄檔案的內容,檔案太大時,會佔用多個 block。

除此之外還包括:

  • superblock:記錄檔案系統的整體資訊,包括 inode 和 block 的總量、使用量、剩餘量,以及檔案系統的格式與相關資訊等;
  • block bitmap:記錄 block 是否被使用的位域。

檔案讀取

對於 Ext2 檔案系統,當要讀取一個檔案的內容時,先在 inode 中去查詢檔案內容所在的所有 block,然後把所有 block 的內容讀出來。

而對於 FAT 檔案系統,它沒有 inode,每個 block 中儲存著下一個 block 的編號。

磁碟碎片

指一個檔案內容所在的 block 過於分散。

block

在 Ext2 檔案系統中所支援的 block 大小有 1K,2K 及 4K 三種,不同的大小限制了單個檔案和檔案系統的最大大小。

大小 1KB 2KB 4KB
最大單一檔案 16GB 256GB 2TB
最大檔案系統 2TB 8TB 16TB

一個 block 只能被一個檔案所使用,未使用的部分直接浪費了。因此如果需要儲存大量的小檔案,那麼最好選用比較小的 block。

inode

inode 具體包含以下資訊:

  • 許可權 (read/write/excute);
  • 擁有者與群組 (owner/group);
  • 容量;
  • 建立或狀態改變的時間 (ctime);
  • 最近一次的讀取時間 (atime);
  • 最近修改的時間 (mtime);
  • 定義檔案特性的旗標 (flag),如 SetUID…;
  • 該檔案真正內容的指向 (pointer)。

inode 具有以下特點:

  • 每個 inode 大小均固定為 128 bytes (新的 ext4 與 xfs 可設定到 256 bytes);
  • 每個檔案都僅會佔用一個 inode。

inode 中記錄了檔案內容所在的 block 編號,但是每個 block 非常小,一個大檔案隨便都需要幾十萬的 block。而一個 inode 大小有限,無法直接引用這麼多 block 編號。因此引入了間接、雙間接、三間接引用。間接引用是指,讓 inode 記錄的引用 block 塊記錄引用資訊。

目錄

建立一個目錄時,會分配一個 inode 與至少一個 block。block 記錄的內容是目錄下所有檔案的 inode 編號以及檔名。

可以看出檔案的 inode 本身不記錄檔名,檔名記錄在目錄中,因此新增檔案、刪除檔案、更改檔名這些操作與目錄的 w 許可權有關。

日誌

如果突然斷電,那麼檔案系統會發生錯誤,例如斷電前只修改了 block bitmap,而還沒有將資料真正寫入 block 中。

ext3/ext4 檔案系統引入了日誌功能,可以利用日誌來修復檔案系統。

掛載

掛載利用目錄作為檔案系統的進入點,也就是說,進入目錄之後就可以讀取檔案系統的資料。

目錄配置

為了使不同 Linux 發行版本的目錄結構保持一致性,Filesystem Hierarchy Standard (FHS) 規定了 Linux 的目錄結構。最基礎的三個目錄如下:

  • / (root, 根目錄)
  • /usr (unix software resource):所有系統預設軟體都會安裝到這個目錄;
  • /var (variable):存放系統或程式執行過程中的資料檔案。

五、檔案

檔案屬性

使用者分為三種:檔案擁有者、群組以及其它人,對不同的使用者有不同的檔案許可權。

使用 ls 檢視一個檔案時,會顯示一個檔案的資訊,例如 drwxr-xr-x. 3 root root 17 May 6 00:14 .config,對這個資訊的解釋如下:

  • drwxr-xr-x:檔案型別以及許可權,第 1 位為檔案型別欄位,後 9 位為檔案許可權欄位
  • 3:連結數
  • root:檔案擁有者
  • root:所屬群組
  • 17:檔案大小
  • May 6 00:14:檔案最後被修改的時間
  • .config:檔名

常見的檔案型別及其含義有:

  • d:目錄
  • -:檔案
  • l:連結檔案

9 位的檔案許可權欄位中,每 3 個為一組,共 3 組,每一組分別代表對檔案擁有者、所屬群組以及其它人的檔案許可權。一組許可權中的 3 位分別為 r、w、x 許可權,表示可讀、可寫、可執行。

檔案時間有以下三種:

  • modification time (mtime):檔案的內容更新就會更新;
  • status time (ctime):檔案的狀態(許可權、屬性)更新就會更新;
  • access time (atime):讀取檔案時就會更新。

檔案與目錄的基本操作

1. ls

列出檔案或者目錄的資訊,目錄的資訊就是其中包含的檔案。

# ls [-aAdfFhilnrRSt] file|dir
-a :列出全部的檔案
-d :僅列出目錄本身
-l :以長資料序列列出,包含檔案的屬性與許可權等等資料

2. cd

更換當前目錄。

cd [相對路徑或絕對路徑]

3. mkdir

建立目錄。

# mkdir [-mp] 目錄名稱
-m :配置目錄許可權
-p :遞迴建立目錄

4. rmdir

刪除目錄,目錄必須為空。

rmdir [-p] 目錄名稱
-p :遞迴刪除目錄

5. touch

更新檔案時間或者建立新檔案。

# touch [-acdmt] filename
-a : 更新 atime
-c : 更新 ctime,若該檔案不存在則不建立新檔案
-m : 更新 mtime
-d : 後面可以接更新日期而不使用當前日期,也可以使用 --date="日期或時間"
-t : 後面可以接更新時間而不使用當前時間,格式為[YYYYMMDDhhmm]

6. cp

複製檔案。

如果原始檔有兩個以上,則目的檔案一定要是目錄才行。

cp [-adfilprsu] source destination
-a :相當於 -dr --preserve=all 的意思,至於 dr 請參考下列說明
-d :若來原始檔為連結檔案,則複製連結檔案屬性而非檔案本身
-i :若目標檔案已經存在時,在覆蓋前會先詢問
-p :連同檔案的屬性一起復制過去
-r :遞迴持續複製
-u :destination 比 source 舊才更新 destination,或 destination 不存在的情況下才複製
--preserve=all :除了 -p 的許可權相關引數外,還加入 SELinux 的屬性, links, xattr 等也複製了

7. rm

刪除檔案。

# rm [-fir] 檔案或目錄
-r :遞迴刪除

8. mv

移動檔案。

# mv [-fiu] source destination
# mv [options] source1 source2 source3 .... directory
-f : force 強制的意思,如果目標檔案已經存在,不會詢問而直接覆蓋

修改許可權

可以將一組許可權用數字來表示,此時一組許可權的 3 個位當做二進位制數字的位,從左到右每個位的權值為 4、2、1,即每個許可權對應的數字權值為 r : 4、w : 2、x : 1。

# chmod [-R] xyz dirname/filename

示例:將 .bashrc 檔案的許可權修改為 -rwxr-xr–。

# chmod 754 .bashrc

也可以使用符號來設定許可權。

# chmod [ugoa]  [+-=] [rwx] dirname/filename
- u:擁有者
- g:所屬群組
- o:其他人
- a:所有人
- +:新增許可權
- -:移除許可權
- =:設定許可權

示例:為 .bashrc 檔案的所有使用者新增寫許可權。

# chmod a+w .bashrc

檔案預設許可權

  • 檔案預設許可權:檔案預設沒有可執行許可權,因此為 666,也就是 -rw-rw-rw- 。
  • 目錄預設許可權:目錄必須要能夠進入,也就是必須擁有可執行許可權,因此為 777 ,也就是 drwxrwxrwx。

可以通過 umask 設定或者檢視檔案的預設許可權,通常以掩碼的形式來表示,例如 002 表示其它使用者的許可權去除了一個 2 的許可權,也就是寫許可權,因此建立新檔案時預設的許可權為 -rw-rw-r–。

目錄的許可權

檔名不是儲存在一個檔案的內容中,而是儲存在一個檔案所在的目錄中。因此,擁有檔案的 w 許可權並不能對檔名進行修改。

目錄儲存檔案列表,一個目錄的許可權也就是對其檔案列表的許可權。因此,目錄的 r 許可權表示可以讀取檔案列表;w 許可權表示可以修改檔案列表,具體來說,就是新增刪除檔案,對檔名進行修改;x 許可權可以讓該目錄成為工作目錄,x 許可權是 r 和 w 許可權的基礎,如果不能使一個目錄成為工作目錄,也就沒辦法讀取檔案列表以及對檔案列表進行修改了。

連結

# ln [-sf] source_filename dist_filename
-s :預設是 hard link,加 -s 為 symbolic link
-f :如果目標檔案存在時,先刪除目標檔案

1. 實體連結

在目錄下建立一個條目,記錄著檔名與 inode 編號,這個 inode 就是原始檔的 inode。

刪除任意一個條目,檔案還是存在,只要引用數量不為 0。

有以下限制:不能跨越檔案系統、不能對目錄進行連結。

# ln /etc/crontab .
# ll -i /etc/crontab crontab
34474855 -rw-r--r--. 2 root root 451 Jun 10 2014 crontab
34474855 -rw-r--r--. 2 root root 451 Jun 10 2014 /etc/crontab

2. 符號連結

符號連結檔案儲存著原始檔所在的絕對路徑,在讀取時會定位到原始檔上,可以理解為 Windows 的快捷方式。

當原始檔被刪除了,連結檔案就打不開了。

可以為目錄建立連結。

# ll -i /etc/crontab /root/crontab2
34474855 -rw-r--r--. 2 root root 451 Jun 10 2014 /etc/crontab
53745909 lrwxrwxrwx. 1 root root 12 Jun 23 22:31 /root/crontab2 -> /etc/crontab

獲取檔案內容

1. cat

取得檔案內容。

# cat [-AbEnTv] filename
-n :打印出行號,連同空白行也會有行號,-b 不會

2. tac

是 cat 的反向操作,從最後一行開始列印。

3. more

和 cat 不同的是它可以一頁一頁檢視檔案內容,比較適合大檔案的檢視。

4. less

和 more 類似,但是多了一個向前翻頁的功能。

5. head

取得檔案前幾行。

# head [-n number] filename
-n :後面接數字,代表顯示幾行的意思

6. tail

是 head 的反向操作,只是取得是後幾行。

7. od

以字元或者十六進位制的形式顯示二進位制檔案。

指令與檔案搜尋

1. which

指令搜尋。

# which [-a] command
-a :將所有指令列出,而不是隻列第一個

2. whereis

檔案搜尋。速度比較快,因為它只搜尋幾個特定的目錄。

# whereis [-bmsu] dirname/filename

3. locate

檔案搜尋。可以用關鍵字或者正則表示式進行搜尋。

locate 使用 /var/lib/mlocate/ 這個資料庫來進行搜尋,它儲存在記憶體中,並且每天更新一次,所以無法用 locate 搜尋新建的檔案。可以使用 updatedb 來立即更新資料庫。

# locate [-ir] keyword
-r:正則表示式

4. find

檔案搜尋。可以使用檔案的屬性和許可權進行搜尋。

# find [basedir] [option]
example: find . -name "shadow*"

① 與時間有關的選項

-mtime  n :列出在 n 天前的那一天修改過內容的檔案
-mtime +n :列出在 n 天之前 (不含 n 天本身) 修改過內容的檔案
-mtime -n :列出在 n 天之內 (含 n 天本身) 修改過內容的檔案
-newer file : 列出比 file 更新的檔案

+4、4 和 -4 的指示的時間範圍如下:

② 與檔案擁有者和所屬群組有關的選項

-uid n
-gid n
-user name
-group name
-nouser :搜尋擁有者不存在 /etc/passwd 的檔案
-nogroup:搜尋所屬群組不存在於 /etc/group 的檔案

③ 與檔案許可權和名稱有關的選項

-name filename
-size [+-]SIZE:搜尋比 SIZE 還要大 (+) 或小 (-) 的檔案。這個 SIZE 的規格有:c: 代表 byte,k: 代表 1024bytes。所以,要找比 50KB 還要大的檔案,就是 -size +50k
-type TYPE
-perm mode  :搜尋許可權等於 mode 的檔案
-perm -mode :搜尋許可權包含 mode 的檔案
-perm /mode :搜尋許可權包含任一 mode 的檔案

六、壓縮與打包

壓縮檔名

Linux 底下有很多壓縮檔名,常見的如下:

副檔名 壓縮程式
*.Z compress
*.zip zip
*.gz gzip
*.bz2 bzip2
*.xz xz
*.tar tar 程式打包的資料,沒有經過壓縮
*.tar.gz tar 程式打包的檔案,經過 gzip 的壓縮
*.tar.bz2 tar 程式打包的檔案,經過 bzip2 的壓縮
*.tar.xz tar 程式打包的檔案,經過 xz 的壓縮

壓縮指令

1. gzip

gzip 是 Linux 使用最廣的壓縮指令,可以解開 compress、zip 與 gzip 所壓縮的檔案。

經過 gzip 壓縮過,原始檔就不存在了。

有 9 個不同的壓縮等級可以使用。

可以使用 zcat、zmore、zless 來讀取壓縮檔案的內容。

$ gzip [-cdtv#] filename
-c :將壓縮的資料輸出到螢幕上
-d :解壓縮
-t :檢驗壓縮檔案是否出錯
-v :顯示壓縮比等資訊
-# : # 為數字的意思,代表壓縮等級,數字越大壓縮比越高,預設為 6

2. bzip2

提供比 gzip 更高的壓縮比。

檢視命令:bzcat、bzmore、bzless、bzgrep。

$ bzip2 [-cdkzv#] filename
-k :保留原始檔

3. xz

提供比 bzip2 更佳的壓縮比。

可以看到,gzip、bzip2、xz 的壓縮比不斷優化。不過要注意的是,壓縮比越高,壓縮的時間也越長。

檢視命令:xzcat、xzmore、xzless、xzgrep。

$ xz [-dtlkc#] filename

打包

壓縮指令只能對一個檔案進行壓縮,而打包能夠將多個檔案打包成一個大檔案。tar 不僅可以用於打包,也可以使用 gip、bzip2、xz 將打包檔案進行壓縮。

$ tar [-z|-j|-J] [cv] [-f 新建的 tar 檔案] filename...  ==打包壓縮
$ tar [-z|-j|-J] [tv] [-f 已有的 tar 檔案]              ==檢視
$ tar [-z|-j|-J] [xv] [-f 已有的 tar 檔案] [-C 目錄]    ==解壓縮
-z :使用 zip;
-j :使用 bzip2;
-J :使用 xz;
-c :新建打包檔案;
-t :檢視打包檔案裡面有哪些檔案;
-x :解打包或解壓縮的功能;
-v :在壓縮/解壓縮的過程中,顯示正在處理的檔名;
-f : filename:要處理的檔案;
-C 目錄 : 在特定目錄解壓縮。
使用方式 命令
打包壓縮 tar -jcv -f filename.tar.bz2 要被壓縮的檔案或目錄名稱
查 看 tar -jtv -f filename.tar.bz2
解壓縮 tar -jxv -f filename.tar.bz2 -C 要解壓縮的目錄

七、Bash

可以通過 Shell 請求核心提供服務,Bash 正是 Shell 的一種。

特性

  • 命令歷史:記錄使用過的命令
  • 命令與檔案補全:快捷鍵:tab
  • 命名別名:例如 lm 是 ls -al 的別名
  • shell scripts
  • 萬用字元:例如 ls -l /usr/bin/X* 列出 /usr/bin 下面所有以 X 開頭的檔案

變數操作

對一個變數賦值直接使用 =。

對變數取用需要在變數前加上 $ ,也可以用 ${} 的形式;

輸出變數使用 echo 命令。

$ x=abc
$ echo $x
$ echo ${x}

變數內容如果有空格,必須使用雙引號或者單引號。

  • 雙引號內的特殊字元可以保留原本特性,例如 x=“lang is $LANG”,則 x 的值為 lang is zh_TW.UTF-8;
  • 單引號內的特殊字元就是特殊字元本身,例如 x=‘lang is $LANG’,則 x 的值為 lang is $LANG。

可以使用 `指令` 或者 $(指令) 的方式將指令的執行結果賦值給變數。例如 version=$(uname -r),則 version 的值為 4.15.0-22-generic。

可以使用 export 命令將自定義變數轉成環境變數,環境變數可以在子程式中使用,所謂子程式就是由當前 Bash 而產生的子 Bash。

Bash 的變數可以宣告為陣列和整數數字。注意數字型別沒有浮點數。如果不進行宣告,預設是字串型別。變數的宣告使用 declare 命令:

$ declare [-aixr] variable
-a : 定義為陣列型別
-i : 定義為整數型別
-x : 定義為環境變數
-r : 定義為 readonly 型別

使用 [ ] 來對陣列進行索引操作:

$ array[1]=a
$ array[2]=b
$ echo ${array[1]}

指令搜尋順序

  • 以絕對或相對路徑來執行指令,例如 /bin/ls 或者 ./ls ;
  • 由別名找到該指令來執行;
  • 由 Bash 內建的指令來執行;
  • 按 $PATH 變數指定的搜尋路徑的順序找到第一個指令來執行。

資料流重定向

重定向指的是使用檔案代替標準輸入、標準輸出和標準錯誤輸出。

1 程式碼 運算子
標準輸入 (stdin) 0 < 或 <<
標準輸出 (stdout) 1 > 或 >>
標準錯誤輸出 (stderr) 2 2> 或 2>>

其中,有一個箭頭的表示以覆蓋的方式重定向,而有兩個箭頭的表示以追加的方式重定向。

可以將不需要的標準輸出以及標準錯誤輸出重定向到 /dev/null,相當於扔進垃圾箱。

如果需要將標準輸出以及標準錯誤輸出同時重定向到一個檔案,需要將某個輸出轉換為另一個輸出,例如 2>&1 表示將標準錯誤輸出轉換為標準輸出。

$ find /home -name .bashrc > list 2>&1

八、管道指令

管道是將一個命令的標準輸出作為另一個命令的標準輸入,在資料需要經過多個步驟的處理之後才能得到我們想要的內容時就可以使用管道。

在命令之間使用 | 分隔各個管道命令。

$ ls -al /etc | less

提取指令

cut 對資料進行切分,取出想要的部分。

切分過程一行一行地進行。

$ cut
-d :分隔符
-f :經過 -d 分隔後,使用 -f n 取出第 n 個區間
-c :以字元為單位取出區間

示例 1:last 顯示登入者的資訊,取出使用者名稱。

$ last
root pts/1 192.168.201.101 Sat Feb 7 12:35 still logged in
root pts/1 192.168.201.101 Fri Feb 6 12:13 - 18:46 (06:33)
root pts/1 192.168.201.254 Thu Feb 5 22:37 - 23:53 (01:16)

$ last | cut -d ' ' -f 1

示例 2:將 export 輸出的資訊,取出第 12 字元以後的所有字串。

$ export
declare -x HISTCONTROL="ignoredups"
declare -x HISTSIZE="1000"
declare -x HOME="/home/dmtsai"
declare -x HOSTNAME="study.centos.vbird"
.....(其他省略).....

$ export | cut -c 12-

排序指令

sort 用於排序。

$ sort [-fbMnrtuk] [file or stdin]
-f :忽略大小寫
-b :忽略最前面的空格
-M :以月份的名字來排序,例如 JAN,DEC
-n :使用數字
-r :反向排序
-u :相當於 unique,重複的內容只出現一次
-t :分隔符,預設為 tab
-k :指定排序的區間

示例:/etc/passwd 檔案內容以 : 來分隔,要求以第三列進行排序。

$ cat /etc/passwd | sort -t ':' -k 3
root:x:0:0:root:/root:/bin/bash
dmtsai:x:1000:1000:dmtsai:/home/dmtsai:/bin/bash
alex:x:1001:1002::/home/alex:/bin/bash
arod:x:1002:1003::/home/arod:/bin/bash

uniq 可以將重複的資料只取一個。

$ uniq [-ic]
-i :忽略大小寫
-c :進行計數

示例:取得每個人的登入總次數

$ last | cut -d ' ' -f 1 | sort | uniq -c
1
6 (unknown
47 dmtsai
4 reboot
7 root
1 wtmp

雙向輸出重定向

輸出重定向會將輸出內容重定向到檔案中,而 tee 不僅能夠完成這個功能,還能保留螢幕上的輸出。也就是說,使用 tee 指令,一個輸出會同時傳送到檔案和螢幕上。

$ tee [-a] file

字元轉換指令

tr 用來刪除一行中的字元,或者對字元進行替換。

$ tr [-ds] SET1 ...
-d : 刪除行中 SET1 這個字串

示例,將 last 輸出的資訊所有小寫轉換為大寫。

$ last | tr '[a-z]' '[A-Z]'

col 將 tab 字元轉為空格字元。

$ col [-xb]
-x : 將 tab 鍵轉換成對等的空格鍵

expand 將 tab 轉換一定數量的空格,預設是 8 個。

$ expand [-t] file
-t :tab 轉為空格的數量

join 將有相同資料的那一行合併在一起。

$ join [-ti12] file1 file2
-t :分隔符,預設為空格
-i :忽略大小寫的差異
-1 :第一個檔案所用的比較欄位
-2 :第二個檔案所用的比較欄位

paste 直接將兩行貼上在一起。

$ paste [-d] file1 file2
-d :分隔符,預設為 tab

分割槽指令

split 將一個檔案劃分成多個檔案。

$ split [-bl] file PREFIX
-b :以大小來進行分割槽,可加單位,例如 b, k, m 等
-l :以行數來進行分割槽。
- PREFIX :分割槽檔案的前導名稱

九、正則表示式

grep

g/re/p(globally search a regular expression and print),使用正則表示式進行全域性查詢並列印。

$ grep [-acinv] [--color=auto] 搜尋字串 filename
-c : 統計個數
-i : 忽略大小寫
-n : 輸出行號
-v : 反向選擇,也就是顯示出沒有 搜尋字串 內容的那一行
--color=auto :找到的關鍵字加顏色顯示

示例:把含有 the 字串的行提取出來(注意預設會有 --color=auto 選項,因此以下內容在 Linux 中有顏色顯示 the 字串)

$ grep -n 'the' regular_express.txt
8:I can't finish the test.
12:the symbol '*' is represented as start.
15:You are the best is mean you are the no. 1.
16:The world Happy is the same with "glad".
18:google is the best tools for search keyword

因為 { 和 } 在 shell 是有特殊意義的,因此必須要使用轉義字元進行轉義。

$ grep -n 'go\{2,5\}g' regular_express.txt

printf

用於格式化輸出。它不屬於管道命令,在給 printf 傳資料時需要使用 $( ) 形式。

$ printf '%10s %5i %5i %5i %8.2f \n' $(cat printf.txt)
    DmTsai    80    60    92    77.33
     VBird    75    55    80    70.00
       Ken    60    90    70    73.33

awk

是由 Alfred Aho,Peter Weinberger, 和 Brian Kernighan 創造,awk 這個名字就是這三個創始人名字的首字母。

awk 每次處理一行,處理的最小單位是欄位,每個欄位的命名方式為:$n,n 為欄位號,從 1 開始,$0 表示一整行。

示例:取出最近五個登入使用者的使用者名稱和 IP

$ last -n 5
dmtsai pts/0 192.168.1.100 Tue Jul 14 17:32 still logged in
dmtsai pts/0 192.168.1.100 Thu Jul 9 23:36 - 02:58 (03:22)
dmtsai pts/0 192.168.1.100 Thu Jul 9 17:23 - 23:36 (06:12)
dmtsai pts/0 192.168.1.100 Thu Jul 9 08:02 - 08:17 (00:14)
dmtsai tty1 Fri May 29 11:55 - 12:11 (00:15)
$ last -n 5 | awk '{print $1 "\t" $3}'

可以根據欄位的某些條件進行匹配,例如匹配欄位小於某個值的那一行資料。

$ awk '條件型別 1 {動作 1} 條件型別 2 {動作 2} ...' filename

示例:/etc/passwd 檔案第三個欄位為 UID,對 UID 小於 10 的資料進行處理。

$ cat /etc/passwd | awk 'BEGIN {FS=":"} $3 < 10 {print $1 "\t " $3}'
root 0
bin 1
daemon 2

awk 變數:

變數名稱 代表意義
NF 每一行擁有的欄位總數
NR 目前所處理的是第幾行資料
FS 目前的分隔字元,預設是空格鍵

示例:顯示正在處理的行號以及每一行有多少欄位

$ last -n 5 | awk '{print $1 "\t lines: " NR "\t columns: " NF}'
dmtsai lines: 1 columns: 10
dmtsai lines: 2 columns: 10
dmtsai lines: 3 columns: 10
dmtsai lines: 4 columns: 10
dmtsai lines: 5 columns: 9

十、程序管理

檢視程序

1. ps

檢視某個時間點的程序資訊

示例一:檢視自己的程序

# ps -l

示例二:檢視系統所有程序

# ps aux

示例三:檢視特定的程序

# ps aux | grep threadx

2. pstree

檢視程序樹

示例:檢視所有程序樹

# pstree -A

3. top

實時顯示程序資訊

示例:兩秒鐘重新整理一次

# top -d 2

4. netstat

檢視佔用埠的程序

示例:檢視特定埠的程序

# netstat -anp | grep port

程序狀態

狀態 說明
R running or runnable (on run queue)
D uninterruptible sleep (usually I/O)
S interruptible sleep (waiting for an event to complete)
Z zombie (terminated but not reaped by its parent)
T stopped (either by a job control signal or because it is being traced)

SIGCHLD

當一個子程序改變了它的狀態時(停止執行,繼續執行或者退出),有兩件事會發生在父程序中:

  • 得到 SIGCHLD 訊號;
  • waitpid() 或者 wait() 呼叫會返回。

其中子程序傳送的 SIGCHLD 訊號包含了子程序的資訊,比如程序 ID、程序狀態、程序使用 CPU 的時間等。

在子程序退出時,它的程序描述符不會立即釋放,這是為了讓父程序得到子程序資訊,父程序通過 wait() 和 waitpid() 來獲得一個已經退出的子程序的資訊。

wait()

pid_t wait(int *status)

父程序呼叫 wait() 會一直阻塞,直到收到一個子程序退出的 SIGCHLD 訊號,之後 wait() 函式會銷燬子程序並返回。

如果成功,返回被收集的子程序的程序 ID;如果呼叫程序沒有子程序,呼叫就會失敗,此時返回 -1,同時 errno 被置為 ECHILD。

引數 status 用來儲存被收集的子程序退出時的一些狀態,如果對這個子程序是如何死掉的毫不在意,只想把這個子程序消滅掉,可以設定這個引數為 NULL。

waitpid()

pid_t waitpid(pid_t pid, int *status, int options)

作用和 wait() 完全相同,但是多了兩個可由使用者控制的引數 pid 和 options。

pid 引數指示一個子程序的 ID,表示只關心這個子程序退出的 SIGCHLD 訊號。如果 pid=-1 時,那麼和 wait() 作用相同,都是關心所有子程序退出的 SIGCHLD 訊號。

options 引數主要有 WNOHANG 和 WUNTRACED 兩個選項,WNOHANG 可以使 waitpid() 呼叫變成非阻塞的,也就是說它會立即返回,父程序可以繼續執行其它任務。

孤兒程序

一個父程序退出,而它的一個或多個子程序還在執行,那麼這些子程序將成為孤兒程序。

孤兒程序將被 init 程序(程序號為 1)所收養,並由 init 程序對它們完成狀態收集工作。

由於孤兒程序會被 init 程序收養,所以孤兒程序不會對系統造成危害。

殭屍程序

一個子程序的程序描述符在子程序退出時不會釋放,只有當父程序通過 wait() 或 waitpid() 獲取了子程序資訊後才會釋放。如果子程序退出,而父程序並沒有呼叫 wait() 或 waitpid(),那麼子程序的程序描述符仍然儲存在系統中,這種程序稱之為殭屍程序。

殭屍程序通過 ps 命令顯示出來的狀態為 Z(zombie)。

系統所能使用的程序號是有限的,如果產生大量殭屍程序,將因為沒有可用的程序號而導致系統不能產生新的程序。

要消滅系統中大量的殭屍程序,只需要將其父程序殺死,此時殭屍程序就會變成孤兒程序,從而被 init 所收養,這樣 init 就會釋放所有的殭屍程序所佔有的資源,從而結束殭屍程序。

參考資料