我的外部記憶區

2006年5月8日星期一

Unix痛恨者手冊:第三章:文檔

文檔什麼文檔

「使用UNIX進行操作系統教學的一個好處是,學生的書包能裝下所有的UNIX源代碼和文檔。」
—— John Lions, 新南威爾士大學,1976年在談論UNIX版本6時說的一段話。
多年以來,有三個獲得UNIX有關知識的簡單途徑:
閱讀源代碼寫一個自己的UNIX給寫UNIX的程序員打電話(或是發email)
和荷馬史詩一樣,UNIX被口頭傳誦著。如果不成為內核黑客,你就不可能是一個嚴肅的UNIX用戶——或者至少應該在身邊有個觸手可及的內核黑客。那個確實存在的文檔——man手冊——不過是一些已經知道自己在做什麼了的人所收集的一些備忘錄。UNIX的文檔是這麼簡潔,你能在一下午讀完它。
[編輯]
在線文檔

man工具是UNIX文檔系統的基礎。man接受你輸入的參數,找到相應的文檔文件,把它輸出到nroff(還包括一些地球上沒有其他地方使用的一些文本格式宏),最後結果被發送到pg或more。
起先,這些零碎文檔被叫做」man頁」(man pages),因為這些文檔多為一頁左右(多數情況是少於一頁)。
man對於那個時代是個不錯的玩意,但那個時代早已一去不復返了。
多年來,man系統不斷發展成熟。值得稱讚的是,它並沒有像UNIX的其他部分一樣搞得代碼混亂程序難懂,可是它也沒變得更有用。事實上,在過去的15年中,UNIX的文檔系統只有了兩處改進:
catman. 程序員曾「驚喜地」發現除了nroff格式以外,他們還能存儲處理過的文檔文件,這樣文檔調出的速度就更快了。 對於今天的快速處理器,catman似乎不那麼需要了。
但是許多nroff處理過的文檔文件仍然佔據著用戶的幾兆磁盤空間。makewhatis, apropos和key (最終構成了man –k功能)是一個對man手冊進行索引的系統,這樣即使不知道程序的確切名字也能進行查詢。
與此同時,電子出版的勢頭早已超過了man手冊。使用今天的超文本系統你能用鼠標從一篇文章跳到另一篇文章;與之相比,man手冊僅僅在末尾提供」SEE ALSO」一節,讓用戶自己再man下去。在線文檔的索 引功能又是如何呢?今天你可以買到CD-ROM上的牛津英語詞典,它對其中的每一個詞都加了索引;可是man手冊還是僅僅對命令名和描述行進行索引。今天甚至連DOS都提供了有索引的超文本文檔。可是man手冊還是採用適合DEC打印終端的80列66行的格式。
公平點說,有些廠商是在看不下去,提供了自己的超文本在線文檔系統。在這些系統上,man手冊走到了進化的盡頭,常常不是過時了,就是根本不存在。
[編輯]
「我知道它就在這裡,可就是找不到」

對於今天還在使用man手冊的人來說,最大的問題是告訴man你要的man手冊就在那裡。在以前,查找man手冊是很容易的:全都在/usr/man下頭。後來man手冊按章節分成了不同的目錄:/usr/man/man1, /usr/man/man2,/usr/man/man3等等。有的 系 統甚至把「本地」man手冊也放在/usr/man/man1下。
當AT&T發佈系統V的時候,情況變得費解了。/usr/man/man1目錄變成了/usr/man/c_man,似乎字母比數字更好記。在有些系統上,/usr/man/man1變成了/usr/local/man。那些銷售UNIX應用程序的公司開始建立自己的man目錄。
最終,伯克利修改了man程序使得它能對環境變量$MANPATH中指定的一系列目錄進行查找。這是個偉大的想法,只有一個小毛病:它不工作。(以下省略100字, 因為我太懶了,內容也有些太過時了,Linux上的 man 還是不錯的,除了無法獲得shell內部命令的man手冊,當然,man bash是一個選擇
-- me)。
[編輯]
這個就是內部文檔?

一些大的UNIX工具也提供自己的文檔。許多程序的在線文檔是一行叫人費解的 「使用」(usage)說明。下面是awk的「使用」說明:
% awk
awk: Usage: awk [-f source | 『cmds』] [files]
是不是挺有用的?複雜一些的程序有著更深入的在線文檔。不幸的是,它們有時候描述的似乎不是你正在運行的程序。
Date: 3 Jan 89 16:26:25 EST (Tuesday)X-Virus: 6From: Reverend Heiny To: UNIX-HATERSSubject: A conspiracy uncovered (陰謀被揭露了)

經過幾個小時的專心研究,我得出了一個重要的結論:

UNIX是狗屎 (UNIX sucks)

現在,你可能覺得很驚訝,但這是事實。這項研究已經被遍佈全球的研究人員所證實了。

更為重要的是,這不僅僅是攤狗屎,而是又稀又粘的臭狗屎,是大寫的臭狗屎。看看下面這個例子,你就知道了:

toolsun% mail
Mail version SMI 4.0 Sat Apr 9 01:54:23 PDT 1988
Type ? for help
「/usr/spool/mail/chris」: 3 messages 3 newN 1 chris Thu Dec 22 15:49 19/643 editor saved 「trash1」N 2 chris Tue Jan 3 10:35 19/636 editor saved 「trash1」N 3 chris Tue Jan 3 10:35 19/656 editor saved 「/tmp/ma9」& ?Unknown command: 「?」&
什麼樣的系統環境(特別是這個到了能開車、投票、喝啤酒年齡的傢伙)會拒絕一個它讓使用的命令?
為什麼用戶手冊是如此脫離現實?
為什麼這些神秘的命令是這麼和功能不符?
我們不知道Heiny的問題是什麼;和我們上面提到的一些問題一樣,這個bug似乎已經被修正了。或者說,它被轉移到了其他程序中。
Date: Tuesday, September 29, 1992 7:47PMX-Virus: 6From: Mark Lottor To: UNIX-HATERSSubject: no comments needed (無需多說)

fs2# add_clientusage: add_client [options] clientsadd_client -i | -p [options] clients-i interactive mode – invoke full-screen mode

[還有一些選項,這裡省略了]

fs2# add_client -i

Interactive mode uses no command line arguments
[編輯]
如何得到真正的文檔

實際上,UNIX最好的文檔是經常用strings處理程序二進制代碼。使用strings你能得到所有程序中定死了的文件名,環境變量,未公開的選項,怪異的錯誤信息等等。比如,如果你想知道cpp是如何去查找頭文件的,你最好使用strings而不是man:
next% man cpp

No manual entry for cpp.

next% strings /lib/cpp | grep //lib/cpp/lib//usr/local/lib//cppnext%

嗯…別著急

next% ls /libcpp* gcrt0.o libssy_s.acpp-precomp* i386/ m68k/crt0.o libsys_p.a posixcrt0.onext% strings /lib/cpp-precomp | grep //*%s*///%s/usr/local/include/NextDeveloper/Headers/NextDeveloper/Headers/ansi/NextDeveloper/Headers/bsd/LocalDeveloper/Headers/LocalDeveloper/Headers/ansi/LocalDeveloper/Headers/bsd/NextDeveloper/2.0CompatibleHeaders%s/%s/lib/%s/specsnext%

我真笨。NEXTSTEP的cpp使用了/lib/cpp-precomp。你不可能在man手冊中發現這些。

next% man cpp-precomp

No manual entry for cpp-precomp.
OK. 這一切究竟是因為什麼?這一切究竟是從何而來?下回分解。
上回書說到源代碼是最好和唯一的文檔,根本原因是因為UNIX是...
給程序員用的,不是用戶
別因為UNIX蹩腳的文檔而責怪Ken和Dennis。 UNIX剛開始建立文檔時並沒有遵守業界流行的文檔標準,一些bug和潛在的陷阱,而不是程序的功能,被記錄了下來,這是因為讀這些文檔的人往往就是UNIX系統開發者。對於許多開發者來說,man手冊不過是收集bug報告的地方。那些針對初級用戶、程序員和系統管理員提供文檔的觀念是新玩意。可悲的是,由於70年代建立的UNIX文檔系統,這一觀念實現的並不是很成功。
UNIX世界認識到了這些文檔方面的現狀,但並不覺得有什麼大不了的。《UNIX生活》很客觀地說明了UNIX對於文檔的態度:
UNIX源代碼是最好的文檔。畢竟,這是系統用以決定該如何運行時所參照的文檔。文檔用來解釋代碼,經常是一些不同的人在不同的時間寫成的,而這些人往往不是寫代碼的人。你應該把這些文檔看作是指南。有時候這些文檔不過是些期望而已。
但是,更一般的做法是去源代碼中尋找未被文檔化使用方法和功能說明。有時候你會發現一些文檔中記錄的功能其實並沒有被實現。
這還只是針對用戶程序。對於內核,情況就更為糟糕了。直到最近,還沒有廠商提供的設備驅動編寫和內核級調用函數的文檔資料。有人開玩笑說:「如果你覺得需要閱讀關於內核函數的文檔,那麼很可能你本來就不配使用這些函數。」
真相恐怕更為邪惡。之所以沒有內核文檔是因為AT&T把它的代碼看成是商業機密。如果你想寫一本說明UNIX內核的書,那麼你就等著入被告席吧。
[編輯]
源代碼就是文檔

命裡注定,AT&T的計劃弄巧成拙了。由於沒有文檔,瞭解內核和應用程序的唯一途徑就是閱讀源代碼。結果是,UNIX源代碼在在最初的20年中被瘋狂的盜版。咨詢人員,程序員和系統管理員去搞UNIX源代碼並不是為了重新編譯或製作出售自己的UNIX版本,他們需要文檔,而源代碼是唯一的選擇。UNIX源代碼從大學流向周邊的高科技公司。這當然是非法的,但是情有可原:UNIX廠商提供的文檔不夠用。
這並不是說源代碼中有什麼值錢的秘密。所有讀過UNIX代碼的人都被下面的一行粗暴註釋驚呆過:
/* you are not expected to understand this */ (/* 沒指望你能明白 */)
儘管這行註釋最開始出現在UNIX V6內核中,但是幾乎所有的原始AT&T代碼都差不多,其中充滿了內聯手動優化和怪異的宏。寄存器變量被冠以p, pp和ppp這類的名字。「這個函數是遞歸的」這樣的註 釋 似乎表明遞歸調用是什麼難理解的概念。事實上,AT&T在文檔方面好為人師的態度只不過是其寫代碼的馬虎態度的一個反映。
要識別一個蹩腳手藝人其實很簡單:你會看到裂縫上的油漆,一個接一個的補丁,所有東西被膠帶和口香糖勉強湊合在一塊兒。必須承認:如果想從頭建立和重新設計什麼,必須要多思考,多下功夫。
Date: Thu,17 May 90 14:43:28 -0700X-Virus: 6From: David Chapman To: UNIX-HATERS

這是man man中的一段,挺有意思:

DIAGNOSITICS

如果你使用-M選項而且給出的路徑並不存在,那麼輸出的錯誤信息可能有點兒不對。比如/usr/foo/目錄不存在,如果你運行:

man –M /usr/foo ls

那麼你得到的錯誤信息是「No manual entry for ls」(「沒有ls的手冊記錄」)。正確的錯誤信息時告訴你目錄/usr/foo不存在。

有寫這段說明的功夫,恐怕足夠修改這個bug了。
[編輯]
無言UNIX:課程設置建議

Date: Fri, 24 Apr 92 12:58:28 PTX-Virus: 6From: cj@eno.corp.sgi.com (C J Silverio)Organization: SGI TechPubsNewsgroups: talk.bizarreSubject: UNIX Without Words (無言UNIX)

[在一場關於文檔無用論的激烈辯論中,我提出了下面這個建議。我膽子小,所以現在才敢公開,供大家參考。]

UNIX Ohne Worter (不會翻 – me)

我被這裡散步的文檔無用論觀點深深折服了。事實上,我進一步認為文檔就是毒品,我對於它的依賴性是人為造成的。在專業人士的幫助下,我想我能夠戒掉它。

而且,我的良心告訴我不能再靠販賣這種毒品為生了。我決定回到數學研究院脫胎換骨,徹底從這個寄生蟲一樣的職業中脫身。

雖然下面這份文檔似乎表明了我中毒有多麼深,可我還是覺得下一版SGI中應該把它提供給用戶。這不過是暫時之舉,以後會把它搞掉的。

這是我的建議:

標題:「無言UNIX」

對像:UNIX新手

簡介:提供在沒有文檔條件下使用UNIX的通用策略。展示在沒有文檔條件下摸清任何操作系統的通用原則。

內容:

介紹:「無文檔」哲學簡介為什麼手冊是惡魔為什麼man手冊是惡魔為什麼你還是應該讀這份文檔「這將是你讀的最後一份文檔!」

第一章:如何猜測可能存在哪些命令

第二章:如何猜測命令名

UNIX的怪異縮略命名法案例:grep

第三章:如何猜測命令選項

如何破解怪異的使用說明案例:tar如何知道什麼時候順序是重要的案例:fine

第四章:如何知道運行正確:沒有消息就是好消息

從錯誤中恢復

第五章:口頭傳統:你的朋友

第六章:如何獲得和維持一個活生生的UNIX高手

如何餵飽你的高手如何讓高手高興提供全部新聞組連接的重要性為什麼你的高手需要最快的計算機免費可樂:高手的長生不老藥如何保持高手身體健康高手什麼時候睡覺?

第七章:常見疑難:你的高手不理你了

識別愚蠢的問題如何安全地提出愚蠢問題

第八章:如何承受壓力

如何對待失敗

註:可能只有6、7章才是真正需要的。是的,這才是正路:我把它稱為「UNIX高手馴養指南」。

OK, 再也沒有文檔了。下回書將帶你進入sendmail的美好世界,為什麼「使用sendmail的感覺和得了花柳病一樣。」?下回分解。

標題: 第八章 csh, pipes和find (part 1)

UNIX演義又開始了,本來這回書要表一表sendmail和花柳病的關係,不過sendmail似乎已經從良了,從良妓女比貞節烈女對我們民族的貢獻要大得多,所以不想再找她麻煩了,對妓女發展史和性病鬥爭史感興趣的,我們可以私下交流。

作為程序員而不是妓女的你,可能對UNIX的編程環境更感興趣,所以這一節中介紹一下UNIX Shell的歷史。我GPL,你沒花錢,所以只能任我擺佈,我上什麼你就吃什麼,不 要廢話。

GPL的好處在於你不必為自己的工作負責,也不必對用戶負責,所以sourseforge上充斥著良莠不齊的自由項目。我希望我的心上人也能理解這一點,這一切的開始並不是為了什麼價值、責任、過去或是未來,這一切甚至不是為了現在,這一切只是源於passion。

在大海吐出的每個泡沫中在上班路上吸入的每一粒塵埃中在過去歲月的每一次陣痛中在一次一次睡去和醒來中在天氣預報和新聞聯播中在七月流火和九月授衣中在七月長生殿七日中在矢車菊和芙蓉中在長繩紀日中在天長地久中在你身邊在我心裡無須尋求意義

第八章 csh, pipes和find

強有力的工具給強有力的傻瓜

「有些操作系統從沒有被好好計劃,以至於只好用反芻的噪音來命名它的命令(awk, grep, fsck, norff),我想到這個就反胃。」

—— 無名氏
UNIX所謂的「強大工具」是個騙局。 這不過是UNIX為了那些東拼西湊的命令和工具所打的幌子。真正的強大工具不需要用戶付出太多努力就能提供強大的功能。任何會使改錐和鑽頭的人都會用電動改錐和電鑽。他們不需要搞懂電學、電機、轉矩、電磁學、散熱或維護。他們只需要把它通上電,帶上安全眼鏡,然後打開開關。許多人連安全眼鏡也不省了。你在五金商店裡找不到有致命缺陷的工具:它們不是根本沒能投放市場,就是被訴訟搞得焦頭爛額。
UNIX設計者的最初目標是提供簡單的工具,然而現在的工具則充滿了過分的設計和臃腫的功能。比如ls這個列文件的命令竟然有18個選項,提供從排序到指定顯示列數的種種功能,而這些功能如果用其他程序實現會更好些(以前正是這樣的)。find命令除了查找文件以外還輸出cpio格式的文件(而這個功能其實用UNIX名聲狼藉的管道很好地實現)。今天,和UNIX類似的電鑽將有20個旋鈕,連著不標準的電源線,不匹配3/8英吋和7/8英吋的鑽頭(而這一點會在手冊的BUG一章中說明)。
和五金店裡的工具不同,許多UNIX強大工具是有缺陷的(有時對文件是致命的):比如tar的不接受超過100個字符的文件名;又比如UNIX調試器總是垮掉,這還不夠,它的core文件將覆蓋你自己的core,讓你下次可以用調試器去調試調試器在調試調試器中生成的core。
[編輯]
Shell遊戲

UNIX的發明人有個偉大的想法: 把命令解析器作為一個用戶程序實現。如果用戶不喜歡缺省的命令解析器,他可以自己寫一個。更重要的是,shell能夠進化,這樣shell將不斷進步,變得越來越強大,靈活和易用,至少理論上是這樣。
這真是個偉大的想法,不過弄巧成拙了。功能的逐漸增加帶來的是一團糟。因為這些功能沒有經過設計,只是在不斷演化。和所有編程語言所遭到過的詛咒一樣,那些利用這些功能的既存shell腳本成為了shell的最大敵人。只要有新的功能加入shell,就會有人在自己的腳本中使用它,這樣這個功能就從此長生不老了。壞主意和臭功能往往怎麼也死不掉。
於是,你得到了一個不完整、不兼容的shell的大雜燴 (以下每個shell的描述都來自於他們各自的man pages):
sh 是個命令編程語言,用於執行來自終端或文件的命令。Jsh 和sh一樣,但具有csh風味的工作控制 (job control)Csh C類型語法的shellTcsh emacs編輯口味的cshKsh KornShell,你的另一個命令和編程語言Zsh Z ShellBash GUN Bourne-Again Shell (GNU Bourne復出Shell)
五金商店裡的螺絲刀和鋸子,儘管可能來自3、4個不同的廠商,但操作方法都差不多。典型的UNIX在/bin或/usr/bin下存了成百個程序,它們來自眾多自以為是的程序員,有著自己的語法、操作範例、使用規則(這一個可以當成管道,而那一個則操作臨時文件),不同的命令行參數習慣,以及不同的限制。拿grep和它的變種fgrep, egrep來說,哪一個是最快的?為什麼它們接受的參數都不一 樣,甚至對正則表達式的理解也不盡相同?為什麼不能有一個程序提供所有功能?負責的傢伙在哪兒啊?
當把命令之間的種種不同都深深烙在腦海中後,你還不能避免被驚著。
[編輯]
Shell Crash

下面這條消息來自哥倫比亞大學編譯原理課程的BBS。
Subject: Relevant UNIX bugOctober 11, 1991

W4115x課程的同學們:

我們剛學習了活動記錄(activation record),參數傳遞(argument passing)和函數調用規則(calling conventions),你們是否知道下面的輸入將讓任何一個cshell立刻崩潰?

:!xxx%s%s%s%s%s%s%s%s

你們知道為什麼麼?

以下的問題供你們思考:

Shell遇到 「!xxx」會做什麼?

Shell遇到 「!xxx%s%s%s%s%s%s%s%s」會做什麼?
為什麼cshell會崩潰?
你將如何修改有關代碼來解決這個問題?
最重要的一點:
當你(是的,就是你)將這個前途遠大的操作系統用21個字符治服的時候,你覺得天理能容麼?
你可以自己試一試。根據UNIX的設計,如果shell垮掉了,你的所有進程將被殺死,你也會被踢出系統。其他操作系統在遇到非法內存訪問錯誤時會彈出調試器,但不是UNIX。
可能這就是為什麼UNIX shells不讓你在shell的地址空間裡動態加載自己的模塊,或者直接調用其他程序中的函數。如果這樣就太危險了。一步走錯,唉喲,你已經被踢出門外了。愚蠢的用戶是應該被懲罰的,程序員的錯誤更是不可容忍。
下回書裡我們將進入色彩斑斕的UNIX語法世界。

沒有留言: