1. 程式人生 > 實用技巧 >Bash 補全詳解

Bash 補全詳解

概述

在設計基於Bash的中文檔案拼音補全的時候,需要高度定製的補全策略,於是特意研究了下Bash的補全機制。

本文主要是man bash裡面相關說明,由於英文水平有限,參考了中文版的man

補全相關的 Shell 變數(Shell Variables)

COMP_CWORD

${COMP_WORDS} 的索引,指向當前游標位置所在的詞。這個變數只有在被可程式設計補全功能 (參見下面的 Programmable Completion 章節) 呼叫的 shell 函式中才可用。

COMP_LINE

當前命令列。這個變數只有在被命令補全功能呼叫的 shell 函式和外部命令中才可用。

COMP_POINT

相對於當前命令起始處的當前游標位置。如果當前游標位置是當前命令的末端, 它的值就和 ${#COMP_LINE} 相等。 這個變數只有在被命令補全功能呼叫的 shell 函式和外部命令中才可用。

COMP_WORDS

一個數組變數 (參見下面的 Arrays(陣列)一節),由當前命令列的各個單詞構成。 這個變數只有在被命令補全功能呼叫的 shell 函式中才可用。

COMPREPLY

一個數組變數,bash 從中讀取可能的命令補全。 它是由命令補全功能呼叫的 shell 函式產生的。

HOSTFILE

包含一個格式和/etc/hosts相同的檔名,當 shell 需要補全主機名時要讀取它。shell 執行過程中可以改變可能的主機名補全列表;改變之後下一次需要主機名補全時 bash 會將新檔案的內容新增到舊列表中。如果定義了 HOSTFILE 但是沒有賦值,bash 將嘗試讀取 /etc/hosts 檔案來獲得可能的主機名補全列表。當取消 HOSTFILE 的定義時,主機名列表將清空。

FIGNORE

一個冒號分隔的字尾名列表,在進行檔名補全時被忽略 (參見下面的 READLINE 章節)。一個字尾滿足其中之一的檔名被排除在匹配的檔名之外。可以是這樣: ".o:~".

GLOBIGNORE

一個冒號分隔的模式列表,定義了路徑名擴充套件時要忽略的檔名集合。 如果一個檔名與路徑擴充套件模式匹配,同時匹配 GLOBIGNORE 中的一個模式時,它被從匹配列表中刪除。

可程式設計的補全(Programmable Completion)

當試圖對一個命令的引數進行詞的補全時,如果已經使用內建命令 complete 定義了這個命令的補全規則 (comspec),將啟動可程式設計補全功能。

首先,命令名被確認。如果針對這個命令有補全規則的定義,那麼將使用規則來產生可能的詞的補全的列表。如果命令詞是一個路徑全名,將首先搜尋針對這個路徑全名的規則。如果針對這個路徑全名沒有找到規則,將嘗試查詢 針對最後一個斜槓後面的部分的規則。

一旦找到了一個規則,它將用作產生匹配的詞。如果沒有找到,將進行上面 Completing 中描述的 bash 預設的補全。

首先,將執行規則指定的動作。只有以被補全的詞開始的匹配詞才會被返回。 當在檔案或目錄名補全中使用 -f 或 -d 選項時,shell 變數 FIGNORE 將用於對匹配進行過濾。

接下來,將產生所有由-G 選項給出的檔名擴充套件模式指定的補全。 模式產生的詞不必匹配要補全的詞。shell 變數 GLOBIGNORE 不會用於過濾匹配結果,但是變數 FIGNORE 會被使用。

接下來,將考慮 -W 選項的引數指定的字串。這個字串首先被劃分,用特殊變數 IFS 中的字元作為分隔符。shell 引用被當作一個詞。 接下來,每個詞被擴充套件,使用上面 EXPANSION 中描述的 brace expansion, tilde expansion, parametervariable expansion, command substitution, arithmetic expansion, 以及 pathname expansion 規則處理。對於結果,再使用上面 Word Splitting 中描述的規則劃分成詞。擴充套件的結果與要補全的詞進行前部一致的比較,匹配的詞成為可能的補全。

在這些匹配被產生後,任何由 -F -C 選項指定的 shell 函式和命令將被執行。當命令或函式被執行時,變數 COMP_LINECOMP_POINT 被賦值,使用上面 Shell Variables 中的規則。 如果要執行 shell 函式,還將設定變數 COMP_WORDSCOMP_CWORD 。當函式或命令被執行時,第一個引數是等待引數被補全的命令的名稱,第二個引數是要補全的詞,第三個引數是當前命令列中,要補全的詞前面的詞。對要補全的詞產生的補全不會進行任何過濾;函式或命令在產生匹配時有完全的自由。

任何 -F 指定的函式將被首先執行。函式可以使用任何 shell 功能, 包含內建命令 compgen,來產生匹配。它必須將可能的補全放到陣列變數 COMPREPLY 中。

(博主注)例如:

COMPREPLY=($(compgen -W "${fix_list}" -- "${cur}"))

接下來,任何 -C 選項指定的命令將被執行,其執行環境與命令替換 的環境相同。它應當向標準輸出列印一個補全的列表,每行一個。 反斜槓可以用來轉義一個新行符,如果需要的話。

所有可能的補全都產生之後,將對列表進行 -X 選項指定的任何過濾。過濾器是一個模式,和路徑名擴充套件中的一樣;模式中的 & 替換為要補全的詞。字面上的 & 可以用反斜槓轉義;反斜槓在進行匹配時被刪除。任何匹配這個模式的補全將從列表中刪除。前導的!將使模式含義相反; 這種情況下,任何不匹配這個模式的補全將被刪除。

最後,B-P-S 指定的任何字首和字尾被新增到補全列表的每個成員後面,結果返回給 readline 補全程式碼,作為可能的補全列表。

如果先前執行的動作沒有產生任何匹配,並且在定義 compspec 規則時,為 complete 命令提供了 -o dirname 選項,將嘗試目錄名補全。

預設情況下,如果找到了一個規則,它產生的任何東西都被返回給補全程式碼, 作為可能的補全的全集。不再嘗試預設的 bash 補全,readline 預設的檔名補全也會禁止。如果定義規則時,為 complete 命令提供了 -o default 選項,在規則沒有產生匹配時將進行 readline 預設的補全處理。

當一個規則指出期望目錄名補全時,可程式設計補全函式強制 readline 在補全的名稱後面新增一個斜槓,如果它是一個到目錄的符號連線。然後還要經過 readline 變數 mark-directories 的值處理,不管 readline 變數 mark-symlinked-directories 的值是什麼。

補全相關的 shell內建命令(SHELL BUILTIN COMMANDS)

compgen

compgen [option] [word]

根據 option word 產生可能的補全。option 是 內建命令 complete 接受的任何選項,除了 -p-r,將匹配結果寫到標準輸出。 當使用 -F-C 選項時,可程式設計補全功能所設定的多數 shell 變數如果存在,其值將不再有用。

產生的匹配與可程式設計補全程式碼根據補全規則加上相同的標誌直接產生的結果相同。 如果指定了 word,只有匹配 word 的補全結果將被顯示出來。

返回值為真,除非提供了非法的選項,或者沒有產生匹配。

complete

complete [-abcdefgjksuv] [-o comp-option] [-A action] [-G globpat] [-W wordlist] [-P prefix] [-S suffix]
		[-X filterpat] [-F function] [-C command] name [name ...]
complete -pr [name ...]

指定每個 name 的引數應當如何被補全。如果給出了 -p 選項, 或者沒有選項給出,現有的補全規則將被顯示出來,以一種可以重用為輸入 的格式顯示。-r 選項將一個針對每個 name 的補全規則刪除。或者,如果沒有給出 name,將刪除所有補全規則。

嘗試詞的補全時,應用這些補全規則的過程在上面 Programmable Completion(可程式設計補全) 中詳述。

其他選項,如果給出的話,具有下列意義。-G, -W, 和 -X 選項的引數 (如果需要的話,還包括 -P 和 -S 選項) 應當被引用,避免在執行內建命令 complete 之前被擴充套件。

返回值為真,除非給出了非法的選項,給出除 -p 和 -r 之外 的某個選項時沒有給出 name 引數,試圖刪除一條 name 的補全 規則但是規則不存在,或者新增補全規則時出錯。

-o comp-option

comp-option 控制著 compspec 除了簡單地產生補全之外的多種行為。 comp-option 可以是如下之一:

action meaning
default 使用 readline 的預設檔名補全,如果 compspec 沒有得到匹配
dirnames 進行目錄名補全,如果 compspec 沒有得到匹配
filenames 告訴 readline,compspec 產生了檔名,使它可以進行任何檔名專用的處理 (例如,給目錄名加上斜槓或消除尾部空白)。主要用於 shell 函式
nospace 告訴 readline 不要向補全的詞在行的最後新增一個空格 (這是預設行為)

-A action

action 可以是下列之一,來產生一系列可能的補全結果:

action meaning
alias 起別名。也可以用 -a 指定
arrayvar 陣列變數名
binding Readline 按鍵關聯
builtin shell 內建命令的名稱。也可以用 -b 指定
command 命令名。也可以用 -c 指定
directory 目錄名。也可以用 -d 指定
disabled 被禁用的內建命令名稱
enabled 啟用的內建命令名稱
export 被匯出的 shell 變數名稱。也可以用 -e 指定
file 檔名。也可以用 -f 指定
function shell 函式的名稱
group 組名。也可以用 -g 指定
helptopic 內建命令 help 接受的幫助主題
hostname 主機名,從環境變數 HOSTFILE 指定的檔案中得到
job 作業名,如果作業控制被啟用的話。也可以用 -j 指定
keyword shell 保留字。也可以用 -k 指定
running 正在執行的作業名,如果作業控制被啟用的話
service 服務名。也可以用 -s 指定
setopt 內建命令 set 的 -o 選項的有效引數
shopt 內建命令 shopt 接受的 shell 選項名
signal 訊號名
stopped 停止的作業名,如果作業控制被啟用的話
user 使用者名稱。也可以用 -u 指定
variable shell 變數的名稱。也可以用 -v 指定

-G globpat

檔名擴充套件模式 globpat 被擴充套件,產生可能的補全。

-W wordlist

wordlist 被使用 IFS 特殊變數中的字元作為定界符來拆分,每個結果的詞被擴充套件。可能的補全是結果列表 中匹配要補全的詞的那一些。

-C command

command 將在一個子 shell 環境中執行,它的結果用作可能的補全。

-F function

shell 函式 function 將在當前 shell 環境中執行。當它結束時,可能 的補全可以從陣列元素 COMPREPLY 中得到。

-X filterpat

filterpat 是一個模式,用於檔名擴充套件。所有前面的選項和引數產生 的可能的補全都要經過這一步處理,每一個匹配 filterpat 的補全都 被從列表中刪除。為 filterpat 加上前導 ! 使模式意義相反;這種情況下,所有不匹配 filterpat 的模式被刪除。

-P prefix

在所有其他選項都處理過之後,prefix 被加到每個可能的補全前面。

-S suffix

在所有其他選項都處理過之後,suffix 被加到每個可能的補全後面。

shopt

shopt [-pqsu] [-o] [optname ...]

對於控制可選的 shell 行為的變數,改變它們的值。沒有選項或者有-p選項時,將顯示所有可設定的選項列表,以及它們是否已經設定的指示。-p 使得輸出以一種可以被重用為輸入的形式顯示。

其他選項有如下含義:

  • -s: 允許(設定) 每個 optname。
  • -u: 禁止(取消) 每個 optname。
  • -q: 禁止通常的輸出 (安靜模式);返回狀態指示了 optname 是否被設定。 如果對 -q 給出了多個 optname 引數,如果所有 optname 都被允許,返回值就是 0; 否則返回非零值。
  • -o: 限制 optname 的值為內建命令 set 的 -o 選項定義的值。

如果使用 -s 或 -u 時沒有給出 optname 引數,顯示將分別限於被設定或被取消的選項。 除非另外說明,shopt 選項預設被禁止(取消)。

返回值在列出選項時是 0,如果所有 optname 都被允許的話,否則是非零值。 當設定或取消選項時,返回值是 0,除非 optname 是非法的 shell 選項。

shopt選項的列表是:

  • cdable_vars
    如果設定的話,內建命令 cd 的引數如果不是目錄,就假定是一個變數,它的值是要切換到的目錄名。
  • cdspell
    如果設定的話, cd 命令中目錄的細微拼寫錯誤能夠得以糾正。檢查的錯誤包括字元錯位,缺字元, 重複輸入同一字元。如果找到了正確的值,將列印正確的檔名,命令將繼續。 這個選項只能在互動 shell 中使用。
  • hostcomplete
    如果設定的話,並且正在使用 readline, bash 將試著對正在進行補全的包含 的詞進行主機名補全 (參見上面的 READLINE 中的 Completing 段落)。這是預設允許的。
  • no_empty_cmd_completion
    如果設定的話,並且正在使用 readline, 試圖在空行上執行補全時, bash 不會搜尋 PATH 來查詢可能的補全。
  • nocaseglob
    如果設定的話, bash 進行路徑擴充套件時使用大小寫不敏感方式匹配檔名(參見上面的 Pathname Expansion 路徑擴充套件)。
  • progcomp
    如果設定的話,將啟用可程式設計補全功能 (參見上面的 Programmable Completion)。 這個選項是預設啟用的。
  • ...

篇幅與文章主題的原因,不展開更多的shopt列表介紹。