認識命令列


進入命令列

以前電很貴的時代, 一部電腦主機會連上好幾副「鍵盤 + 螢幕」 (那時還沒有滑鼠) 讓很多人可以共用一部主機 [CPU+記憶體+硬碟]。 每付「鍵盤 + 螢幕」稱作一個終端機 (terminal)。 現在電腦越來越便宜, 速度越來越快, 不但可以一人一機, 而且一個螢幕可以當好幾個用 -- 例如一部 Linux 電腦可以提供 6 個虛擬終端機 (virtual terminal), 方便我們同時交待好幾件事情給電腦做。 因為每個 VT 都分別獨自作業, 彷彿是 6 付獨立的「鍵盤 + 螢幕」一樣, 所以現在我們用 ctrl-alt-F1 切換到 VT1 時, 要重新登入一次. (ctrl-alt-F2 到 ctrl-alt-F6 是其他 VT; 而 ctrl-alt-F7 是 X Window 圖形環境) 等一下螢幕上如果出現亂碼, 那是因為這 6 個 VT 不支援中文。 請小心抄下這個指令 (注意: 空格與大小寫都很重要), 叫它不要用中文印錯誤訊息:
unset $(env | grep -i zh_TW | sed 's/=.*//')
也可以切回 VT7, 在 X Window 圖形環境下從 toolbar 或主選單當中叫出「終端機」來練習。

我們下幾個簡單的 命令 (command) 來了解一下命令列的操作. 每下一個命令之後要按 Enter 鍵, 電腦才會執行. 還沒有按 Enter 之前, 你大可以在 命令列 (command line) 上面用 Backspace 及左右鍵來修改打錯的命令, 甚至可以用上箭頭把過去下過的命令叫出來修改, 或用 readline 介面提供的更多功能鍵來修改你的命令.

  1. date 看看今天的日期和現在的時間.
  2. cal 看看這個月的月曆.
  3. ls 看看目前目錄下有那些檔案及子目錄.
  4. echo 印一列空白列 (蠻無聊的; 不過以後會有用).
  5. exit 結束工作, 離開命令列模式 (其實用 ctrl-d 更方便).

命令列上的參數與選項

我們的自然語言 (中文英文等) 裡面, 有些動作需要受詞, 例如: 消遣 (誰?), 吃 (什麼東西?), 唱 (那一首歌?) ... 同樣地, 有些命令需要 參數/引數 (arguments), 像下面例子當中的 cal 有兩個參數: 7 與 2000, 而 ls 有一個參數: /usr/doc.

  1. cal 7 2000 顯示公元兩千年七月的月曆.
  2. ls /usr/doc 看看根目錄下的 usr 子目錄下的 doc 子目錄裡面有什麼東西.
  3. echo 'good morning!' 複誦一遍 'good morning!'.
  4. cp abc.txt def.txt 複製一份 abc.txt 這個檔案, 把新檔叫做 def.txt.
  5. finger ckhung 看看使用者 ckhung 的資訊.
  6. sleep 3 睡 3 秒鐘.
  7. look liter 查看以 liter 開頭的英文字有那些.

在自然語言裡面, 同一個動作可以有不太相同的表達方式, 我們用副詞來表達, 例如:「慢慢」跑, 「小心」拿, 「簡單」報告, 「狼吞虎嚥地」吃, 「充滿感情地」唱 ... 同樣地, 有些命令可以接受 選項 (options) 並會因此而用不太一樣的方式來顯示結果, 例如:

  1. uname -a 「完整地」顯示有關這部機器的資訊.
  2. who -q 「簡要地」顯示有多少人在線上.
  3. ls -la 「詳細地」而且「完整地」顯示目前目錄下有什麼東西. 這句話其實是 ls -l -a 的簡寫.
  4. echo -n 'hello' 「單純地」複誦 "hello" (最後不要換列).

作業: 試試看上面的例子如果沒有加 options 會有什麼效果? 如何叫電腦顯示 /etc/rc.d 目錄下所有檔案目錄的大小及修改日期?

Shell 的角色

[命令列的角色]

有一些大機關 (例如中華電信) 入門處有一個服務檯, 主要的工作就是方便民眾在不太清楚要找誰服務的情況下, 將民眾交待的工作分派給機構內負責特定業務 (查帳? 申請新門號? 補繳通話費?) 的專業負責人. 同樣地, 我們在命令列上交辦給電腦的工作, 也都會先由 shell 來幫我們分派給其他程式去執行. 這個 shell 像是入門處服務檯的服務人員一樣, 先是負責印出 提示符號 (shell prompt 或 command prompt) 告訴使用者: 電腦已處理完上一個命令, 你可以開始指示下一個命令.

如果是很簡單, 很基本的命令 (想像你要找出口, 或者要找廁所, 總不需要再找一位專家來幫忙吧?) 像這樣的事情, shell 就不需要到系統去找其他程式來幫忙, 而是自己直接就完成了. 這類命令叫做 shell 的 內建命令 (built-in command) 例如 exit (離開) 和 echo (複誦) 都是 built-in commands. 又有些事情, 與 shell 本身具有密切的關係, 交由其他任何人來處理都不恰當 (想像你要問: 「今天早上到現在為止已有多少人前來服務處問問題?」), 這也是由 shell 的內建命令來完成, 例如 history.

然而大部分有用的業務還是要有專人來負責. 當 shell 發現你敲進去的是它自己無法直接處理的 外部命令 (external commands) 時, 它就會到系統各處去找適當的程式來執行. 上面的例子大部分都是外部命令. 下 type exittype cal 就可以看出 exit 是內建命令, 而 cal 則是外部命令.

因為整部電腦的資源都可以透過 shell 來使用, 它像是電腦與使用者之間的窗口, 像是電腦的「殼」一樣, 所以叫做 shell. 先前我們透過 X Window 的 圖形介面 (Graphical User Interface, GUI) 來執行許多程式, 固然很方便, 但是學「選單的擺設/位置」只是死的知識, 換一套選單你就傻眼了. 例如你去用別人的電腦, 他可能自己修改過選單, 甚至使用不同的 視窗管理員 Window Manager, 從他的選單裡面找不到你熟悉的應用程式, 這時候會簡單的命令列操作就很有用了. 請回到 X Window 下, 打開一個中文終端機, 下 xpaint 命令, 叫出我們先前用過的塗鴉程式; 再開另外一個中文終端機, 下 pydict 命令, 叫出英文字典. 即使你在一個不熟悉的圖形環境, 只要可以打開一個終端機, 照樣可以工作.

程序管理的概念

上面的例子有點麻煩, 每次為了使用一個應用程式, 就需要開兩個視窗. 那是因為一個終端機內每次只能夠有一個 前景程序 (foreground process) 在執行, 要等它執行結束 (例如你選 xpaint 的 file 選單內的 quit), shell 才會再印出 提示符號, 讓你輸入下一個命令. 如果當初下命令時, 我們把它丟到背景去執行, 就可以叫 shell 馬上回來接受下一個命令了 (請抄下終端機印出來的兩個數字, 例如 [1] 908): xpaint & 句中的 & 符號, 表示要把 xpaint 變成一個 背景程序 (background process) 來執行. 使用背景執行的方式, 我們就可以只開一個終端機, 卻同時執行很多 程序 (processes). 注意: 「程式」指的是靜態的可執行檔, 例如用 type xpaint 可以看出 xpaint 的可執行檔放在 /usr/X11R6/bin/ 目錄底下; 而「程序」指的則是動態的, 從磁碟機裡活起來, 正在執行的程式分身. 一個靜態的程式可以同時產生好幾份動態的程序: 請再下幾次 xpaint & 然後用 ps 命令看一下 xpaint 有幾個分身在跑.

有關程序管理的詳細說明, 請參考 多工環境 這篇講義. 對初學者而言, 最重要的是 ps x 命令. 這可以看出目前以你的名義正在執行的程序有那些. 大致說來, 每個視窗會有一個對應的程序 (不完全正確的說法); 另外還有一些奇奇怪怪的程序你可以暫時不要理它. 請從桌面上的工具列與選單內打開所有你曾經學過的應用軟體, 然後用 ps x 再看一次, 並抄下每個應用程式的名字. 下次你遇到一個不熟悉的 GUI 介面, 就不會束手無策了.

另一個重要命令是 kill, 作用是把程序終止掉. 當初用 & 把程式丟到背景去執行時, 印出來的第二個數字叫做 PID (程序代號). 以上面的例子而言, 你可以下 kill 908 把最早的 xpaint 程序 "作掉", 效果相當於按 xpaint 視窗右上角的 icon, 把視窗關掉. 有些情況無法用按 icon 的方式終結程序, kill 就很有用了.

為什麼要學命令列?

組合的力量