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 選項指定的任何過濾。過濾器是一個模式,和路徑名擴展中的一樣;模式中的 & 替換爲要補全的詞。字面上的 & 可以用反斜槓轉義;反斜槓在進行匹配時被刪除。任何匹配這個模式的補全將從列表中刪除。前導的!將使模式含義相反; 這種情況下,任何不匹配這個模式的補全將被刪除。

最後,-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列表介紹。

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