Bash readline 使用技巧

Bash readline 使用技巧

很多人會用 Bash,但是很少有人知道 readline 是怎麼回事。readline 是一個強大的庫,只要使用了它的程序,都可以用同一個配置文件配置,而且用同樣的方法操作命令行,讓你可以方便的編輯命令行。

使用 readline 的程序現在主要有 Bash, GDB,ftp 等。readline 付予這些程序強大的 Emacs 似的命令行編輯方式,你可以隨意綁定你的鍵盤。

術語解釋

在下文中,我們經常提到 "C-x r" 這類鍵操作。"C-x r" 其實就是按Ctrl-x,然後按 r。同理 "C-M-@" 就是按 ctrl-alt-@(M表示meta, 在 PC 上就是 Alt 鍵),但是其實 @ 是shift-2 (看看你的鍵盤)。所以 "C-M-@" 實際上要你按 ctrl-alt-shift-2。

但是在配置文件裏的鍵序列中,我們把 "C-x r" 表示爲 "\C-xr", 把 "C-M-@" 表示爲 "\C-\M-@",你自己看看就知道怎麼回事了。同理 "Esc a" 別表示成 "\ea"。

這就是 Emacs 裏的按鍵的通常標記方法。EMACS = Esc Meta Alt Ctrl Shift :)

技巧篇

在自己配置命令行之前,我們先來看看利用缺省的鍵綁定能夠進行的一些巧妙的用法:

第一招:使用以前的命令行參數

你是否經常出現這種情況?你想把 ~/text-browser/ 目錄下的3個.tar.gz文件搬到/usr3/software/,於是你輸入:

$mv ~/text-browser/*.tar.gz /usr3/software/

我想你一定已經知道,打入 ~/text 之後按 TAB 就可以補全text-browser這個長文件名吧?這是Bash 的基本功能。我廢話?好了,就當你知道吧。不過今天我要講的東西比這個複雜一些。

Go on! 剛剛輸入到這裏,你突然想起,應該在 /usr3/software/ 下先建立一個目錄叫browsers,這樣放進去的文件比較好管理。

於是你 Ctrl-u,刪掉了這行命令。唉呀,這麼長的命令一下就沒了。是不是有點可惜?這還不算麻煩。然後你

mkdir /usr3/software/browser
mv ~/text-browser/*.tar.gz /usr3/software/browser
嗯。TAB 是幫了你不少忙。可是你實際上有更好的辦法來完成這項工作。好吧,看看 readline 怎樣神奇的完成你的任務:

我們回到這種情況:

$mv ~/text-browser/*.tar.gz /usr3/software/
你剛纔是按了 Ctrl-u 刪除了所有輸入的東西。可惜啊!你要是按 M-#(也就是按住 PC 機的 Alt 鍵,再按 #,實際上就是 Alt-Shift-3),那麼 Bash 就會在這樣最開頭插入一個 "#",然後輸入這行。這樣命令就被作爲一行註釋載入了歷史。

這有什麼好處?這樣你的這行命令裏的內容就可以被再次利用。看着:你接着輸入:

mkdir ...
等等,你是不是想輸入 /usr3/software/?你不用再敲一遍了!直接按 M-.(Alt 加句號),看看, /usr3/software/ 是不是出現在命令行上了?M-. 就是調用了 yank-last-arg 函數,把上一條命令的最後一個參數放在命令行上。好了,回車吧!

你接着輸入:

mv ...
等等,這下是該輸入 ~/text-browser/*.tar.gz 了。煩不煩啊?換一種方式吧。請按:"M-1 M-."(把上一條命令的第一個參數放在命令行上)。這樣命令行成爲了:
mv /usr3/software/browser
怎麼成這樣了?看看你的“上一條命令”是什麼吧?是……你自己看。所以這個參數不是你想要的。那麼繼續再按一次 "M-."。看到了吧?你的命令行已經成爲:
mv ~/text-browser/*.tar.gz
好。打一個空格。再按一下 "M-."。命令行變成了:
mv ~/text-browser/*.tar.gz /usr3/software/browser
這就是你想要的!

是不是看起來你還是花了不少工夫?但是想一想,如果你是要執行這樣一個命令呢?

mv /data/ftp/pub/TUG/texmf/tex/latex/CJK/GB/GB.cap \
 /usr/local/texlive/texmf-local/tex/latex/CJK/GB/
嗯。記住這個有用命令:M-. , 它的前面可以用 M-0, ... 作爲數字參數。

第二招:補全命令名,文件名和變量名

你知道 TAB 可以補全命令行上很多東西。可是你遇到這種情況的時候怎麼辦?

man a-very-very-long-command-name
你輸入了 man a-ver... 之後,按 TAB,什麼反應也沒有。因爲 TAB 執行的是 “按情況補全”(complete),它看到 man,知道這應該是一個命令,那麼它認爲: “後面應該是一個文件名參數。” 但是你想要的是命令的名字怎麼辦?答案:按 "M-!".

再來看:你需要設置 XMODIFIERS="@im=fcitx"。你輸入了

export XM...
按 TAB? 沒有反應。爲什麼呢?因爲 TAB 的補全想要一個文件名,而當前目錄沒有開頭是 "XM..." 的文件。那麼你怎麼補全?答案:"M-$"。

其實 readline 的補全方式被 Bash 擴充了很多。看看有多少吧!

"TAB": complete
"\M-!": complete-command
"\M-/": complete-filename
"\M-@": complete-hostname
"\M-~": complete-username
"\M-$": complete-variable
自己試試吧!

第三招:擴展命令行

你的一個目錄裏有很多類似的文件,名字叫 T12.txt, T12.log, T23.txt, T23.log, T13.txt, T13.log…… 有後綴 txt 的,也有後綴 log 的。... 你想把其中的某些 T*.txt 都移動到另外一個目錄,而T*.log都不動。但是T*.txt 也不是全部都要移動。所以你想把T*.txt 都放在命令行上,然後選擇其中一些。你輸入:

mv T...
接着按 "M-*"(insert-completions)。結果 T 開頭的文件都被放到命令行上了。嗯。這在某些時候是有用的,可是現在它把 T*.log 的文件也放上去了。不行。我們於是繼續輸入:
mv T*.txt 
好了,現在我們可以使用 "C-x*"(先按ctrl-x,然後按*)。結果所有名字T*.txt 的文件都被放到了命令行上面。"C-x*" 執行的函數叫做 glob-expand-word.

配置篇

你是不是覺得那些命令很難記住?不順手?別怕!它們都是可以改變的,就像Emacs的鍵綁定那樣,可以被任意的改變!

所有使用readline的程序,都使用一個配置文件來決定它的行爲和鍵綁定。這個文件一般是 INPUTRC 環境變量確定的。如果這個環境變量沒有值,那麼缺省使用 ~/.inputrc。

~/.inputrc 文件很簡單,只有4種語句:

  1. 註釋
  2. 變量設置語句(set variable value)
  3. 鍵綁定("keyseq":function)
  4. 條件語句($if ... $endif)
我們先不說其它的,先來看看鍵綁定吧!

鍵綁定

  1. 綁定語句。

    你現在就可以動手設置你喜歡的控制方式。比如,我發現有些時候我需要在命令行上做上 mark(Emacs 術語),然後把mark 和光標之間的 region(Emacs術語) 刪掉,這個操作在 Emacs 裏叫做kill-region. 但是我們發現這個函數在 Bash 裏缺省是沒有綁定的。如果我希望得到跟 Emacs 一樣的綁定 C-w 的話,就把這行插入到 ~/.inputrc:

    "\C-w":kill-region
    
  2. 使綁定生效。爲了使這個鍵綁定生效,你需要執行 re-read-init-file 函數。這個函數缺省綁定在了 "C-x C-r"。你修改 ~/.inputrc 之後在 Bash 裏輸入 "C-x C-r" 就可以使新的配置生效了。
  3. 列出可用的函數。

    不過你怎麼知道那些函數可以被綁定呢?readline 的 info 頁列出了很多函數,可是你不會每次都去info裏查詢吧,很麻煩啊。其實你可以使用bash的 bind 命令來得到所有的鍵綁定:

    $bind -p
    
    可以顯示所有現有的已經綁定和沒有綁定的函數。沒有被綁定的函數被顯示爲 "(not bound)",並被加上了註釋。就像這樣:
    "\C-g": abort
    "\C-x\C-g": abort
    "\M-\C-g": abort
    "\C-j": accept-line
    "\C-m": accept-line
    # alias-expand-line (not bound)
    # arrow-key-prefix (not bound)
    # backward-byte (not bound)
    "\C-b": backward-char
    "\M-OD": backward-char
    "\C-h": backward-delete-char
    "\C-?": backward-delete-char
    
    你可以把這個命令的輸出作爲一個模板,嵌入到 ~/.inputrc 文件。把你喜歡的函數綁定到方便的按鍵。

    其實 readline 有三個函數可以讓你方便的查詢函數,變量和宏的綁定情況,它們是:

    dump-functions
    dump-variables
    dump-macros
    
    可是它們缺省都沒有被綁定到任何按鍵。你可以爲它們分別設置類似 "C-xf", "C-xv", "C-xm" 這樣容易記憶的綁定。
  4. 如果忘了綁定……

    這樣你就可以設置你需要的綁定啦!但是你還是有可能在需要的時候突然記不起哪些鍵綁定可以補全。這時候你輸入:

    $bind -p | grep compl
    
    得到結果:
    "\C-i": complete
    "\M-\e": complete
    "TAB": complete
    "\M-!": complete-command
    "\M-/": complete-filename
    "\M-@": complete-hostname
    "\M-{": complete-into-braces
    "\M-~": complete-username
    "\M-$": complete-variable
    "\M-\C-i": dynamic-complete-history
    "\M-g": glob-complete-word
    "\M-*": insert-completions
    .......
    
    這樣你記不住一個鍵的時候就可以方便的查詢,這樣幾次之後,你就會把自己需要的按鍵都記住了。

配置變量

  1. 體驗:

    Bash 的 readline 有一些變量可以控制它的行爲。比如:

    bell-style 可以控制出錯時是 audible(發出響聲),visible(閃動屏幕),還是none(什麼都不做);editing-mode 可以控制你是用 Emacs 的輸入方式還是用 vi 的;

    completion-query-times 的值控制在補全的個數超過多少N時,bash 提示: “Display all N possibilities? (y or n)”;

    如果我設置 expand-tilde 爲 on,當輸入“ls ~/doc”,按 TAB 時,命令行會自動變成 "ls /home/wy/doc".

    如果把 visible-stats 設置爲 on,那麼列出補全的時候,目錄,可執行文件,符號連接,會被分別使用 /, *, @ 來標記,就像 ls -F 的到的結果。

  2. 設置:

    設置的方法極其簡單,就在 ~/.inputrc 文件裏寫入類似語句:

    set visible-stats on
    
    然後 "C-x C-r" 使設置生效。
  3. 怎樣知道有哪些設置?

    可以設置的參數是很多的。使用命令

    $bind -v
    
    就可以得到所有這些可以設置的變量和它們的值了。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章