大話Emacs—Shell Mode 第一回 引子
Shell Mode 是 Emacs 裡面很有意思的一個模式。通常來說在 Emacs 裡面運行 shell 主要有3種途徑。一種是使用 Emacs Terminal Emulator。這種模式基本就是在Emacs裡面類比一個Terminal,然後在這個Terminal裡面運行subShell。從使用者體驗角度來說呢,How to say? 他就是一個 Terminal, 是吧。另外一種途徑是使用 Shell Mode。在這種模式下使用者是通過一種間接的方式和 Shell 進行互動。也許有些人覺得間接這個詞感覺比較不爽。其實吧,你們不正是通過作業系統,甚至應用程式,間接的和你們的機器打交道才混到現在的嗎?(環顧四周,玩兒過 ENIAC 的傢伙沒有過來砸場子吧?)
所
以說,間接本身就是一種美。在 Emacs Shell Mode 方式中,真正和使用者直接互動的實際上是一個 Shell
buffer。使用者只是將命令輸入到這個 Shell buffer 當中,然後由 comint.el 負責把它轉交給實際的
Shell;命令產生的輸出再由 comint.el 負責接收並且插入到 Shell buffer 中來。這樣做有什麼好處?沒看出來嗎?我們說到了
Shell buffer,它是個 buffer,一個普通的 buffer,一個沒有任何低級趣味的 buffer!要知道 Emacs
最大的本事就是操作 buffer。也就是說 Emacs 當中能在一個 buffer
裡面使用的任何功能,都可能直接朝這個地方來招呼了!不止這些,還要加上comint.el所提供的專有命令。所以在這種模式下,你所面對的不再是一個獨
立的 mode,你能調動的是整個的
Emacs。從吹牛的角度說,那傢伙,幾乎就沒有它辦不了的事兒。。。是吧?除了。。。運行全螢幕的應用程式,比如說
vim。。。這個,話說,你可以使用 Terminal mode 嘛。
好了,不再羅嗦了。讓我們來看幾個小小的案例,初步體會一下間接的工作模式究竟帶來了哪些變化。
大話Emacs—Shell Mode 第二回 半拉命令真頭疼
不要說你從來就沒有頭疼過。做人要誠實。
在這樣一個“月黑風高”的下午,當你滿懷信心的在 shell
提示符前輸入了一行命令,快要結束的時候,突然想起來還有一個參數。。。還不能確定他究竟應該是什嗎?貌似要先執行另外一條命令去確認一下。。。呃。。。在這個時候,你覺得應該怎麼做?說實話,馬上說,不要想!
你是不是會用 Ctrl c 殺掉這行輸入,然後輸入那條確認的命令。再然後,重新輸入剛剛輸入的那條命令。。。再再然後呢,看著螢幕上的那條刺眼的半拉子命令,告訴我,你一定想過這樣一件事情———— “那麼,我剛才輸的那行命令不是就白輸了嗎?!” (外面的風,又緊了一些。。。)唉,算了吧。白輸了就白輸了唄,這有什麼了不起的?我還是趕緊幹活兒吧。我還要早點兒下班,回去關家裡的窗戶呢。可是,可是又有一條該死的命令被輸了一半!誰能告訴我另一個命令參數究竟應該是什嗎?為什麼越是著急就有越多的麻煩? (外面雨已經下起來了,風還是一點都沒有停息。。。) 這一刻,我們的主人公終於覺得忍無可忍,“我要捍衛我的勞動成果!絕對不能讓我的寶貴生命浪費在無休止的重複輸入中!”(台上做振臂高呼狀,台下觀眾西紅柿臭雞蛋準備中)
什麼什嗎?你們要換台了?好的,好的,趕緊講正題。 咱們前文書說過,Emacs Shell Mode 的一個顯著特點就是這種間接的工作方式。使用者所作的一切只是把一行行文字輸入到 Shell buffer 裡面去,然後由 comint.el 轉交給背景 Shell 進程。這就意味著,如果你沒告訴 comint.el 把你的文字轉交給 Shell,那個背景 Shell 進程根本就不會知道你在前面已經想出幾百個主意只等著算計它了。(回頭瞧瞧,它還在後邊傻樂呢)
現在鏡頭切換。在這個新的情境裡面,我們的主人公是工作在 Shell Mode 裡面的。現在主人公輸入了一條半拉子命令,然後突然想起來需要確認一個奇怪的參數。。。現在主人公不必在振臂高呼了。只見他臉上掠過一絲難以察覺的笑容,然後向上移動游標,在螢幕上尋找一塊空白乾淨的地方。不幸這會兒螢幕上都挺滿,只見我們的主人公不慌不忙的輸入 C-o 按鍵組合,自己產生了一個空白行,然後在這塊空白的地區裡快速的敲下那行確認的命令,然後輕擊斷行符號,comint.el 把這行確認的命令發送到 Shell 執行,並且將命令的輸出拿回到 Shell buffer,這個時候,guess what? 剛才那條輸了一半的半拉子命令,還在原來的地方,跟那兒等著你呢。樂去吧你就。(台下觀眾開始鼓掌,凡是鼓掌的,一會兒散戲之後,都跟我到後台領冰棍吃。)
這就是間接的魅力。沒說命令非得是在 Shell 提示符前才能夠輸入。那是 Shell 訂的規矩。憑什麼啊?我就不樂意跟這種 Shell 打交道。現在我們是在一 buffer 裡頭。在這裡頭我樂意怎麼寫,我就怎麼寫。等我寫完了,我告訴我們家鄰居,那 comint,人家樂意去找 shell,我讓他們倆去打交道。我們覺得這兒舒服,我們跟這兒玩兒我們自己的。這多爽阿。
大話Emacs—Shell Mode 第三回 我叫你的名字,你敢答應嗎?
《西遊記》裡面說有這麼一集,說的是金角大王,銀角大王偷了太上老君的寶葫蘆,只要是一叫孫行者的名字,那猴子立刻就自己個兒的跑到這個葫蘆裡頭化為膿水
了。後來呢,孫行者為了逃避這太上老君的寶葫蘆,給自己起了無數的名字,什麼叫者行孫啦,行者孫啦,甭管叫什麼吧,只要金角大王叫對了他的名字,這孫悟空
都會抑制不住的跑到人家的寶葫蘆裡頭去。
好的,好的,我只說這麼小段《西遊記》啊。我保證這一節只講正題啊,而且裡面一定有 code 啊。其實你們後頭肯定會聽到,我在這開場白裡面說的《西遊記》裡面的情節絕對不是廢話。我在這裡一樣有一個 “我叫你的名字,你敢答應嗎?”的寶葫蘆。
咱
們前文書不是說過嗎?Emacs Shell Mode 是通過一個 Shell buffer 來和使用者互動的。因為這是個
buffer,所以你幾乎可以隨心所欲作一個 buffer
能做的任何事情。包括隨便想在哪兒寫,隨便想在哪兒刪,隨便想在哪兒儲存和尋找。在這裡我們還可以用的更為複雜一些,甚至可以通過對 buffer
裡面的內容進行處理,讓他自動產生我們需要的命令。
這裡講一個執行個體給大家看看。登入到我們的一台機器上,看一下有哪些 WebSphere MQ 的 Queue Manager?
看
起來這裡有 10個 Queue Mananger。現在我需要把他們都啟動起來。啟動 Queue Manager 的命令是 strmqm,
要命的是這個命令一次只接受一個 Queue Manager
名字作為參數。而我需要啟動10個。而且每一個都很慢。我可不想像個傻瓜似得一直等在這裡輸入這10條命令。而且這些名字也全都起的各不一樣,誰都不挨
誰,就是用迴圈搞著也不方便。那該怎麼辦呢?事實上我可以讓 Emacs 來幫我構造這10條命令。做起來很簡單, 因為我們是在 shell
buffer 裡面,我只需要選中上面這段輸出,按下 M-| 按鍵組合,或者使用 shell-command-on-region 命令,用一行
sed 命令來處理這段選中的地區。
sed -n -e '/Ended/s/QMNAME(\([^)]*\)).*/strmqm \1/p'
斷行符號之後,就看到這樣一個 buffer 。這實際上就是一個 \*Shell Command Output*\ 的臨時 buffer,顯示的就是剛才那條 sed 的執行結果。這個結果正是我們想要的 10條構造好的啟動命令。
什
嗎?你說 sed 這個東西
這麼複雜,寫來寫去多麻煩的啊,下回萬一寫錯了。。。是吧?多耽誤事兒的?那是啊。這種複雜的玩意兒為什麼要每次都寫呢?我連產品的安裝目錄都不願意每次
都寫一遍。我可以把它定義成一個命令縮寫,就叫做 sedstrmqm。這個名字好記多了吧? 方法也很簡單。因為這是一個很長的命令,先用 M-b
命令數一數這行命令一共包含有多少個所謂的 word。也就是說按多少次 M-b 按鍵組合 可以把游標從 p' 後面一路移動到 sed 前面,在這裡是
10次。那麼就輸入 C-u 10 M-x add-global-abbrev 命令,然後用 sedstrmqm 作為縮寫名就可以了。
說
了這麼多了,我們剛才弄出來那10條命令在還在隔壁屋獃著呢。總得有人去把他們弄過來。拷貝粘貼當然比較沒面子了。還要先搞到那個
buffer,然後再搞回這個 buffer 。。。那隔壁班的 MM 早就看的不耐煩了。既然有 MM
在座就一定要秀一點炫的東西出來。就像開頭說到的金角大王那樣,在 Minibuffer 裡面輸入 M-x come-here, 然後跟 MM
說:我叫你的名字,你敢答應嗎? 斷行符號之後在 minibuffer 提示區會出現一個 Input Buffer Name: 的提示,預設的
name 就是我們想要的 *Shell Command Output* buffer,直接斷行符號就會看到那個 buffer
裡面的內容自動的進到我們的寶葫蘆裡面來了。
怎
麼樣?好玩兒吧?會玩兒嗎?沒玩兒過吧?( 呃,這個好像是陳佩斯小品裡頭的詞兒 ) 事實上,這個 come-here
也很簡單,一共就兩行代碼。但是呢,真的很有玩兒頭。 我在我自己的 Emacs 擴充裡面還有一個很好玩兒的
jump,這是用在多視窗模式下的。通常我會在 Emacs 裡開4個 Shell Mode
視窗登入到多台工作機器中去,當我在一個視窗裡面敲完一行命令,這行命令通常也需要在另外的機器上運行一遍。在這個時候我會告訴他
jump!就是自動跳到另外的視窗中去,省得我再把它拷貝粘貼過去了。jump 的代碼也很簡單,起作用的也就兩三行。下回我們講到多視窗的時候再講。
好了,今天的評書連播節目到此結束。聽眾朋友們,下次節目請關注我們的節目預告。請大家一起說,我們的口號是,讓我們把工作都玩兒成遊戲吧!!! (全體演員上台鼓掌,鞠躬,後台領冰棍去嘍。。。。)
(defun come-here (&optional arg) "Bring content from specific buffer to current buffer" (interactive (list (let (( arg (read-buffer "Input buffer Name: " "*Shell Command Output*") )) (insert-buffer-substring (get-buffer arg)) )) ))