為什麼 Python(或 Ruby、Perl 等)沒有取代 Bash 成為系統 Shell?

關聯問題:http://www.zhihu.com/question/20244763

如果編程語言是否可以作為系統Shell使用,與它的流行程度正相關,那為何Python還沒有成為標配的系統Shell?

選擇Python(或其它)作為系統Shell,一定就比Bash或者POSIX Shell更經濟嗎?


@狼大人 和 @yegle 說的都很有道理,不過我覺得大家都忽視了一點,就是一個軟體的慣性(或者說是一種習慣)。尤其是 Shell 這種基礎設施的軟體,一旦啟用了一會,很多人很多軟體就會採用這樣的標準,所以只要不是太差一般就不會改變。

舉一個例子吧,我的老師教我使用 Linux 的時候,編輯文件是用 vi,所以後來有很長一段時間我都不知道 vim 是什麼東西。後來我也一直使用 vi 這個命令,倒不是什麼少一個字母比較方便的問題,就是習慣了。我們也都知道在 Linux 中是沒有 vi 的,至少 debian 是沒有的,默認安裝了 vim-tiny,然後可以安裝完整版的 vim,vi 則一直是 vim 的一個 link。我不知道是我的老師開始的時候用 UNIX 習慣使用 vi,還是我老師的老師是用 UNIX 的然後教他的時候就教了 vi,反正作為從 UNIX 繼承過來的一套軟體,命令的格式、樣式也算是一種慣性,不會也不應該輕易的改變。Linux 中還有很多這樣的例子,比如 cc -&> gcc,lex -&> flex,yacc -&> bison,都是遵循 UNIX 的習慣。

也許是類 UNIX 系統中,有太多太多的腳本是使用 Shell 腳本寫的,所以這個不應該輕易的改變。比如,如果我們自己編譯過一些軟體或者類庫,我們一定會對 ./configure 這個文件不會陌生,這個就是一個用 Shell 寫(準確的應該說是生成的)的腳本。打開這個文件的第一行,你會看到 #! /bin/sh 這樣的一段。我們都知道 sh 和 bash 是不一樣的,sh 作為一種古老的 Shell,在 Linux 中已經基本上被 繼任者 bash 代替了,但是那些 autoconf 的腳本依然繼承了 sh 這個古老的慣性,也是為了兼容其他的系統吧,比如在 FreeBSD 中,默認安裝就是沒有 bash 的。

所以,倒也不是哪一個好或者是哪一個不好,就是大家都習慣了,反正也沒有什麼太大的問題,幾十年了也不好再改了。


@余天升 同學說的「慣性」這一點很有道理,但身邊有不少人,用 bash 多年之後在別人的推薦下改用了 zsh (包括我),幾天就完全切換完成了。在得知 Debian 系中 vi 只是 vim 的別名之後,養成打 vim 而不是 vi 的習慣的,也大有人在。因此,我認為特殊的不是 bash,而是 shell 這一類東西。shell 和其他腳本語言的區別是很重要的。

所謂「shell」,首先得是操作系統界面(這也是 shell 的原義),其次才是一個編程語言。而操作系統的職能中,文件系統和進程管理是兩塊很重要的地方。因此 shell 十分強調文件命令,這是其他腳本語言所不具備的。具體強調的方式,有語義上的,也有語法上的。

考慮最簡單的,用 vim 打開文件 a.c,用 shell 寫是:

vim a.c

用 Python 的話寫出來就得是:

from subprocess import call
call(["vim", "a.c"])

這裡可以看到的幾點是,1) shell 有意混淆內建函數(builtin function)和外部命令的區別;2) shell 對裸詞(bareword)的支持,即不加引號的詞自動視為字元串;3) shell 使用空格分割參數,調用也不需要括弧。這三點使得 shell 中寫外部命令調用變得十分 trivial,因為這是 shell 作為操作系統界面需要做的最多的事情。

通配符也是一個很典型的例子:

rm *.c

用 Python 寫出來就得是:

from os import unlink
from glob import glob
[unlink(f) for f in glob("*.c")]

很顯然,通配符完全是為操作文件服務的。

最後,pipeline 前面有人提到過了。pipeline 是 Unix tool philosophy 中很重要的一環,可惜因為先天不足,應用不廣。


原因很簡單,歷史習慣+沒人做。

說python不能做shell的我就呵呵了,知道scsh嗎?scheme都能做shell憑啥python不能?說起來丟人,當初我還真動手要做一個pysh,弄了兩周弄到兼容不同終端類型的時候實在不勝其煩放棄了。當時交互、解釋執行、基本的iO、管道都已經有雛形了。


Shell 是有很多缺(tuo)陷(xie)的。比如說一個最簡單的例子,如果你下載的文件名字裡面有很多空格,在準備批量操作比如歸檔的時候都會很麻煩。Shell 的自動解析通常會把你搞得很慘。而且那東西還是個feature 對吧?那不是bug。

其實這就是很典型的不適合用Shell去解的問題嘛。你找個沒有自動解析的工具,比如說隨便哪種腳本語言都行啦。為什麼選Ruby呢?當然因為Ruby有 irb 咯。

irb(main):033:0&> dir = "Archive-Dir"

irb(main):034:0&> dst = "Your-destination-directory"

irb(main):035:0&> num = 16

irb(main):036:0&> lines = `ls -rt ~/Downloads/ | tail -n #{num}`.split("
")

irb(main):037:0&> lines.each { |l| print `mv "#{l}" #{dir}/#{dst}` }

這樣一來就是這麼簡單了,其實就只有兩行嘛。我只所以寫那麼多變數是因為我還有很多文件需要交互的去做的。那麼我就只需要改變數,然後用箭頭找歷史,一路回車就行了。

但是為什麼 Shell 還是不能夠被取代呢?因為還有大量的互動式任務用 Shell 的時候可以簡單到不可想像的地步。

diff -u &<(ls | sort ) &<( grep amazon mp3.url.txt |

awk -F "/" "{print $NF}" | sort ) 2&>1 |

egrep "^+[^+]" |sed -e "s/^+//" |

xargs -n 1 ./download.sh

甚至於是這樣

diff -u &<(ls | sort ) &<( ssh -i ~/my.key dove@myhost grep amazon mp3.url.txt |

awk -F "/" "{print $NF}" | sort ) 2&>1 |

egrep "^+[^+]" |sed -e "s/^+//" |

xargs -n 1 ./download.sh

所以呢,應該用 Shell 處理的問題還是要用 Shell 處理的。

順便問一下,為什麼不用 Python ?

我真的不想僅僅因為沒對齊…… …… ……

人生苦短,不用Python。

稍微補充一點 Shell 的好處。就是 Shell 這樣的東西呢,畢竟也算是歷史悠久,酒精考驗的老同志了,所以不容易出現用戶還得自己分辨不同版本下面數學計算究竟應該等於多少這樣的事情。。。


同樣實現一個功能,例如判斷某個主機的存活,bash只需要一句話

ping -c1 -w1 -t5 192.168.0.125&>/dev/null 2&>1 echo ok|| echo down

而python 可能還要經歷import os或者commands或者是subprocess等包然後調用系統ping然後再來判斷。。這種現象在很多方面都可以找到。甚至很多時候,當我無法用python(可能我沒學到家)實現的時候,bash,分分鐘就給我搞定。

我信奉的是python的那個信條,我們運維人員不應該將生命浪費在代碼上,誠然,如果我們能用bash搞定輕鬆搞定的,為什麼還要繞遠路呢?我想很多人會是和我一樣的想法。

曾經有一次,我想用python實現某個功能,進而想到了那個機器很差勁,想用C來實現,但是看到C的代碼居然並不比python麻煩,瞬間,我感覺我的世界觀崩潰了(也許,大型的程序,C的確比python複雜。)進而想到。或許我們在討論某些程序的優劣或者是某些語言代替某些語言的時候,我們該想想應用場景。

同樣我又想到了一個同事說的一句話:不以應用場景談語言的都是耍流氓~

實際上很多時候,人們只會選擇更方便快捷的方法來實現自己的想法。


Python/Ruby/Perl 沒有取代 Bash 的必要,Bash 是一個 Domain-Specific Language,而 Python 是個 General-purpose Programming Language,語言本身存在的目的本就不同,這也正是 DSL 存在的意義,可以參看維基百科相關條目。

我們討論這個問題的前提是在 *nix 的背景下,那就應該從 *nix 自身的發展歷史尋找原因,也就不難理解為什麼 Python 永遠不會做為 Shell 的替代存在。

Unix 的初期硬體條件的限制決定了 *nix 的設計哲學,其中最重要的兩點就是:一、一個工具只做一件事,並把它做好;二、工具之間通過 plain text 進行數據交換。這樣的設計降低了系統的複雜度,只需要 Shell 這樣的膠水語言通過搭積木的方式即可完成很多複雜的任務。由於並不需要複雜的數據結構操作,Shell 不需要成為像 Python 或者 Perl 這樣完整的程序語言,而且這一條件到現在也沒有發生變化。

這裡我比較贊同 @yegel 的觀點,至於 @狼大人 對於 Bash 語法的吐槽,我相信在未來相當長一段時間 Bash 的語法不會徹底的改變。因為在 *nix 的世界裡,Shell 的實現並不只有 Bash,可移植性是一個很重要的因素,被 @狼大人 吐槽的那些奇葩語法大部分都是 POSIX 定義的,也正是要感謝 POSIX 的存在,我們才能享受 *nix 帶來的各種好處。

另外,具有交互模式的語言並不一定就能做為 Shell,成為 Shell 的一個必要條件是符合 *nix 的設計哲學,成為一個膠水語言,做為工具之間溝通的媒介,至少實現 pipe 是必不可少的。


因為:

BASH 是拿來「用」的

python 是拿來「「的


bash 是基於 字元串的。這很適合作為 系統Shell

而 Python 是面向對象的,至少在 bash 設計的那個年代,不要說面向對象的系統shell了,就連面向對象都沒有

現在的確是由 Powershell 這樣面向對象的 系統Shell,但是要注意 面向對象的shell 意味著大量的 原本shell內的原生函數要重新設計,就比如 grep 等等都是純粹的面向字元串,在操作文本,而powershell中的where完全是面向對象的,是在操作類型,二進位的數據。如果想要把 python 作為系統的shell,就必須從頭設計這些工具。

的確 windows 是成功的設計了這些工具,這是因為長久以來windows的習慣都是,用二進位的代碼、數據去相互調用、交互,比如他的那一坨dll。。而powershell的出現,只是提供了一個動態語言,藉由.net, 能輕鬆的與.net程序或者是系統dll介面 交互。powershell本質上操作的是 二進位對象。

但 unix 的哲學是,一切皆文本,一切皆流。長久以來大家都按這樣的精神設計的。這就意味著,面向對象的shell 本質上與 unix 整個系統的哲學矛盾。。所以,如果你要設計一個 基於python的shell 的話。。目測要重寫的程序不是很少。。


python?你想每次都call(["ls", "path"])一次么?打括弧一點都不好玩=。=


反向思考很容易解答這個問題,什麼語言能夠取代sh?

我們知道在一部分unix中ksh取代了sh成為預設shell,linux中則bash取代sh成為預設的shell。他們都有什麼特點?

對了一個最顯著的特點是,他們與sh的語法向下兼容。或者至少是絕大部分兼容sh的語法,python不兼容sh的語法,所以絕對不可能替代shell的地位。。


因為比bash 複雜


@yegle 的答案是對的,我再補充一點資料:

The shell is somewhat unique, in that it is both a powerful command line interface to the
system and a scripting language interpreter. --The Linux Command Line. 2nd.

  • Python與CLI是牛馬不相及的兩個東西,無從替代。
  • 如果想要替換scriptinterpreter,把shebang設為#!/usr/bin/env python就可以了。不過正如 @余天升 所言,雖然Python在代碼可讀性、資源量比Shell Script要有優勢,但這裡面還有個legacy的問題。


習慣問題。對於高級用戶來說,自行將 Python 設置為 shell 不成問題。但是對於中級用戶來說,剛剛脫離純 GUI 開始接觸 shell,這個人群的經驗範圍跨度很大。他們必須在很長一段時間之內不斷相互交流以及吸取高級用戶的經驗。如果想讓這些人舒服的用上 Python,就必須讓很多高級用戶一下子轉到 Python,否則就沒有人帶領他們。但是,除非特別自我的高級用戶,很多高級用戶在工作中又必須和很多中級用戶打交道,所以他們又不願完全採取一種大多數中級用戶不熟悉的方案。所以雙方相互摯肘。而 bash 也不是一個 on user"s way 的東西。所以這個問題就維持現狀了。


個人淺見,拋磚引玉

最大問題在於遷移成本。在沒有好到「用了後整個世界都清凈了」或者「非如此不可」的情況下,採用一種使用風格和過去有重大改變的解決方案,是不太容易推行的。

如果在python shell里調用外部程序可以像bash一樣直接,或許會更容易接受

「經濟」要看怎麼算,看執行效率的話python應該不會比bash差(?),沒做過評測。看易用性和人員學習成本的話,python好一點吧。

================

易用性要怎麼看,還是剛才說的,如果在python shell里調用外部程序、使用管道可以像*sh一樣方便,那就好了。


Essentially, shell is a tool to run other tools.


都說 xx 替換了 yy,實際上,能幹好自己的一畝三分地就不錯了


很顯然,bash更簡潔


慣性。


因為用全功能語言實現日常操作不方便

想像一下把自己的shell改成python

用os.chdir移動目錄 用os.system執行程序 用os.popen實現重定向

堅持一天

另外perl解釋器連read-eval-print loop都沒有


Bash is a different kind of language, both because it"s more devoted to
handling native unix executables, but also because it"s a more primitive
and older language devoted to doing things in ways they needed to be
done before the present price/cost of resources.

There are a lot of things you can do much more efficiently in Bash, and
in far fewer lines. Also, in Sysadmin land, you may find more of the
people managing your production boxes will know Bash than Ruby.
Probably far more. In my shop, practically everyone is still refusing
to use Ruby and they want me to write anything I can in Bash, when it"s
at all practical. To a certain extent I think this kind of request has
reasonable roots and should be taken into account.


推薦閱讀:

Unix和Linux操作系統有什麼區別?
FreeBSD 還有前途嗎?
為什麼現在沒有人開發新的OS內核?目前只有linux、unix、window、mac等,很希望有人能開發一個新的內核出來
Terminal 和 Console 的區別是什麼?
如何讓我不再折騰 Linux?

TAG:Python | 編程 | Linux | Unix | Bash | Linux運維 |