標籤:根據 定義 存在 條件陳述式 需要 不可 變數 環境變數 技巧
很多人都會用一些“指令碼語言”(scripting language),卻很少有人真正的知道到底什麼是指令碼語言。很多人用 shell 寫一些“指令碼”來完成日常的任務,用 Perl 或者 sed 來處理一些文字檔,很多公司用“指令碼”來跑它們的“build”(叫做 build script)。那麼,到底什麼是“指令碼語言”與“非指令碼語言”的區別呢?
其實“指令碼語言”與“非指令碼語言”並沒有語義上,或者執行方式上的區別。它們的區別只在於它們設計的初衷:指令碼語言的設計,往往是作為一種臨時的“補丁”。它的設計者並沒有考慮把它作為一種“通用程式語言”,沒有考慮用它構建大型的軟體。這些設計者往往沒有經過系統的訓練,有些甚至連最基本的程式語言概念都沒搞清楚。相反,“非指令碼”的通用程式語言,往往由經過嚴格訓練的專家甚至一個小組的專家設計,它們從一開頭就考慮到了“通用性”,以及在大型工程中的可靠性和可擴充性。
首先我們來看看“指令碼”這個概念是如何產生的。使用 Unix 系統的人都會敲入一些命令,而命令貌似都是“一次性”或者“可拋棄”的。然而不久,人們就發現這些命令其實並不是那麼的“一次性”,自己其實一直在重複的敲入類似的命令,所以有人就發明了“指令碼”這東西。它的設計初衷是“批量式”的執行命令,你在一個檔案裡把命令都寫進去,然後執行這個檔案。可是不久人們就發現,這些命令列其實可以用更加聰明的方法構造,比如定義一些變數,或者根據系統類別型的不同執行不同的命令。於是,人們為這指令碼語言加入了變數,條件陳述式,數組,等等構造。“指令碼語言”就這樣產生了。
然而人們卻沒有發現,其實他們根本就不需要指令碼語言。因為指令碼語言裡面的這些結構,在任何一種“嚴肅”的程式語言(比如 Java,Scheme)裡面,早就已經存在了,而且設計得更加完善。所以指令碼語言往往是在重新發明輪子,甚至連輪子都設計不好。早期指令碼語言的“優勢”,也許只在於它不需要事先“編譯”,它“調用程式”的時候,貌似可以少打幾個字。指令碼語言對於 C 這樣的語言,也許有一定的價值。然而,如果跟 Scheme 或者 Java 這樣的語言來比,這個優勢就非常不明顯了。比如,你完全可以想一個自動的辦法,寫了 Java 代碼之後,先調用 Java 編譯器,然後調用 JVM,最後刪掉 class 檔案。或者你可以選擇一種有解釋執行方式的“嚴肅語言”,比如 Scheme。
很多人把 Scheme 誤稱為“指令碼語言”,就是因為它像指令碼語言一樣可以解釋執行,然而 Scheme 其實是比 C 和 Java 還要“嚴肅”的語言。Scheme 從一開頭就被設計為一種“通用程式語言”,而不是用來進行某種單一簡單的任務。Scheme 的設計者比Java 的設計者造詣更加深厚,所以他們對 Java 的一些設計錯誤看得非常清楚。像 Chez Scheme 這樣的編譯器,其實早就可以把 Scheme 編譯成高效的機器代碼。實際上,很多 Scheme 解譯器也會進行一定程度的“編譯”,有些編譯為位元組碼,有些編譯為機器代碼,然後再執行。所以在這種情況下,通常人們所謂的“編譯性語言”與“解釋性語言”,幾乎沒有本質上的區別,因為你看到的“解譯器”,不過是自動的先編譯再執行。
跟 Java 或者 Scheme 這樣的語言截然不同,“指令碼語言”往往意味著異常拙劣的設計,它的設計初衷往往是目光短淺的。這些語言裡面充滿了曆史遺留下來的各種臨時的 hack,幾乎沒有“原則”可言。Unix 的 shell(比如 bash,csh,……),一般都是這樣的語言。Java 的設計也有很多問題,但也跟“指令碼語言”有天壤之別。然而,在當今現實的工程項目中,指令碼語言卻佔據了它們不該佔有的地位。例如很多公司使用 shell 指令碼來處理整個軟體的“build”過程或者測試過程,其實是相當錯誤的決定。因為一旦這種 shell 指令碼日益擴充,就變得非常難以控制。經常出現一些莫名其妙的問題,卻很難找到問題的所在。Linux 使用 shell 指令碼來管理很多啟動項目,系統配置等等,其實也是一個曆史遺留錯誤。所以,不要因為看到 Linux 用那麼多 shell 指令碼就認為 shell 語言是什麼好東西。
如果你在 shell 指令碼裡使用通常的程式設計技巧,比如函數等,那麼寫幾百行的指令碼還不至於到達不可收拾的地步。可是我發現,很多人頭腦裡清晰的程式設計原則,一遇到“寫指令碼”這樣的任務就完全崩潰了似的,他們彷彿認為寫指令碼就是應該“鬆散”一些。很多平時寫非常聰明的程式的人,到了需要處理“系統管理”任務的時候,就開始寫一些 shell 指令碼,或者 Perl 指令碼。他們寫這些指令碼的時候,往往完全的忘記了程式設計的基本原則,例如“模組化”,“抽象”等等。他們大量的使用“環境變數”一類的東西來傳遞資訊,他們忘記了使用函數,他們到處打一些臨時性的補丁,只求當時不出問題就好。到後來,他們開始耗費大量的時間來處理指令碼帶來的麻煩,卻始終沒有發現問題的罪魁禍首,其實是他們錯誤的認為自己需要“指令碼語言”,然後認為寫指令碼的時候就是應該隨便一點。
所以我認為指令碼語言是一個禍害,它幾乎永遠是錯誤的決定。我們應該盡一切可能避免使用指令碼語言。在沒有辦法的情況下(比如老闆要求),也應該在指令碼裡面儘可能的使用通常的程式設計原則。
【轉】什麼是“指令碼語言”