Cygwin: 微軟視窗底下的自由軟體環境 -- 洪朝貴 & 梁錫卿

(刊載於「資訊與教育」雙月刊, 1999/06)

洪朝貴
朝陽科技大學 資訊管理技術系 副教授
http://www.cyut.edu.tw/~ckhung/
O: (04) 332-3000 x4271/7123

梁錫卿
朝陽科技大學 資訊管理技術系 講師
http://itdc.im.cyut.edu.tw/~jerry/index.htm
O: (04) 332-3000 x7123

摘要

諸如 GNU/Linux [1] 或 FreeBSD [2] 等自由軟體的普遍應用將是未來數年內資訊界的主要趨勢之一。 甚至有國外的學者認為 UNIX 基本操作應納入中學基礎課程。 [3] 要學習使用自由軟體, 最直接的方式就是安裝這些自由作業系統。 但是部分使用者可能對於微軟視窗系統比較熟悉, 基於各種外在環境與個人因素, 無法安裝使用自由作業系統。 本文介紹 cygwin [4] 這套微軟視窗系統下的自由軟體, 讓這些使用者可以提早熟悉自由作業系統, 減輕將來轉換作業系統時的學習負擔。

簡介

[作者於 2002 年 2 月補充: 注意: 這一篇文章已經很老舊; 新的 cygwin 環境有一些很大的改變, 且 cygnus 公司已被 redhat 公司收購. 請以 redhat 公司網站上的說明為準. 請見 新文章.]

Cygwin 的程式原始碼公開, 而且受到「革奴大眾公有版權」 (GNU General Public License) 保護, 是標準的自由軟體, 而不是短期免費軟體。[5] Cygwin 目前仍處於 beta (b20) 版本, 但是用以在微軟視窗系統下預先學習 Linux 已經足夠。 它可以安裝在 Windows 95 或 98 上; 但安裝在 Windows NT 上會比較穩定。 以下以 Windows 95 為例。

安裝 Cygwin

首先從 cygwin 的首頁 [4] 循線可找到 下載站臺. 有兩個版本: 使用者版 (user.exe) 約 3 MB, 包含命令列操作程式 bash, 文字檔案處理工具 textutils, 系統檔案管理工具 fileutils 等等; 程式設計師版 (full.exe) 約 14 MB, 除了包含 user.exe 所有內容之外, 還包括 C/C++ 編譯器 gcc 以及跨平臺視窗設計語言 Tcl/Tk 等等。 取回 README, faq.txt 兩個文件說明檔, 以及 user.exe (不打算學程式設計的使用者) 或 full.exe, 在 MS Windows 底下執行。 安裝完畢後你的程式集選單上會出現一個 cygwin 程式, 即可開始執行。

第一次執行時會出現錯誤訊息, 顯示沒有 /tmp 目錄可用。 以下列出第一次執行時建議執行的步驟, 一併解決其他幾個不相關的小問題:

        ln -s $TMP /tmp
        ln -s `pwd`/H-i586-cygwin32/bin /bin

第一句是為了讓 bash 和 Windows 共用同一個暫存目錄, 第二句是為了讓系統目錄 /bin 指向所有可執行檔真正存放的地方, 其中 pwd 命令前後的倒引號是指將 pwd 命令 (印出目前工作目錄) 的結果代換成為 ln 命令列參數的一部分。 注意 pwd 後面的倒引號與其後的斜線之間沒有空格。 接下來以你熟悉的純文字檔案編輯器建立一個檔案 c:/.bashrc 例如:

        notepad c:/.bashrc

(注意: 請不要使用 Word, 因為 Word 內定存檔格式為二進位檔.) 在 notepad 內鍵入

        HOME=`pwd`
        export HOME

同樣要注意 pwd 外面的是倒引號。 每次以 cygwin 進入 bash 時, 系統會自動執行這個檔案裡面的所有 UNIX 命令, 有點類似 DOS/Windows 下的 autoexec.bat。 最後, 如果你安裝的是程式設計師版 (full.exe), 我們可以替兩個常用的視窗界面設計語言建立 symbolic link (類似 Windows 下的捷徑):

        cd /bin
        ls cygwish*.exe tix*.exe
        ln -sf cygwish80.exe wish
        ln -sf tix4180.exe tixwish

如果你在 ls 這個步驟所看到的檔案名稱有點出入, 那只是因為你所使用的版本比較新。 其後兩步的檔案名稱請隨著修改。至此, 安裝動作全部完成。

建議讀者取得任何 UNIX 使用書籍, 或閱讀網路上許多介紹 UNIX 命令的網頁。 [6] Cygwin 上面的 UNIX 命令並不完整, 但是最常用的命令大部分都有支援。

Bash 簡介與 UNIX 術語

進入 cygwin 程式之後, 你所面對的是 bash 這個程式。 這是一個 shell, 亦即一個類似 DOS 下 command.com 或共享軟體 4dos.com 的命令列操作界面。 一個 shell 最主要的工作就是擔任使用者與作業系統核心程式 (kernel) 之間的溝通界面, 而 bash 與 tcsh (可自 cygwin 的網頁取得) 則是 UNIX 下最常用的 shells。 兩者大同小異, 皆透過 GNU readline 界面 [7] 提供方便的鍵盤操作, 學會善用之後可以大幅度提升工作效率, 並可在其他許多命令列界面的自由軟體之下使用。

我們以一個命令實例說明命令列的操作其實與一般語言一樣自然, 甚至更簡單, 同時介紹一些常用術語:

  1. 剛開始學語文時, 由於詞彙不足, 而且不熟文法, 因此很難把心裡的意思完全表達出來, 我們只會說 "列出!"; 剛開始使用用命令列時, 我們也只會對電腦下達單獨的命令: "ls"。
  2. 之後我們學會動詞後面可以接受詞: "列出 cygnus.bat 這個檔案." 亦即 "ls cygnus.bat"。
  3. 接下來我們學會名詞前面可以加上形容詞: "列出根目錄底下的 bin 目錄底下的 gzip.exe 檔案" 亦即 "ls /bin/gzip.exe"。
  4. 同樣一個動作, 可以有大同小異的數種不同做法, 這就是使用副詞的時機了: "詳細列出根目錄底下的 bin 目錄底下的 gzip.exe 檔案" 翻譯成命令即是: "ls -l /bin/gzip.exe" 如此一來, 顯示資料不僅有檔案名稱, 還包含讀寫權限、檔案大小 ..。 等等資訊。 這裡的 -l 叫做 ls 命令的選項 (option), 它稍微修改 dir 命令的效果, 扮演副詞的角色。 先前不加任何選項時, ls 展現的是它內定 (default) 的行為。

Bash 本身認得一些命令, 例如 exit 表示使用者要離開 bash。 這類命令稱為 bash 的內建命令 (built-in commands)。 用 help 可以查閱 bash 有那些內建命令。 如果使用者下了 bash 本身不認得的命令, 它就到系統某些特定的角落去找看看有沒有與使用者所下命令名稱相同的可執行檔, 再把該執行檔載入記憶體執行。 這樣找到的命令稱為外部命令 (external commands), 例如 ls 就是。

有不少命令要從鍵盤讀入資料, 因此鍵盤稱為標準輸入裝置 (standard input 簡稱 stdin); 而有更多命令把結果印到螢幕上, 因此螢幕稱為標準輸出裝置 (standard output 簡稱 stdout)。 例如使用者下達 grep ea 命令後, 命令列上的提示字串 (command prompt) 就不會出現了, 因為 grep 命令正等著從 stdin 讀入資料。 從此以後使用者打入的每一列文字, grep 都會檢查是否包含有 ea 這個字串, 如果有的話就把該列原封不動地印出來。 Grep 不斷地讀寫, 直到使用者在一列的開頭單獨鍵入檔案結束字元 (end of file character) 為止。在 UNIX 系統下, eof 字元為 ^D; 在 cygwin 當中由於要配合 Windows/DOS 的習慣, 以 ^Z 作為 eof 字元。

有些時候命令印出的資料太多了, 在螢幕上不容易看, 使用者可以 (用 > 符號, 見下例) 叫 shell 把本來應該印到 stdout 上的資料改印到一個檔案裡面, 這個動作叫做輸出重新導向 (output redirection)。 例如 find . 命令會把目前目錄底下以及它的子目錄、孫目錄 ..。 底下所有檔案名稱列出。 如果我們下這樣的命令: find . > listing 就可以把結果放在 listing 這個檔案裡面。 同樣地, bash 也提供輸入重新導向 (input redirection)功能, 使用者用 < 符號可以讓本來希望從 stdin 讀入資料的命令不自知地改從使用者指定的檔案中讀取資料。

使用者可以同時開啟好幾個 cygwin 視窗。 用 UNIX 的術語來說, 每個視窗叫做一個控制臺 (tty)終端機 (terminal)。 不僅如此, 使用者可以在一個 tty 之內同時做好幾件事情。 每件正在進行當中的事情叫做一個程序 (process)。 因為一個 tty 只有一個 stdin, 所以它只能提供一個程序 在前景 (foreground)執行。 其他程序或者在背景 (background)執行, 或者在休眠 (sleep) 狀態。 像 find . > listing 這樣要花很多時間執行的命令, 使用者可以用 find . > listing & 這樣的方式把它丟到背景去執行。 使用 jobs 這個內建命令可以看到這個 tty 內有那些程序正在背景執行或正在休眠; 使用 ps 這個外部命令可以看到所有正在執行的程序 (不分 tty, 也不論是否在前景)。

這些術語在各類 UNIX 書籍或線上文章/手冊當中都經常出現, 以上簡略的介紹旨在邀請讀者體認: 這些其實都是很自然的觀念; 我們只不過是把這些自然的觀念冠上術語而已, 並非 UNIX 系統下高深的學問。 熟記這些術語對於閱讀手冊有非常大的幫助。

文字檔案與「軟體工具箱哲學」

UNIX 系統設計當中一個最基本的精神就是模組化: 每個命令專門只做一件事情, 把這一件事情盡量做好, 並且提供與其他命令很好的溝通管道。 初學者往往會覺得單獨的 UNIX 命令沒有什麼用處; 但是隨著時間與經驗的累積, 這些命令將產生相乘而非相加的效果, 大幅度提升使用者的生產力。 用不太精準的說法作比喻, 同樣學習了 5 個, 5 個, 再 5 個命令, 如果這些命令之間有很好的正交性 (orthogonality), 那麼使用者可以完成的事情將有 125 種而非 15 種。 這種強調模組化/正交性的原則, 也有人稱之為「軟體工具箱哲學」。 [8] 這樣的文化/哲學與微軟視窗系統底下的文化/哲學是迥然不同的, 也因此使用者要有非常不一樣的學習方式與學習重點。 以下是對於初學者的一些建議。

  1. 習於處理純文字檔、用純文字檔儲存資料
    UNIX 下的 cat, tr, cut, paste, join, sort, uniq, diff, comm, ..。 等等文字檔案處理工具, 正是上述軟體工具箱當中最基本的元件; 如果你的資料檔案存成一些特殊的二進位格式, 就只有提供該檔案格式的軟體可以處理了。
  2. 熟悉 regular expression 觀念
    我們往往需要搜尋某類字串; regular expression 就是用以描述「某類字串」而不只是「某個字串」的工具。 許多重要的工具程式都支援這個觀念, 像是 grep, egrep, sed, vi, perl, ..。等等。 例如 sed 's/[0-9]\+//g' xxx 命令可以印出 xxx 檔案內容, 但是把其中所有的數字都去掉。 這裡面 [ ] - \+ 等等都是 regular expression 的特殊符號。
  3. 記憶很多命令不是重點, 學習如何組合命令才是重點
    組合命令的能力才是真正讓 UNIX 使用者發揮所學的利器。 最常用的組合方式有二: 其一是管線 (pipe), 以 | 表示, 把一個原本應該印到 stdout 的命令和一個原本應該從 stdin 讀入資料的命令串聯起來, 將前面命令的輸出送給後面命令作為輸入。 例如 ps aux | grep '^ckhung' 命令把目前系統內的所有程序全部列出, 但是因為 ps 的輸出經過 grep 的處理, 最後真正印出的只有以 ckhung 字串開頭的那幾列。 其二是命令結果代換 (command substitution), 以倒引號表示, 把前一個命令原本應該印到 stdout 的資料印到下一個命令的命令列去, 變成它的命令列參數。 例如 mailx `cat friends` 中 cat 命令把 friends 檔案的內容印到 mailx 的命令列上, 仿彿我們在下達 mailx 命令時, 把 friends 檔案的內容用手抄到 mailx 後面作為參數一樣。 Find 是一個經常使用在這種場合的命令, 值得花時間學。

讀者掌握這些原則之後, 逐漸就會發覺在 UNIX 命令列底下, 有限的知識配合上組合的巧思可以解決許多從來沒有學過的問題, 例如系統管理員如何把屬於使用者 ckhung 的所有程序全部中止掉呢?

        kill ` ps aux | grep '^ckhung' | cut -c 9-14 `
又如, 或許目前目錄所在硬碟分割快滿了, 我們如何把目前目錄底下 (及其子目錄、孫目錄 ..。底下) 最大的廿個檔案搬移至 /overflow 目錄下, 並建立 symbolic link 以使得這廿個檔案原來所在的目錄底下仍舊可以找到這些檔案呢?
        ls -l `find . -type f` | sort -n +4 | tail -20 | cut -c 55- > listing
        mv `cat listing` /overflow
        perl -pe 's#^(.+)/([^/]+)\n$#ln -s /overflow/$2 $1\n#' listing | bash
這就好像我們或許從來沒有學過 (3+2)*(7-1)-(3-1)*(1+2) 這個式子的答案是多少, 但是只要是會四則運算的人都可以算出答案一樣。 這樣的文化是否與大家熟悉的滑鼠文化大異其趣呢? 這也就是筆者一直強調的「讓知識發揮相乘效果」了。 使用電腦的過程當中, 經常會出現這類以圖形界面 (GUI) 進行非常吃力, 但又沒有複雜到需要寫程式來完成的工作。 資訊從業人員所學的技術, 究竟是靜態的抑或是動態、有擴展性的; 企業內的資訊部門是否能夠以既有的工具在最短的時間內完成非常規性的工作, 從這裡可以看出一些端倪。

跨平臺程式研發工具

本節的對象是程式設計師, 也就是當初下載 full.exe 的讀者。 這個版本的 cygwin 裡面有幾個重要的跨平臺程式研發工具, 包含符合 ANSI 標準的 C/C++ 編譯器 gcc 與 g++, 除錯程式 gdb, 圖形界面 (GUI) 研發語言 Tcl/Tk, 以及 Tcl/Tk 的數個擴充程式 Tix (高階視窗元件擴充), Incr Tcl/Tk (物件導向擴充), expect (交談式程式批次化擴充) 等等。 本文僅就 gcc/g++ 與 Tk/Tix 的使用做非常簡略的介紹; 參考資料所列的網址上可查得更豐富的資訊。[9]

首先用 notepad 建立一個 C 程式檔, 內容可以是任何簡單的 C 程式, 例如最常見的 hello.c:

        notepad hello.c
在 notepad 中鍵入
        #include <stdio.h>
        int main(void)
        {
            printf("hello, world!\n");
        }
並存檔後, 即可編譯:
        gcc -Wall -o hello hello.c
最後可以 hello 命令執行。 至於除錯程式 gdb 的使用, 請參考網頁簡介。[10]

接下來我們看 Tk 與 Tix。 如果讀者按照上文步驟安裝的話, 應該可以如下執行範例程式:

        $HOME/share/tk8.0/demos/widget
        $HOME/share/tix4.1/demos/widget
版本名稱可能略有不同, 請視狀況修改。 接著我們執行 wish 命令, 螢幕上出現兩個新的視窗。 我們在文字視窗內鍵入:
        button .b -text "Good morning!"
        pack .b
圖形視窗上隨即出現一個小按鈕。 Tixwish 是 wish 的擴充, 除了 wish 可以使用的命令之外, 還有許多其他高階視窗元件。

最後, 這裡列出幾個 cygwin 當中沒有包含的常用跨平臺自由軟體:

  1. 在 Tcl/Tk 的主要網頁上另外有 MS Windows 版的 Tcl/Tk 可執行檔, 不包含其他擴充程式, 但是有豐富的文件。 建議讀者先找到最新版本再下載。[11]
  2. 上文所提到的 perl 程式由於檔案過大, 並不包含在 cygwin 當中。 [12]
  3. PostgreSQL 是一個主從式架構的物件導向關聯式資料庫 (object relational database), 可以在 Windows NT 底下使用。 [13]

DIY 滿足自己的軟體需求

Cygwin 本身所附的只是最基本的命令與工具; 經過一段時間之後, 使用者必然會有其他的軟體需求。 只要使用者願意花一些時間上網路尋找, 一定會發覺你的需求多半已有其他人提出來過。 以下從最簡單的方式開始, 列出幾個解決方案:
  1. Cygnus 把所有使用者所貢獻的程式搜集在一個網頁裡面。 [14] 這裡有另一個常用 shell tcsh, 文字瀏覽器 lynx, 編輯器 joe, 類似 Norton Commander 的 Midnight Commander, 文字模式試算表 bc, 品質媲美 Photoshop 的 GIMP, ..。等等。
  2. 如果你在 UNIX 系統下有一個常用的自由軟體, 也想拿來 MS Windows 下使用, 可以從該軟體的 UNIX 版文件下開始找起, 往往可以從其首頁找到 MS Windows 版的可執行檔。 例如非常適合用以學習微積分與線性代數的數學函數繪圖器 gnuplot 和矩陣計算機 rlab 就是。[15] 如果沒有現成的可執行檔, 也可以取得它的程式原始碼, 把它拿來 cygwin 底下編譯, 成功以後記得向全世界報告你的成果。 聽起來很複雜; 其實對於大部分文字模式下的中小型軟體而言這是輕而易舉的事, 因為大多都附有自動設定組態與自動編譯所需的程式 (configure 與 makefile)。 別人不曾做過並不表示很困難, 可能只是別人沒有需求而已。 這不僅可以滿足自己的軟體需求、提升自己的技術能力, 同時可以服務社會大眾, 並借此留名, 何樂不為呢? 另外, 讀者從這裡也可以看出程式原始碼開放的重要性了。
  3. 如果編譯失敗, 甚至找不到你要的自由軟體, 可以上網路相關的 newsgroup 尋求幫助。何謂相關的 newsgroup 呢? 那就要視你的應用程式而定了, 如果你做到這一步, 相信也已經看過足夠的文件, 可以找到相關的資訊了。 或者也可以從「主要 newsgroup 目錄」找起。[16]

結論

GNU/Linux 不只是一個作業系統, 而是一個新的「贈予文化」的產物 (更確切地說, 是一個強調互助互利的舊文化的重生)。[17] 同樣地, 使用者要學習 GNU/Linux 及其上的自由軟體, 眼光必須超越技術上的差異, 深入體認到學習方式與心態的不同。 筆者正在搜集視窗系統上自由軟體的網址, 盼望讓國內的讀者可以提早接觸這樣的文化, 適應資訊產業未來的變化。 [18] 更盼望國內有心的教育單位或事業協助映射國外的自由軟體網站或移植既有軟體, 這不僅是對國內資訊教育的一大貢獻, 更是學校或企業展現特色的機會。

參考資料

  1. http://linux.cis.nctu.edu.tw/
  2. http://freebsd.csie.nctu.edu.tw/
  3. http://linuxtoday.com/news_story.php3?ltsn=1998-12-24-003-05-OP
  4. http://sources.redhat.com/cygwin/
  5. http://www.cyut.edu.tw/~ckhung/a/c_83.php
  6. http://www.cyut.edu.tw/~ckhung/b/gnu/
  7. http://www.cyut.edu.tw/~ckhung/b/gnu/basictool.php#readline
  8. 請在 Linux 或 FreeBSD 環境下, 下達命令 info -f textutils 參考相關文件, 或見網頁上不太完整的節錄版: http://penguin.im.cyut.edu.tw/cgi-bin/info2www?(textutils)
  9. http://www.cyut.edu.tw/~ckhung/l/index.php#fs_cat
  10. http://www.cyut.edu.tw/~ckhung/b/mi/gdb.php
  11. http://www.scriptics.com/software/8.0.html#Download Binary
  12. ftp://dongpo.math.ncu.edu.tw/perl/CPAN/ports/win32/Standard/x86 找 perl*-bindist*-bc.* 等檔案。
  13. http://members.tripod.com/~kevlo/postgres/postgresinstall.txt
  14. http://sources.redhat.com/cygwin/ported.html
  15. ftp://ftp.dartmouth.edu/pub/gnuplot/ http://rlab.sourceforge.net/
  16. http://www.cyut.edu.tw/~ckhung/l/mr/index.cgi?major=RTFM&path=news/answers
  17. http://www.catb.org/~esr/writings/cathedral-bazaar/
  18. http://www.cyut.edu.tw/~ckhung/l/index.php#fs_win
  19. 筆者在近完稿時發現 Paul Dunne 寫了許多介紹 GNU/Linux 的文章: http://dunne.home.dhs.org/linux.html 其中也有一篇包含如何在 MS Windows 底下使用 cygwin: http://dunne.home.dhs.org/articles/hex.gnu-win32
  20. Linux HOWTO 文件中的 DOS-Win-to-Linux-HOWTO 同樣針對熟悉 MS DOS 與 Windows 的讀者, 直接切入 Linux (而不經由 cygwin), 但是裡面所提到的許多觀念都可以在 cygwin 的 bash 下練習。 http://metalab.unc.edu/LDP/HOWTO/DOS-Win-to-Linux-HOWTO.html