章 1. GNU/Linux 教學

內容目錄

1.1. 控制臺基礎
1.1.1. shell 提示字元 (prompt)
1.1.2. GUI 下的 shell 提示符
1.1.3. root 帳號
1.1.4. root shell 提示字元
1.1.5. GUI系統管理工具
1.1.6. 虛擬控制檯
1.1.7. 怎樣退出命令列提示字元
1.1.8. 怎樣關閉系統
1.1.9. 恢復一個正常的控制檯
1.1.10. 建議新手的額外軟體包
1.1.11. 額外使用者帳號
1.1.12. sudo 調配
1.1.13. Play time
1.2. 類 Unix 檔案系統
1.2.1. Unix 文件基礎
1.2.2. 檔案系統深入解析
1.2.3. 檔案系統權限
1.2.4. 控制新建檔案的許可權:umask
1.2.5. 一組使用者的許可權(組)
1.2.6. 時間戳
1.2.7. 連結
1.2.8. 命名管道(先進先出)
1.2.9. 套接字
1.2.10. 設備文件
1.2.11. 特別設備文件
1.2.12. procfs 和 sysfs
1.2.13. tmpfs
1.3. Midnight Commander (MC)
1.3.1. 自定義 MC
1.3.2. 啟動 MC
1.3.3. MC 文件管理
1.3.4. MC 指令列技巧
1.3.5. MC 內部編輯器
1.3.6. MC 內部檢視器
1.3.7. 自動啟動 MC
1.3.8. MC 中的 虛擬檔案系統
1.4. 類 Unix 工作環境基礎
1.4.1. 登入 shell
1.4.2. 定製bash
1.4.3. 特殊按鍵
1.4.4. 滑鼠操作
1.4.5. 文件內容查看
1.4.6. 文字編輯器
1.4.7. 設置預設文本編輯器
1.4.8. 使用 vim
1.4.9. 記錄shell活動
1.4.10. 基本的Unix指令
1.5. 簡單 shell 指令
1.5.1. 指令執行和環境變數
1.5.2. “$LANG”變量
1.5.3. "$PATH" 變數
1.5.4. "$HOME" 變數
1.5.5. 指令列選項
1.5.6. Shell 萬用字元
1.5.7. 指令的回傳值
1.5.8. 典型的順序指令和 shell 重導向
1.5.9. 指令別名
1.6. 類 Unix 的文本處理
1.6.1. Unix 文本工具
1.6.2. 正規表達式
1.6.3. 替換表達式
1.6.4. 正規表達式的全域性替換
1.6.5. 從文字檔案的表格中提取資料
1.6.6. 用於管道指令的小片段指令碼

我想,當你學習一個電腦系統,就像學習一門新的外語。雖然教學和文檔是有幫助的,但你必須自己練習。爲了幫助你順利的開始,我詳細說明一些基本要點。

Debian GNU Linux中最強大的設計來自Unix作業系統,一個多人多工的作業系統。你必須學會利用這些特性以及Unix和GNU/Linux的相似性。

別迴避面對Unix的文檔,不要只是依賴於GNU/Linux文檔,這樣做會剝奪你瞭解許多有用的資訊。

[注意] 注意

如果你在任何類Unix系統中使用過一段時間的命令列工具,你可能已經掌握了這份文檔中的內容。那請把它當做一個實戰檢驗和進修。

啟動系統之後,如果你沒有安裝 GUI(例如GNOME 或者 KDE),那麼你會看到字元登入介面。假設你的主機名為foo,那麼登入提示符將如下所示。

如果你安裝了一個 GUI 環境,那麼你仍然能夠用 Ctrl-Alt-F3 進入基於字元的登入提示符,同時你能透過 Ctrl-Alt-F2 回到 GUI 環境(更多詳情請參閱下文 節 1.1.6, “虛擬控制檯”)。

foo login:

在登錄提示字元下,你輸入你的使用者名,例如penguin,然後按 Enter 鍵,接下來輸入你的密碼並再次按 Enter 鍵。

[注意] 注意

遵循Unix傳統,Debian系統下的使用者名和密碼是大小寫敏感的。使用者名通常由小寫字母組成。第一個使用者帳號通常在安裝期間進行創建。額外的使用者帳號由root使用者用 adduser(8)創建。

系統以保存在 "/etc/motd" 中的歡迎資訊(Message Of The Day)來開始,同時顯示一個指令提示字元。

Debian GNU/Linux 12 foo tty3

foo login: penguin
Password:

Linux foo 6.5.0-0.deb12.4-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.5.10-1~bpo12+1 (2023-11-23) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.

Last login: Wed Dec 20 09:39:00 JST 2023 on tty3
foo:~$

現在,你就在 shell 下。shell 解析你的指令。

如果你在安裝 Debian 的過程中,安裝了一個 GUI 環境,那麼你在啟動系統後將使用圖形登入介面。輸入你的使用者名稱和密碼可以登入到非特權使用者帳號。使用 Tab 鍵(跳格鍵)可以在使用者名稱和密碼之間移動,也可以使用滑鼠主要鍵點選。

要在 GUI(圖形使用者介面)環境下獲得 shell 提示符,你必須啟動一個x 終端模擬器程式,例如gnome-terminal(1)、rxvt(1)或xterm(1)。在 GNOME 桌面環境下,你可以按 超級鍵(Windows 鍵),在搜尋提示裡輸入"terminal"來開啟終端。

在其它一些桌面系統(如 fluxbox)下面,可能沒有明顯的開始選單入口。如果是這種情況,試下右擊桌面螢幕並希望能有彈出選單。

root 帳號也被稱作超級使用者或特權使用者。用這個帳號,你能夠履行下面的系統管理任務。

  • 讀、寫和刪除系統上的任何文件,不顧它們的文件權限

  • 設置系統上任何文件的所有者和權限

  • 設置系統上任何非特權使用者的密碼

  • 免使用者密碼登錄任何使用者

root 帳號擁有至高無上的權力,你要慎重和負責任的使用。

[警告] 警告

從來不和其他人共享 root 密碼。

[注意] 注意

一個文件(包括硬體設備,如CD-ROM等,這些對Debian系統來說都只是一個文件)的權限可能會導致非root使用者無法使用或存取它 。雖然在這種情況下,使用root帳戶是一個快速的方法,但正確的解決方法應該是對文件權限和使用者組的成員進行合適的設置(參見節 1.2.3, “檔案系統權限”)。

如果你的桌面選單沒有使用適當許可權啟動 GUI(圖形使用者介面)的自動化管理工具,你可以在終端模擬器(例如gnome-terminal(1)、rxvt(1)或xterm(1))中 root 的 shell 提示符下啟動它。參見節 1.1.4, “root shell 提示字元”節 7.9, “X 服務端連線”

[警告] 警告

永遠不要在顯示管理器(例如gdm3(1))的提示符下輸入root來使用 root 賬戶啟動 GUI 顯示/會話 管理器。

永遠不要在顯示關鍵資訊的X Window下運行不受信任的遠程GUI程序,因爲它可能會監聽你的X螢幕。

在預設的Debian系統中,有6個可切換的類VT100字元控制檯,可以直接在Linux主機上啓動shell。除非你處於GUI環境下,否則你可以同時按下左Alt鍵F1F6之一的鍵在虛擬控制檯間切換。每一個字元控制檯都允許獨立登入帳號並提供多使用者環境。這個多使用者環境是偉大的Unix的特性,很容易上癮。

如果你處於 GUI 環境中,你可以透過 Ctrl-Alt-F3 鍵前往字元控制檯 3,也就是同時按下左 Ctrl 鍵左 Alt 鍵F3 鍵。你可以按下 Alt-F2 回到 GUI 環境,它一般執行在虛擬控制檯 2。

你也可以使用命令列切換到另一個虛擬控制檯,例如切換到控制檯 3。

# chvt 3

就像任何其他的現代作業系統一樣,Debian會通過記憶體中的快取數據進行文件操作以提高性能,因此在電源被安全地關閉前需要適當的關機過程,通過將記憶體中的數據強制寫入硬盤來維持文件的完整性。如果軟體的電源控制可用,那麼關機過程中會自動關閉系統電源。(否則,你可能需要在關機過程之後按電源鍵幾秒鐘。)

在普通多使用者模式模式下,可以使用命令列關閉系統。

# shutdown -h now

在單使用者模式下,可以使用命令列關閉系統。

# poweroff -i -f

參見節 6.3.8, “怎樣通過 SSH 關閉遠端系統”

不需任何桌面環境,就能執行Debian的最小安裝方式,但若能使用 mcvim 併用 apt-get(8),對初學者而言,仍是有用的。

# apt-get update
 ...
# apt-get install mc vim sudo aptitude
 ...

如果你已經安裝了這些軟體包,那麼不會有新的軟體包被安裝。


閱讀一些資訊文檔,也是一個好的主意。


你可以用下面的指令安裝這些包。

# apt-get install package_name

對於典型的單使用者工作站,例如運行在筆記本電腦上的桌面Debian系統,通常簡單地調配sudo(8)來使爲非特權使用者(例如使用者penguin)只需輸入使用者密碼而非root密碼就能獲得管理員權限。

# echo "penguin  ALL=(ALL) ALL" >> /etc/sudoers

另外,可以使用下列指令使非特權使用者(例如使用者penguin)無需密碼就獲得管理員權限。

# echo "penguin  ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers

這些技巧只對你管理的單使用者工作站中那個唯一的使用者有用。

[警告] 警告

在多使用者工作站中不要建立這樣的普通使用者帳號,因爲它會導致非常嚴重的系統安全問題。

[注意] 注意

在上述例子中,使用者penguin的密碼及帳號要有和root帳號密碼同樣多的保護。

在這種情況下,管理員權限被賦予那些有權對工作站進行系統管理任務的人。永遠不要讓你的公司行政管理部門或你的老闆進行管理(例如給予他們權限),除非他們獲得了授權並有這樣的能力。

[注意] 注意

爲了對受限的設備和文件提供存取權限,你應該考慮使用 羣組 提供的近用限制而不是使用 root 權限,來自 sudo(8)。

隨着越來越細緻周密的調配,sudo(8)可以授予一個共享系統上的其它使用者有限的管理權限而不共享root密碼。這可以幫助對有多個管理員的主機進行責任追究,你可以瞭解到是誰做什麼。另一方面,你可能不想任何人有這樣的權限。

在GNU/Linux和其他類Unix作業系統中,文件被組織到目錄中。所有的文件和目錄排放在以“/”爲根的巨大的樹裏。叫它樹是因爲如果你畫出檔案系統,它看起來就像一棵樹,只是它是顛倒過來的。

這些文件和目錄可以分散在多個設備中。mount(8)用於把某個設備上找到的檔案系統附着到巨大的文件樹上。相反的,umount(8)把它再次分離。在當前的Linux核心裏mount(8)帶某些參數,可以把文件樹的一部分綁定到另外的地方,或者可以把檔案系統掛載爲共享的、私有的、從設備、或不可綁定的。對每個檔案系統支援的掛載選項可以在/usr/share/doc/linux-doc-*/Documentation/filesystems/找到。

Unix系統上叫做目錄,某些其他系統上叫做文件夾。請同樣留意,在任何Unix系統上,沒有的驅動器的概念,例如“A:”。這只有一個檔案系統,並且所有東西都包含在內。這相對於Windows來說是一個巨大的優點。

下面是一些 Unix 文件基礎。

[注意] 注意

雖然你可以在文件名中使用任意的字幕或者符號, 但是在實際情況下這樣做是一個壞主意. 最好避免使用一些在命令列裏面含有特殊意義的字元, 比如空格, 製表符, 換行符, 和其它的特殊字元: { } ( ) [ ] ' ` " \ / >< | ; ! #&^ * % @ $. 如果你想有一個區分度良好的命名, 比較好的選擇是利用 時期, 連字元和下劃線. 你也可以每個單詞的首字母大寫, 這叫大駝峯命名法, 比如這樣 "LikeThis". 經驗豐富的Linux使用者會趨向於在文件名中不使用空格.

[注意] 注意

這個 "root" 可能既表示 "超級使用者root" 又表示 " 根目錄"(/root) . 應該根據上下文確定它的用法.

[注意] 注意

單詞path不僅表示包含全限定文件名, 也可能表示指令搜索的路徑. 通常路徑真實的意思是需要通過上下文來明確.

關於檔案階層的最佳詳細實踐在檔案系統階層標準("/usr/share/doc/debian-policy/fhs/fhs-2.3.txt.gz" 和 hier (7)). 你應該記住以下的一些標準作爲開始學習的步驟.


按照UNIX系统的傳統,Debian GNU / Linux 的文件系统是在硬體數據儲存設備,諸如硬碟或其他的儲存設備上,與硬體的互動,如控制台和遠端序列終端都是以統一的方式呈現在 “/ dev /” 下面。

每個檔案、目錄、命名管道(一種兩個程式間共享資料的方法)或 Debian GNU/Linux 系統上的物理裝置都有一個叫做 inode的資料結構,描述了其相關特性,例如擁有它的使用者(所有者),它屬於的群組,最後一次存取時間,等等。把所有東西都表示在檔案系統中的想法是來源於 Unix,現代的 Linux 核心則將這個思路進行了擴充。現在,甚至有關計算機上正在執行的程序的資訊都可以在檔案系統中找到。

這個對物理實體和內部行程的統一和抽象是非常強大的,因爲這允許我們用同樣的指令對許多完全不同的設備進行同樣的操作。甚至可以通過向鏈接到運行行程的特殊文件寫入數據來改變核心的運行方式。

[提示] 提示

如果你需要識別文件樹和物理實體之間的對應關係,不帶參數運行mount(8)。

類Unix系統的檔案系統權限被定義給三類受影響的使用者。

  • 擁有這個文件的使用者u

  • 這個文件所屬的其他使用者(g

  • 所有其餘的使用者(o),同樣稱爲“世界”和“所有人”

對文件來說,每個對應權限允許下列動作。

  • 可讀r)權限允許所有者檢查文件的內容。

  • 可寫w)權限允許所有者修改文件內容。

  • 可執行x)權限允許所有者把文件當做一個指令運行。

對於目錄來說,每個對應權限允許下列動作。

  • 可讀r)權限允許所有者列出目錄內的內容。

  • 可寫w)權限允許所有者添加或刪除目錄裏面的文件。

  • 可執行x)權限允許所有者存取目錄裏的文件。

在這裏,一個目錄的可執行權限意味着不僅允許讀目錄裏的文件,還允許顯示他們的屬性,例如大小和修改時間。

ls(1)用於顯示文件和目錄的權限資訊(更多)。當運行時帶有“-l”選項,它將按給定順序顯示下列資訊。

  • 文件類型(第一個字母)

  • 文件的存取權限(9個字元,三個字元組成一組按照使用者、組、其他的順序表示)

  • 鏈接到文件的硬鏈接數

  • 文件所有者的使用者

  • 這個文件所屬的

  • 以字元(字節)爲單位的文件大小

  • 文件的日期和時間(mtime)

  • 文件的名字


chown(1)用於 root 帳號修改文件的所有者。chgrp(1)用於文件的所有者或 root 帳號修改文件所屬的組。chmod(1)用於文件的所有者或root帳號修改文件和文件夾的存取權限。操作一個foo文件的基本語法如下 。

# chown newowner foo
# chgrp newgroup foo
# chmod  [ugoa][+-=][rwxXst][,...] foo

例如,你可以按照下面使一個目錄樹被使用者foo所有,並共享給組bar

# cd /some/location/
# chown -R foo:bar .
# chmod -R ug+rwX,o=rX .

有三個更加特殊的權限位。

  • Set_User_ID位(sS替換使用者的x

  • Set_Group_ID位(sS替換組的x

  • 粘置位(tT替代其他使用者的x

這裏“ls -l”對這些位的輸出是大寫的,如果這些輸出裏隱藏了可執行位,則它未設置

給一個可執行文件設置Set-User-ID位將允許一個使用者以他自己的ID運行這個可執行文件(例如root)。類似的,給一個可執行文件設置了Set-Group-ID位將允許一個使用者以文件的組ID運行該文件。(例如root組)。由於這些設置可能引起安全風險,使能它們的時候需要格外留意。

在一個目錄上設置“Set-Group-ID”將打開類 BSD 的文件創建計劃,所有在目錄裏面創建的文件將屬於目錄所屬的

給一個目錄設定“粘滯位”將保護該目錄內的檔案不被其所有者之外的一個使用者刪除。為了保護一個在像“/tmp”這樣所有人可寫或同組可寫的目錄下檔案內容的安全,不僅要去除可寫許可權,還要給其所在目錄設定粘滯位。否則,該檔案可以被任意對其所在目錄有寫許可權的使用者刪除並建立一個同名的新檔案。

這裏有少量有趣的文件權限例子。

$ ls -l /etc/passwd /etc/shadow /dev/ppp /usr/sbin/exim4
crw------T 1 root root   108, 0 Oct 16 20:57 /dev/ppp
-rw-r--r-- 1 root root     2761 Aug 30 10:38 /etc/passwd
-rw-r----- 1 root shadow   1695 Aug 30 10:38 /etc/shadow
-rwsr-xr-x 1 root root   973824 Sep 23 20:04 /usr/sbin/exim4
$ ls -ld /tmp /var/tmp /usr/local /var/mail /usr/src
drwxrwxrwt 14 root root  20480 Oct 16 21:25 /tmp
drwxrwsr-x 10 root staff  4096 Sep 29 22:50 /usr/local
drwxr-xr-x 10 root root   4096 Oct 11 00:28 /usr/src
drwxrwsr-x  2 root mail   4096 Oct 15 21:40 /var/mail
drwxrwxrwt  3 root root   4096 Oct 16 21:20 /var/tmp

chmod(1)有另一種數值模式來描述檔案許可權。這種數字模式使用3到4位八進位制(底為8)數。


這聽起來很複雜實際上相當簡單。如果你把“ls -l”指令輸出的前幾列(2-10),看成以二進位制(底為2)表示檔案的許可權(“-”看成0,“rwx”看成1),你應該可以理解用數字模式值的最後3位數字對檔案許可權的八進位制表示。

嘗試下列例子

$ touch foo bar
$ chmod u=rw,go=r foo
$ chmod 644 bar
$ ls -l foo bar
-rw-r--r-- 1 penguin penguin 0 Oct 16 21:39 bar
-rw-r--r-- 1 penguin penguin 0 Oct 16 21:35 foo
[提示] 提示

如果你需要在 shell 指令碼中存取“ls -l”顯示的資訊,你需要使用相關指令,如test(1),stat(1)和readlink(1)。shell 內建指令,如“[”或“test”,可能也會用到。

[警告] 警告

在做重啟或者類似行為前,確保儲存沒有儲存的修改。

你能夠增加一個使用者 penguinbird 組,在兩個步驟內:

  • 使用下面中的一個改變組配置:

    • 執行 "sudo usermod -aG bird penguin"。

    • 執行"sudo adduser penguin bird"。(只在典型的 Debian 系統)

    • 執行"sudo vigr"編輯 /etc/group 和"sudo vigr -s"編輯 /etc/gshadow 來追加 penguinbird 行。

  • 使用下面中的一個來應用配置:

    • 冷重啟再登入。(最佳選項)

    • 執行 "kill -TERM -1" 並做一些修復行為,比如"systemctl restart NetworkManager.service"。

    • 透過 GUI(圖形使用者介面)選單登出再登入。

你能夠從 bird 組移除使用者 penguin,用兩個步驟:

  • 使用下面中的一個改變組配置:

    • 執行 "sudo usermod -rG bird penguin"。

    • 執行 "sudo deluser penguin bird"。(只在典型的 Debian 系統)

    • 執行"sudo vigr"編輯 /etc/group 和"sudo vigr -s"編輯 /etc/gshadow 來移除 bird 行裡面的penguin

  • 使用下面中的一個來應用配置:

    • 冷重啟再登入。(最佳選項)

    • 執行 "kill -TERM -1" 並做一些修復行為,比如"systemctl restart NetworkManager.service"。

    • 透過 GUI(圖形使用者介面)選單登出,不是 Gnome 桌面的一個選項。

在現代桌面系統,任何熱重啟嘗試是真實的冷重啟的脆弱替代。

[注意] 注意

或者,你可以通過新增一行 “auth optional pam_group.so”到 “/etc/pam.d/common-auth” 以及調配 “/etc/security/group.conf” ,使得在身份驗證過程動態新增使用者到組。(參見章 4, 認證和訪問控制。)

在 Debian 系統中,硬體裝置是另一種檔案。如果你從一個使用者帳號存取某些裝置出現問題,例如CD-ROM和USB記憶棒,你需要使這個使用者成為相關組的成員。

一些著名的由系統提供的組允許其成員不需要 root 許可權存取某些特定的檔案和裝置。


[提示] 提示

你需要屬於 dialout 組使得可以重調配調變解調器,撥號到任意地方,等等。但如果root 使用者在 “/etc/ppp/peers/” 為受信任點建立了預定義組態檔案的話,你只需要屬於dip 組,就可以通過使用pppd(8)、pon(1),以及poff(1)指令 建立撥號 IP 連結到這些受信任的點。

某些著名的由系統提供的組允許它們的成員不帶 root 許可權執行特定的指令。


由系統提供的使用者和組的完整列表,參見由 base-passwd包提供的“/usr/share/doc/base-passwd/users-and-groups.html”中,當前版本的“使用者和組”。

使用者和組系統的管理指令,參見passwd(5),group(5),shadow(5),newgrp(1),vipw(8),vigr(8),以及pam_group(8)。

GNU/Linux 文件有三種類型的時間戳。


[注意] 注意

ctime 不是文件創建時間。

[注意] 注意

atime在 GNU/Linux 系統上的真實值可能和歷史上 Unix 的定義有所不同。

  • 覆蓋一個文件,將會改變該文件所有的 mtime, ctime, 和 atime 屬性。

  • 改變文件的所有者或者權限,將改變文件的 ctime atime 屬性。

  • 在歷史上的 Unix 系統中,讀取一個檔案將改變檔案的 atime 屬性。

  • 讀一個檔案,將改變檔案的 atime屬性;在 GNU/Linux 系統上,這僅發生在其檔案系統使用“strictatime”引數掛載的情況下。

  • 如果 GNU/Linux 系統的檔案系統使用 "relatime" 選項掛載,第一次讀檔案,或者隨後讀檔案,將改變該檔案的 atime 屬性. (從 Linux 2.6.30 開始的預設行為)

  • 如果 GNU/Linux 系統的檔案系統使用 "noatime" 掛載,則讀一個檔案,不會改變這個檔案的 atime 屬性。

[注意] 注意

為了在正常的使用場景中能夠提升檔案系統的讀取效率,新增了 "noatime" 和 "relatime" 這兩個載入選項。如使用了 "strictatime" 選項,即使簡單的檔案讀操作都伴隨著更新 atime 屬性這個耗時的寫操作。但是 atime 屬性除了 mbox(5) 檔案以外卻很少用到。詳情請看 mount(8)。

使用 touch(1) 指令修改已存在檔案的時間戳。

對於時間戳,在非英語區域(“fr_FR.UTF-8”),ls 命令輸出本地化字串。

$ LANG=C  ls -l foo
-rw-rw-r-- 1 penguin penguin 0 Oct 16 21:35 foo
$ LANG=en_US.UTF-8  ls -l foo
-rw-rw-r-- 1 penguin penguin 0 Oct 16 21:35 foo
$ LANG=fr_FR.UTF-8  ls -l foo
-rw-rw-r-- 1 penguin penguin 0 oct. 16 21:35 foo
[提示] 提示

參考節 9.3.4, “定製時間和日期的顯示” 自定義 “ls -l” 輸出 。

有兩種方法把一個檔案 “foo” 連結到一個不同的檔名 “bar”。

請參閱下面的示例,rm 指令結果中連結數的變化和細微的差別。

$ umask 002
$ echo "Original Content" > foo
$ ls -li foo
1449840 -rw-rw-r-- 1 penguin penguin 17 Oct 16 21:42 foo
$ ln foo bar     # hard link
$ ln -s foo baz  # symlink
$ ls -li foo bar baz
1449840 -rw-rw-r-- 2 penguin penguin 17 Oct 16 21:42 bar
1450180 lrwxrwxrwx 1 penguin penguin  3 Oct 16 21:47 baz -> foo
1449840 -rw-rw-r-- 2 penguin penguin 17 Oct 16 21:42 foo
$ rm foo
$ echo "New Content" > foo
$ ls -li foo bar baz
1449840 -rw-rw-r-- 1 penguin penguin 17 Oct 16 21:42 bar
1450180 lrwxrwxrwx 1 penguin penguin  3 Oct 16 21:47 baz -> foo
1450183 -rw-rw-r-- 1 penguin penguin 12 Oct 16 21:48 foo
$ cat bar
Original Content
$ cat baz
New Content

硬連結可以在同一個檔案系統內建立,並共用同一個 inode 號,由ls(1)帶 “-i”選項顯示。

符號連結總是名義上具有“rwxrwxrwx”的檔案存取許可權,如上面例子所示,實際的有效存取許可權由它所指向的檔案確定。

[注意] 注意

除非你有非常好的理由,否則不要建立一個複雜的符號連結或硬連結通常是個好主意。符號連結的邏輯組合可能導致檔案系統噩夢般的無限迴圈。

[注意] 注意

通常使用符號連結比使用硬連結更合適,除非你有一個好理由使用硬連結。

.”目錄連結到它所在的目錄,因此任何新建目錄的連結數從2開始。“..”目錄連結到父目錄,因此目錄的連結數隨著新的子目錄的建立而增加。

如果你剛從Windows遷移到Linux,你很快將清楚 Unix 的檔名連結相較於Windows最相近的“快捷方式”是多麼精心設計的。由於它是在檔案系統中實現的,應用無法看到連結檔案跟原始檔案之間的區別。在硬連結這種情況,這真的是毫無差別。

命名管道是一個像管道一樣的檔案。你把內容放進了檔案,它從另一端出來。因此,它被稱為FIFO,即先進先出:你從管道這端先放進去的東西會從另一端先出來。

如果對一個命名管道進行寫入操作,寫入的過程不會被終止,直到寫入的資訊從管道中被讀取出來。讀取過程將會持續到沒有資訊可以讀取為止。管道的大小始終是零,它不儲存資料,它只是連線兩個過程,像shell提供的 " 1| 2" 語法功能一樣。然而,一旦管道有了名稱,這兩個程序就可以不必在同一個指令列,甚至由同一個使用者執行。管道是 UNIX 的一個非常有影響力的創新。

嘗試下列例子

$ cd; mkfifo mypipe
$ echo "hello" >mypipe & # put into background
[1] 8022
$ ls -l mypipe
prw-rw-r-- 1 penguin penguin 0 Oct 16 21:49 mypipe
$ cat mypipe
hello
[1]+  Done                    echo "hello" >mypipe
$ ls mypipe
mypipe
$ rm mypipe

設備文件包括系統的物理設備和虛擬設備,如硬盤、顯卡、顯示屏、鍵盤。虛擬設備的一個例子是控制檯,用“/dev/console”來描述。

設備文件有兩種類型。

  • 字元設備

    • 每次存取一個字元

    • 一個字元等於一個字節

    • 如鍵盤、串口…

  • 塊設備

    • 通過更大的單元–塊,進行存取

    • 一個塊>一個字節

    • 如硬盤等…

你可以讀寫塊設備文件,儘管該文件可能包含二進位數據,讀取後顯示出無法理解的亂碼。向文件寫入數據,有時可以幫助定位硬體連接故障。比如,你可以將文本文件導入打字機設備“/dev/lp0”,或者將調製解調指令發送到合適的串口“/dev/ttyS0”。但是,除非這些操作都小心完成,否則可能會導致一場大災難。所以要特別小心。

[注意] 注意

常規存取打字機,使用lp(1)。

設備的節點數可以通過執行ls(1)得到,如下所示。

$ ls -l /dev/sda /dev/sr0 /dev/ttyS0 /dev/zero
brw-rw---T  1 root disk     8,  0 Oct 16 20:57 /dev/sda
brw-rw---T+ 1 root cdrom   11,  0 Oct 16 21:53 /dev/sr0
crw-rw---T  1 root dialout  4, 64 Oct 16 20:57 /dev/ttyS0
crw-rw-rw-  1 root root     1,  5 Oct 16 20:57 /dev/zero
  • "/dev/sda"的主設備號是8,次設備號是0。它可以被disk羣組的使用者讀寫。

  • "/dev/sr0"的主設備號是11,次設備號是0。它可以被cdrom羣組的使用者讀寫。

  • "/dev/ttyS0"的主設備號是4,次設備號是64。它可以被dailout羣組的使用者讀寫。

  • "/dev/zero"的主設備號是1,次設備號是5。它可以被任意使用者讀寫。

在現代Linux系統中,處在"/dev"之下的檔案系統會自動被udev()機制填充。

procfssysfs兩個僞檔案系統,分別掛載於"/proc"和"/sys"之上,將核心中的數據結構暴露給使用者空間。或者說,這些條目是虛擬的,他們打開了深入瞭解作業系統運行的方便之門。

目錄"/proc"爲每個正在運行的行程提供了一個子目錄,目錄的名字就是行程的 PID。需要讀取行程資訊的系統工具,如ps(),可以從這個目錄結構獲得資訊。

"/proc/sys"之下的目錄,包含了可以更改某些核心運行參數的接口。(你也可以使用專門的sysctl()指令修改,或者使用其預加載/調配文件"/etc/sysctl.conf"。)

當人們看到這個特別大的文件"/proc/kcore"時,常常會驚慌失措。這個文件於你的的電腦記憶體大小相差不多。它被用來調試核心。它是一個虛擬文件,指向系統記憶體,所以不必擔心它的大小。

"/sys"以下的目錄包含了核心輸出的數據結構,它們的屬性,以及它們之間的鏈接。它同時也包含了改變某些核心運行時參數的界面。

參考"proc.txt(.gz)","sysfs.txt(.gz)",以及其他相關的Linux核心文檔("/usr/share/doc/linux-doc-*/Documentation/filesystems/*"),這些文件由linux-doc-*軟體包提供。

tmpfs是一個臨時檔案系統,它的文件都保存在虛擬記憶體中。必要時,位於記憶體頁快取的tmpfs數據可能被交換到硬碟中的交換分區

系統啓動早期階段,"/run"目錄掛載爲tmpfs。這樣即使"/"掛載爲只讀,它也是可以被寫入的。它爲過渡態文件提供了新的存儲空間,同時也替代了Filesystem Hierarchy Standar2.3版中說明的目錄位置:

  • "/var/run" → "/run"

  • "/var/lock" → "/run/lock"

  • "/dev/shm" → "/run/shm"

參考"tmpfs.txt(.gz)", 文件位於Linux核心文檔("/usr/share/doc/linux-doc-*/Documentation/filesystems/*")目錄之下,由軟體包linux-doc-*提供。

Midnight Commander (MC) 是一個Linux終端或其它終端環境下的 GNU 版 "瑞士刀" 。它為新手們提供了一個選單式樣的終端使用體驗,這更易於學習運用標準的 Unix 指令。

你可能需要按照下面的指令來安裝標題為 " mc " 的Midnight Commander 包.

$ sudo apt-get install mc

使用 mc(1) 指令那個來瀏覽 Debian 系統。這是最好的學習方式。請使用游標鍵和Enter 鍵來翻看一些感興趣的內容。

  • "/etc" 及其子目錄

  • " /var/log " 及其子目錄

  • " /usr/share/doc " 及其子目錄

  • " /usr/sbin " 和 " /usr/bin "

雖然 MC 差不多可以讓你做任何事情,但學會從 shell 提示下使用指令列工具也是非常重要的,可以讓你變得熟悉類 Unix 工作環境。

在使用類 Unix 系統過程中, 各種類似於VimEmacs的工具,你應該精通其中的一個。

我認為習慣於使用 Vim 指令是一個明智的選擇,因為Linux/Unix系統裡一般都附帶了 Vi 編輯器。 (實際上最初的vi 以及後來的 nvi 這類工具程式很常見。因為在 Vim 裡提供了F1幫助鍵,在同類工具中它的功能更強大,所以我選擇 Vim 而不是其它新出的一些工具。)

假設你不是用 Emacs 就是用XEmacs 作為你的編輯器,其實還有更好的選擇,尤其是在程式設計的時候。 Emacs 還有很多其他的特點,包括新手導讀,目錄編輯器,郵件客戶端等等。當編寫指令碼或程式的時候,它能自動識別當前工作模式所對應的格式,讓使用更加便利。一些人甚至堅持認為Linux系統裡最需要配備的就是 Emacs。花十分鐘來學習 Emacs 可以為後面的工作剩下更多時間。在此強烈推薦學習使用 Emacs 時候直接使用 GNU Emacs 參考手冊。

在實踐應用中所有這些程式都會有一個教學,輸入 "vim" 和F1鍵就可以啟動Vim。建議你最好閱讀一下前面的35行。移動游標到 "|tutor|" 並按 Ctrl-] 就可以看到線上教學。

[注意] 注意

好的編輯器,像 Vim 和 Emacs,可以處理 UTF-8 及其它不常用編碼格式的文字。有個建議就是在 GUI(圖形使用者介面) 環境下使用 UTF-8 編碼,並安裝要求的程式和字型。編輯器裡可以選擇獨立於 GUI(圖形使用者介面)環境的編碼格式。關於多位元組文字可以查閱參考文件。

最近的 vim(1) 用完全的 "nocompatible" 選項啟動自己,進入到 普通 模式。[1]


請使用 "vimtutor" 程式來學習 vim,透過一個互動式的指導課程。

vim 程式基於 模式 輸入的按鍵來改變它的行為。在 插入-模式和 替代-模式下,輸入的按鍵大部分進入了緩衝區。移動游標大部分在 普通-模式下完成。互動選擇在 可視-模式下完成。在普通-模式下輸入 ":" ,改變它的 模式 進入到 Ex-模式。 Ex-接受命令。

[提示] 提示

Vim 和 Netrw 軟體包可以一起使用。Netrw 同時支援在本地和網路讀寫檔案,瀏覽目錄。用 "vim ." (一個點作為引數)來嘗試 Netrw,在":help netrw"讀取它的文件。

vim 的高階配置,參見 節 9.2, “定製vim”

讓我們來學習基本的Unix指令。在這裏,我指的是一般意義上的“UNIX”。任何UNIX複製所衍生的系統通常都會提供等價的指令。Debian系統也不例外。如果有一些指令不像你想的那樣起作用,請不要擔心。如果shell中使用了別名,其對應的指令輸出會不同。這些例子並不意味着要以這個順序來執行。

建議嘗試使用非特權使用者帳號來使用下列的指令。

表格 1.17. 基本的Unix指令列表

指令 說明
pwd 顯示當前/工作目錄的名稱
whoami 顯示當前的使用者名
id 顯示當前使用者的身份(名稱、uid、gid和相關組)
file foo 顯示“foo”文件的文件類型
type -p commandname 顯示“commandname”指令的文件所處位置
which commandname 同上
type commandname 顯示“commandname”指令的相關資訊
apropos key-word 查找與“key-word”有關的指令
man -k key-word 同上
whatis commandname 用一行解釋 “commandname” 指令
man -a commandname 顯示“commandname”指令的解釋(Unix風格)
info commandname 顯示“commandname”指令相當長的解釋(GNU風格)
ls 顯示目錄內容(不包含以 . 點號開頭的文件和目錄)
ls -a 顯示目錄內容(包含所有文件和目錄)
ls -A 顯示目錄內容(包含幾乎所有文件和目錄,除了“..”和“.”)
ls -la 顯示所有的目錄內容,幷包含詳細的資訊
ls -lai 顯示所有的目錄內容,幷包含inode和詳細的資訊
ls -d 顯示當前目錄下的所有目錄
tree 使用樹狀圖顯示目錄內容
lsof foo 列出處於開啟狀態的檔案 "foo"
lsof -p pid 列出被某程序開啟的檔案: "pid"
mkdir foo 在當前目錄中建立新目錄“foo
rmdir foo 刪除當前目錄中的“foo”目錄
cd foo 切換到當前目錄下或變量“$CDPATH”中的“foo”目錄
cd / 切換到根目錄
cd 切換到當前使用者的家目錄
cd /foo 切換到絕對路徑爲“/foo”的目錄
cd .. 切換到上一級目錄
cd ~foo 切換到使用者“foo”的家目錄
cd - 切換到之前的目錄
</etc/motd pager 使用預設的分頁顯示程式來顯示“/etc/motd”的內容
touch junkfile 建立一個空文件“junkfile
cp foo bar 將一個現有文件“foo”複製到一個新文件“bar
rm junkfile 刪除文件“junkfile
mv foo bar 將一個現有文件“foo”重命名成“bar”(“bar”必須不存在)
mv foo bar 將一個現有文件“foo”移動到新的位置“bar/foo”(必須存在“bar”目錄)
mv foo bar/baz 移動一個現有文件“foo”到新位置並重命名爲“bar/baz”(必須存在“bar”目錄,且不存在“bar>/baz”目錄)
chmod 600 foo 使其他人無法讀寫現有文件“foo”(並且所有人都無法執行該文件)
chmod 644 foo 使其他人對現有文件“foo”可讀但不可寫(並且所有人都無法執行該文件)
chmod 755 foo 使其他人對“foo”可讀而不可寫(並且所有人都能執行該文件)
find . -name pattern 使用 shell “pattern” 查找匹配的文件名(速度較慢)
locate -d . pattern 使用 shell “pattern” 查找匹配的文件名(速度較快,使用定期生成的數據庫)
grep -e "pattern" *.html 在當前目錄下以“.html”結尾的所有文件中,查找匹配“pattern”的文件並顯示
top 全螢幕顯示行程資訊,輸入“q”退出
ps aux | pager 顯示所有正在運行的行程的資訊(BSD風格)
ps -ef | pager 顯示所有正在運行的行程的資訊(Unix system-V風格)
ps aux | grep -e "[e]xim4*" 顯示所有正在運行“exim”和“exim4”的行程
ps axf | pager 顯示所有正在運行的行程的資訊(ASCII風格)
kill 1234 傳送程式中止訊號給ID爲“1234”的行程
gzip foo 使用 Lempel-Ziv 編碼(LZ77)將“foo”壓縮爲“foo.gz
gunzip foo.gz 將“foo.gz”解壓爲“foo
bzip2 foo 使用 Burrows-Wheeter 塊排序壓縮算法和 Huffman 編碼將“foo”壓縮爲“foo.bz2”(壓縮效果比gzip更好)
bunzip2 foo.bz2 將“foo.bz2”解壓爲“foo
xz foo 使用 Lempel-Ziv-Markov 鏈算法將“foo”壓縮爲“foo.xz”(壓縮效果比bzip2更好)
unxz foo.xz 將“foo.xz”解壓爲“foo
tar -xvf foo.tar 從“foo.tar”檔案中提取文件
tar -xvzf foo.tar.gz 從被gzip壓縮過的“foo.tar.gz”檔案中提取文件
tar -xvjf foo.tar.bz2 從“foo.tar.bz2”檔案中提取文件
tar -xvJf foo.tar.xz 從“foo.tar.xz”檔案中提取文件
tar -cvf foo.tar bar/ 將目錄“bar/”中的內容打包到“foo.tar”檔案中
tar -cvzf foo.tar.gz bar/ 將目錄“bar/”中的內容打包到被壓縮的“foo.tar.gz”檔案中
tar -cvjf foo.tar.bz2 bar/ 將目錄“bar/”中的內容打包到“foo.tar.bz2”檔案中
tar -cvJf foo.tar.xz bar/ 將目錄”bar/“中的內容打包到”foo.tar.xz“檔案中
zcat README.gz | pager 使用預設的分頁顯示程式來顯示“README.gz”壓縮包中的內容
zcat README.gz > foo 將“README.gz”解壓後的內容輸出到文件“foo”中
zcat README.gz >> foo 將“README.gz”解壓後的內容添加到文件“foo”的末尾(如果文件不存在,則會先建立該文件)

[注意] 注意

Unix有一個慣例,以“.”開頭的文件將被隱藏。它們一般爲包含了調配資訊和使用者首選項的文件。

對於cd指令,參見builtins(7)。

基本的 Debian 系統的預設分頁顯示程式是more(1),它無法往回滾動。通過指令“apt-get install less"安裝less軟體包後,less(1)會成爲預設的分頁顯示程式,它可以通過方向鍵往回滾動。

"[" 和"]" 在正規表達式 "ps aux | grep -e "[e]xim4*"" 指令中,可以避免grep在結果中排除它自己, 正規表達式中的 "4*" 意思是空或字元"4" ,這樣可以讓 grep 既找到 "exim" 也找到 "exim4"。 雖然 "*" 可以用於指令名稱匹配和正規表達式中,但是它們的含義是不一樣的。欲詳細瞭解正規表達式可以參考 grep(1)。

作爲訓練,請使用上述的指令來遍歷目錄並探究系統。如果你有任何有關控制臺指令的問題,請務必自行閱讀手冊。

嘗試下列例子

$ man man
$ man bash
$ man builtins
$ man grep
$ man ls

手冊的風格可能讓人有點難以習慣,因爲它們都相當簡潔,尤其是比較老舊、非常傳統的那些手冊。但是,一旦你習慣了它,你會欣賞它們的簡潔。

請注意,許多類Unix指令(包含來自 GNU 和 BSD 的)都可以顯示簡短的幫助資訊,你可以使用下列的其中一種方式來查看它(有時不帶任何參數也可以)。

$ commandname --help
$ commandname -h

現在,你對如何使用 Debian 系統已經有一些感覺了。讓我們更深入瞭解 Debian 系統的指令執行機制。在這裏,我將爲新手做一般的講解。精確的解釋參見bash(1)。

一般的指令由有序的組件構成。

  1. 初始化此程式之環境變數值(可選)

  2. 指令名

  3. 參數(可選)

  4. 重導向(可選:> , >> , < , << 等等)

  5. 控制運算子(可選:&&||換行符號 , ; , & , ( , )

一些環境變數的值會改變部分Unix指令的行爲。

環境變數的預設值由PAM系統初始化,其中一些會被某些應用程式重新設定。

  • PAM(可插拔身份驗證模組)系統的模組,比如 pam_env 模組,可以透過 /etc/pam.conf"、 "/etc/environment"和"/etc/default/locale"設定環境變數。

  • 顯示管理器(例如gdm3)可以透過"~/.profile"給 GUI(圖形使用者介面)會話重新設定環境變數。

  • 使用者特有的程式初始化時,可以重新設定在 "~/.profile"、"~/.bash_profile" 和 "~/.bashrc" 中設定的環境變數。

預設的語言環境是在 "$LANG" 環境變數中定義,它在安裝的時候配置為 "LANG=xx_YY.UTF-8",或者在接下來的 GUI(圖形使用者介面)中配置,例如在 GNOME 中是,"設定" → "區域 & 語言" → "語言" / "格式"。

[注意] 注意

目前建議最好用變數 "$LANG" 來配置系統環境變數,只有在逼不得已的情況下才用 $LC_*" 開頭的變數。

$LANG” 變數的完整的語言環境值由3部分組成:“xx_YY.ZZZZ”。



使用 shell 命令列按順序執行下列典型的指令。

$ echo $LANG
en_US.UTF-8
$ date -u
Wed 19 May 2021 03:18:43 PM UTC
$ LANG=fr_FR.UTF-8 date -u
mer. 19 mai 2021 15:19:02 UTC

這裡,date(1)程式執行時使用了不同的語言環境值。

大多數的指令在執行時並沒有預先定義環境變數。對於上面的例子,你也可以選擇如下的方式。

$ LANG=fr_FR.UTF-8
$ date -u
mer. 19 mai 2021 15:19:24 UTC
[提示] 提示

提交一個 BUG 報告的時候,如果使用的是非英語的環境,在 "LANG=en_US.UTF-8" 語言環境環境下對命令進行執行和檢查會更好一些。

對於語言環境調配的細節,參見 節 8.1, “語言環境”

讓我們試著記住下面 Shell 指令裡部分指令列所使用的指令習語。


Debian 系統是一個多工的作業系統。後臺任務讓使用者能夠在一個 shell 中執行多個程式。後臺行程的管理涉及 shell 的內建指令:jobsfgbgkill。請閱讀 bash(1) 中的章節:“SIGNALS”、“JOB CONTROL” 和 “builtins(1)”。

嘗試下列例子

$ </etc/motd pager
$ pager </etc/motd
$ pager /etc/motd
$ cat /etc/motd | pager

儘管4個 shell 重導向的例子都會顯示相同的結果,但最後一個例子毫無意義地運行了額外的 cat 指令浪費了資源。

shell 允許你使用 exec 通過任意一個文件描述符來打開文件。

$ echo Hello >foo
$ exec 3<foo 4>bar  # open files
$ cat <&3 >&4       # redirect stdin to 3, stdout to 4
$ exec 3<&- 4>&-    # close files
$ cat bar
Hello

預定義(Predefined)的文件描述符0-2。


在類 Unix 的工作環境中,文本處理是通過使用管道組成的標準文本處理工具鏈完成的。這是另一個重要的 Unix 創新 (設計哲學)。

這裏有一些在類 Unix 系統中經常使用到的標準文本處理工具。

如果你不確定這些指令究竟做了什麼,請使用“man command” 來自己把它搞清楚吧。

[注意] 注意

排序的順序和表示式的範圍取決於語言環境。如果你想要獲得一個命令的傳統行為,可以使用 “LANG=C” 或 C.UTF-8 語言環境代替原來的 UTF-8 語言環境(參見 節 8.1, “語言環境”)。

[注意] 注意

Perl 正規表達式( perlre(1) )、Perl 兼容正則表達式(PCRE)Pythonre 模組提供的正規表達式與一般的 ERE 相比多了許多通用的擴展。

正規表達式被使用在許多文字處理工具中。它們類似 shell 的萬用字元,但更加複雜和強大。

正規表達式描述要匹配的模式,它是由文字字元和元字元 (metacharacters)構成的。

元字元僅僅是帶有特殊含義的字元。它們有兩種主要的形式,BREERE ,使用哪種取決於上述的文本工具。


常見的 emacs 表示為基本的 BRE 但擴充為 "+" 與 "?" 做為 metacharacters 當成 ERE。因此,不需要以 "\" 在正規的表示 emacs 表示中做為跳脫字元。

grep(1) 可以使用正規表達式來進行文本搜索。

嘗試下列例子

$ egrep 'GNU.*LICENSE|Yoyodyne' /usr/share/common-licenses/GPL
GNU GENERAL PUBLIC LICENSE
GNU GENERAL PUBLIC LICENSE
Yoyodyne, Inc., hereby disclaims all copyright interest in the program

下面有一個文字檔案 “DPL” ,裡面含有 2004 年以前 Debian 專案的領導者名字和起始日期,並以空格分隔。

Ian     Murdock   August  1993
Bruce   Perens    April   1996
Ian     Jackson   January 1998
Wichert Akkerman  January 1999
Ben     Collins   April   2001
Bdale   Garbee    April   2002
Martin  Michlmayr March   2003
[提示] 提示

參見 “Debian 簡史” 獲得最新的 Debian 領導階層歷史

Awk 經常被用來從這種型別的檔案中提取資料。

嘗試下列例子

$ awk '{ print $3 }' <DPL                   # month started
August
April
January
January
April
April
March
$ awk '($1=="Ian") { print }' <DPL          # DPL called Ian
Ian     Murdock   August  1993
Ian     Jackson   January 1998
$ awk '($2=="Perens") { print $3,$4 }' <DPL # When Perens started
April 1996

Shell (例如 Bash )也可以用來分析這種檔案。

嘗試下列例子

$ while read first last month year; do
    echo $month
  done <DPL
... same output as the first Awk example

內建指令 read 使用 “$IFS” (內部域分隔符)中的字元來將行分隔成多個單詞。

如果你將 “$IFS” 改變為 “:” ,你可以很好地使用 shell 來分析 “/etc/passwd”。

$ oldIFS="$IFS"   # save old value
$ IFS=':'
$ while read user password uid gid rest_of_line; do
    if [ "$user" = "bozo" ]; then
      echo "$user's ID is $uid"
    fi
  done < /etc/passwd
bozo's ID is 1000
$ IFS="$oldIFS"   # restore old value

(如果要用 Awk 做到相同的事,使用 “FS=':'” 來設定域分隔字元。)

IFS 也被 shell 用來分割參數擴展、指令替換和算術擴充套件的結果。這不會出現在雙引號或單引號中。 IFS 的預設值為 空格tab換行字元

請謹慎使用 shell 的 IFS 技巧。當 shell 將指令碼的一部分解釋為對它的輸入時,會發生一些奇怪的事。

$ IFS=":,"                        # use ":" and "," as IFS
$ echo IFS=$IFS,   IFS="$IFS"     # echo is a Bash builtin
IFS=  , IFS=:,
$ date -R                         # just a command output
Sat, 23 Aug 2003 08:30:15 +0200
$ echo $(date -R)                 # sub shell --> input to main shell
Sat  23 Aug 2003 08 30 36 +0200
$ unset IFS                       # reset IFS to the default
$ echo $(date -R)
Sat, 23 Aug 2003 08:30:50 +0200

下面的指令碼作為管道的一部分,可以做一些細緻的事情。


使用 find(1) 和 xargs(1),單行 shell 指令碼能夠在多個檔案上迴圈使用,可以執行相當複雜的任務。參見 節 10.1.5, “查詢檔案的語法”節 9.4.9, “使用檔案迴圈來重複一個指令”.

當使用 shell 互動模式變得太麻煩的時候,請考慮寫一個 shell 腳本(參見 節 12.1, “Shell 腳本”).



[1] 即使舊的 vim 也能夠啟動完全的 "nocompatible" 模式,透過使用 "-N" 選項啟動。