久久久精品2019中文字幕神马_欧美亚洲一区三区_欧美大人香蕉在线_精品88久久久久88久久久_中文字幕一区二区三区在线播放 _精品国产一区二区三区久久影院_欧洲av在线精品_粉嫩av一区二区三区_亚洲欧美一区二区三区极速播放_国产亚洲精品久久

首頁 > 房產

【環球報資訊】在命令行按下tab鍵之后, 發生了生么?

來源:博客園 時間:2023-06-25 06:26:08

1. 引言2. complete命令3. 自定義補全列表4. 動態補全列表5. compgen命令6. 別名的自動補全7. 補全規則永久生效8. 自動加載9. 參考1. 引言

當我們輸入ls 再按下TAB時, 會自動列出當前路徑下所有的文件;

當我們輸入ls a再按下TAB時, 會自動列出當前路徑下所有以a開頭的文件; 若只有一個以a開頭的文件, 將會自動補全;

當我們輸入type 再按下TAB時, 會自動列出全所有可執行的命令;


(相關資料圖)

當我們輸入docker rmi 再按下TAB時, 會自動列出所有鏡像名;

一個顯示文件, 一個顯示命令, 一個顯示容器名, 這是怎么做到的?

本文將帶你一探究竟, 并以docker為例, 實現一個簡單的docker自動補全規則

2. complete命令

上述功能, 是 Bash 2.05 版本新增的功能, 叫做自動補全. 自動補全允許我們對命令和選項設置補全規則, 按下TAB之后, 會根據我們設置的規則返回補全列表, 當補全列表只有一個元素時, 就會自動補全.

bash自動補全用到最主要的命令就是complete, 這是一個Bash的內置命令(builtin), 用于指定某個命令的補全規則, complete語法如下:

complete [-abcdefgjksuv] [-o comp-option] [-DEI] [-A action] [-G globpat] [-W wordlist] [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [name …]complete -pr [-DEI] [name …]選項:    -o comp-option        定義一些補全的行為, 可以使用的行為如下:        nospace    補全后不在最后添加空格        nosort     對于補全列表不要按字母排序    -A action        使用預設的補全規則, 可使用的補全規則如下:        alias        補全列表設置為所有已定義的別名. 等同于-a        builtin      補全列表設置為所有shell內置命令. 等同于-b        command      補全列表設置為所有可執行命令. 等同于-c        directory    補全列表設置為當前路徑下所有目錄. 等同于-d,                     也就是說 complete -d xxx 與 complete -A directory xxx 等價, 只是寫法不一樣        export       補全列表設置為所有環境變量名. 等同于-e        file         補全列表設置為當前路徑下所有文件. 等同于-f        function     補全列表設置為所有函數名        signal       補全列表設置為所有信號名        user         補全列表設置為所有用戶名. 等同于-u        variable     補全列表設置為所有變量名. 等同于-v    -F function        用函數來定義補全規則, 函數運行后 COMPREPLY 變量做為補全列表    -W wordlist        用一個字符串來做為補全列表    -p name        顯示某個命令的補全規則, 如果 name 為空的話則顯示所有命令的補全規則    -r        移除某個命令的補全規則

ls命令默認的補全列表是當前路徑下所有文件, 現在, 我們改變其補全規則, 讓其補全列表變為所有可執行命令

$ cd /# 先測試下 ls 默認的補全規則$ lsbin/    boot/   dev/    etc/    home/   lib/    lib32/  lib64/  libx32/ media/  mnt/    opt/    proc/   root/   run/    sbin/   srv/    sys/    tmp/    usr/    var/# 修改 ls 的補全規則, 讓所有可執行命令作為其補全列表$ complete -c ls# 測試修改補全規則后的 ls$ ls whowho                   whoami                whoopsie              whoopsie-preferences

提示: 上述改變的補全規則只在當前shell有效, 即不會影響到其他用戶, 重新登錄后也會失效. 所以想要恢復ls命令的補全規則的話, 只需要退出再重新登錄服務器就好了. 至于如何永久改變補全規則, 請看后文.

我們再來看下type命令預設的補全規則, 發現type命令設置的補全列表是所有可執行命令

$ complete -p typecomplete -c type

至此, 我們應該知道引言中所提出的問題, 為什么ls命令會文件而type命令會列出命令

3. 自定義補全列表

盡管Bash預設了很多補全規則, 但是很明顯, 如果我們自己想給docker命令寫補全規則的話, 預設的補全規則顯然是不能滿足我們需求的. 所以, 我們可以用-W選項來自定義補全列表.

假設我們自己寫了個mydocker命令, 可以使用的功能有mydocker rm, mydocker rmi, mydocker stop, mydocker start, 顯然, mydocker的補全列表為rm rmi stop start, 我們可以使用下面的命令來設置補全規則

# 將 rm rmi stop start 設置為 mydocker 的補全列表$ complete -W "rm rmi stop start" mydocker$ mydockerrm     rmi    start  stop$ mydocker ststart  stop

到這一步, 我們已經能給相當一部分的命令來定義補全規則了. 但是, 上述的"-W"選項, 是靜態的補全規則, 不會隨著某些條件的改變而變化; docker rmi 所有顯示的鏡像名, 會隨著鏡像的增刪而改變; docker rm 所有顯示的容器名, 會隨著容器的增刪而改變; 是動態的補全規則, 這是如何做到的呢?

我們直接通過-p選項來查看docker預設的補全規則就好了, 發現docker命令是通過-F _docker來指定補全規則; 再通過type _docker來查看_docker是什么玩意, 發現_docker是一個非常復雜的函數

$ complete -p dockercomplete -F _docker docker$ type _docker_docker is a function_docker (){    ......}

接下來, 我們來好好聊一聊-F這個選項

4. 動態補全列表

-F選項會指定一個函數做為補全規則, 每次按下TAB時, 就會調用這個函數, 并且將COMPREPLY的值做為補全列表, 所以我們需要在函數中處理COMPREPLY變量

除了COMPREPLY變量外, Bash還提供了一些變量來方便我們獲取當前的輸入

變量名類型說明
COMP_LINE字符串當前的命令行輸入的所有內容
COMP_WORDS數組當前的命令行輸入的所有內容, 和COMP_LINE不同的是, 這個變量是一個數組
COMP_CWORD整數當前的命令行輸入的內容位于COMP_WORDS數組中的索引
COMPREPLY數組補全列表

接下來我們編寫一個補全腳本來測試這些變量, 腳本名字可以隨便取, 暫且叫做 test.sh, 文件內容如下:

_complete_test() {    echo    echo "COMP_LINE: $COMP_LINE"                # 當前的命令行輸入的所有內容(字符串)    echo "COMP_WORDS: ${COMP_WORDS[@]}"         # 當前的命令行輸入的所有內容(數組)    echo "COMP_CWORD: $COMP_CWORD"              # 數組的索引    echo "last_word: ${COMP_WORDS[COMP_CWORD]}" # 最后一個輸入的單詞    echo "COMPREPLY: $COMPREPLY"                # 補全列表}complete -F _complete_test mydocker

我們通過執行source test.sh來使腳本生效, 然后來測試腳本

$ source test.sh$ mydocker COMP_LINE: mydocker    # 當前的命令行輸入的所有內容(字符串)COMP_WORDS: mydocker   # 當前的命令行輸入的所有內容(數組)COMP_CWORD: 1          # 數組的索引last_word:             # 最后一個輸入的單詞COMPREPLY:             # 補全列表$ mydocker xyCOMP_LINE: mydocker xy    # 當前的命令行輸入的所有內容(字符串)COMP_WORDS: mydocker xy   # 當前的命令行輸入的所有內容(數組)COMP_CWORD: 1             # 數組的索引last_word: xy             # 最后一個輸入的單詞COMPREPLY:                # 補全列表

我們理解了上述的變量之后, 我們是不是可以這樣做: 獲取當前輸入的內容, 如果是mydocker的話, 將補全列表設置為rm rmi stop start; 如果是mydocker rm的話, 查詢出所有的容器名, 并將補全列表設置為所有的容器名, startstop同理; 如果是mydocker rmi的話, 補全列表設置為所有的鏡像名. 因為每次自動補全都會執行我們的函數, 所以我們的補全列表就是動態的了

在修改test.sh腳本之前, 我們造一點測試數據, 拉取兩個鏡像并運行這兩個鏡像

$ docker pull redis$ docker pull redmine

接下來將test.sh腳本修改為如下內容:

_complete_mydocker() {    local prev    prev="${COMP_WORDS[COMP_CWORD-1]}"    case "${prev}" in        rm) COMPREPLY=( $(docker ps -a | tail -n +2 | awk "{print $NF}") ) ;;        rmi) COMPREPLY=( $(docker images | tail -n +2 | awk "{print $1}") );;        mydocker) COMPREPLY=( rm rmi stop start ) ;;    esac}complete -F _complete_mydocker mydocker

注意: case語句中判斷的是倒數第二個輸入的單詞, 因為當我們運行mydocker r時, 最后一個單詞是r, 倒數第二個單詞是mydocker, 顯然此時我們需要的是mydocker的補全列表

修改完腳本后, 要再次執行source test.sh才能使腳本生效. 然后來測試腳本

$ mydocker rm     rmi    start  stop# 貌似有點問題?$ mydocker rmrm     rmi    start  stop$ mydocker rmi redis             redmine# 貌似又有問題?$ mydocker rmi rediredis            redmine

目前的補全腳本還是存在一些問題, 其實也很容易發現問題, 無論我們輸入mydocker rmi re還是mydocker rmi redi, 都會匹配到補全腳本中的rmi) COMPREPLY=( $(docker images | tail -n +2 | awk "{print $1}") );;, 我們返回的補全列表COMPLETE都是同樣的結果, 補全列表并沒有變, 補全列表返回的都是redis redmine. 然而, 我們想要的是, 輸入mydocker rmi re返回redis redmine, 輸入mydocker rmi redi返回redis, 這就需要compgen命令出場了

Tips: 可能有些讀者會有疑問, 為什么設置同樣的候選列表, 使用-W就和預期一樣而使用-F就會出現上述問題, 因為-W已經幫我們實現了類似compgen的功能, 而-F需要我們手動處理才行

5. compgen命令

compgen也是一個Bash內置命令, 其選項幾乎和complete是通用的, 其作用就是篩選, 看幾個例子大家就明白怎么用了

# -W指定補全列表, 并返回與st相匹配的值$ compgen -W "rm    rmi    start    stop" -- ststartstop# -W指定補全列表, 并返回與sto相匹配的值$ compgen -W "rm    rmi    start    stop" -- stostop# -b指定補全列表為Bash內置命令, 并返回與c相匹配的值$ compgen -b -- ccallercdcommandcompgencompletecompoptcontinue

學會了compgen命令, 我們再來修改腳本, 將COMPREPLY=( rm rmi stop start )修改為COMPREPLY=( $(compgen -W "rm rmi stop start" -- 最后一個單詞) )就可以動態修改補全列表了

最后將腳本修改如下:

_complete_mydocker() {    local cur prev mydocker_opts images contains    cur="${COMP_WORDS[COMP_CWORD]}"    prev="${COMP_WORDS[COMP_CWORD-1]}"    mydocker_opts="rm rmi stop start"    images=$(docker images | tail -n +2 | awk "{print $1}")    contains=$(docker ps -a | tail -n +2 | awk "{print $NF}")    case "${prev}" in        rm) COMPREPLY=( $(compgen -W "${contains}" -- ${cur}) ) ;;        rmi) COMPREPLY=( $(compgen -W "${images}" -- ${cur}) );;        mydocker) COMPREPLY=( $(compgen -W "${mydocker_opts}" -- ${cur}) ) ;;    esac}complete -F _complete_mydocker mydocker

執行腳本后再次測試腳本, 已經能達到我們想要的效果了

$ mydocker rm     rmi    start  stop$ mydocker rmrm   rmi $ mydocker rmi redis             redmine$ mydocker rmi reredis             redmine# 這里就會自動補全了$ mydocker rmi redi
6. 別名的自動補全

筆者用docker相關的命令用的比較多, 不想每次敲這么長, 所以直接執行alias d=dockerd設置為docker的別名, 設置后方是方便了很多, 但是用不了自動補全

沒關系, 既然docker有自動補全, 那么d也必須有自動補全. 通過執行complete命令發現, docker的補全規則是_docker函數提供的

$ complete -p dockercomplete -F _docker docker

那我們只需要執行complete -F _docker d, 將d的補全規則設置為_docker, 這樣d也可使用自動補全了

$ d build      cp         events     help       images     inspect    login      network    plugin     pull       restart    run        secret     start      swarm      top        version    commit     create     exec       history    import     kill       logout     node       port       push       rm         save       service    stats      system     unpause    volume     container  diff       export     image      info       load       logs       pause      ps         rename     rmi        search     stack      stop       tag        update     wait   
7. 補全規則永久生效

上述例子中, 我們執行補全規則腳本, 使用的是. completion_script或者source completion_script的形式來執行, 而不是通過./completion_scriptbash completion_script的形式來執行, 是因為: 前者的作用范圍是當前shell; 而后者會在子shell中執行, 不會影響到當前shell, 看起來就和沒執行一樣. 子shell是另外一個很重要的概念, 感興趣的讀者可自行了解.

由于source completion_script的作用范圍是當前shell, 所以我們設置的補全規則不會影響到其他用戶, 同時也會在重新登錄后失效. 要使補全規則永久生效, 我們將source completion_script本添加到 ~/.bashrc或者 ~/.profile文件中即可. 因為這兩個文件是Bash的初始化文件, 每次登錄Bash都會執行初始化文件, 所以就可以達到永久生效的效果.

8. 自動加載

最后提一下自動補全腳本是如何自動加載的. 入口是 /etc/bash.bashrc這個文件, 其會調用 /usr/share/bash-completion/bash_completion/etc/bash_completion

$ cat /etc/bash.bashrc............if ! shopt -oq posix; then  if [ -f /usr/share/bash-completion/bash_completion ]; then    . /usr/share/bash-completion/bash_completion  elif [ -f /etc/bash_completion ]; then    . /etc/bash_completion  fifi

查看 /etc/bash_completion得知, 無論調用哪個文件, 最后實際上調用的都是 /usr/share/bash-completion/bash_completion

$ cat /etc/bash_completion. /usr/share/bash-completion/bash_completion

打開 /usr/share/bash-completion/bash_completion文件, 在2151行左右, 有以下一段代碼, 大概意思就是會執行 /etc/bash_completion.d中的每個文件, 所以, 我們將自動補全腳本放在這個路徑下, 并設置好讀權限, 每次登錄系統就會自動加載, 也可以達到永久生效的效果.

$ cat /usr/share/bash-completion/bash_completion............compat_dir=${BASH_COMPLETION_COMPAT_DIR:-/etc/bash_completion.d}if [[ -d $compat_dir && -r $compat_dir && -x $compat_dir ]]; then    for i in "$compat_dir"/*; do        [[ ${i##*/} != @($_backup_glob|Makefile*|$_blacklist_glob) \            && -f $i && -r $i ]] && . "$i"    donefi

實際上, Ubuntu中一般的自動補全腳本一般放在 /usr/share/bash-completion/completions/, 也會自動加載, 入口是 /etc/bash_completion.d的2132行左右寫道了complete -D -F _completion_loader, 這里就不展開講了.

9. 參考https://www.gnu.org/software/bash/manual/bash.html#Programmable-Completion-Builtins

相關稿件

【環球報資訊】在命令行按下tab鍵之后, 發生了生么?

谷歌稱愿為Stadia花五年打造3A游戲 奈何成本太高_當前速讀

車保險到期了不開可以先不交嗎

如何養護丙烯酸涂料,讓你的禮物更持久美麗?男生必看送女生禮物小技巧!|今亮點

黃金消費旺 吉祥又時尚 每日關注

動物園里過端午

環球今頭條!重慶四環來了!將形成“四環二十二射六十聯線”高速公路網布局

Lisa Selesner(lisa selesner)|環球關注

天天新動態:女子用蹲便器洗粽葉被吐槽 店老板:沒連接下水道

要學會取舍_天天時快訊

上汽大眾全新Polo Plus怎么樣及廣汽謳歌TLX-L 2.4L多少錢|全球速訊

【當前獨家】讓傳統節日綻放時代新韻(今日談)

潮訊:蘋果終于修復這漏洞;安卓比iOS更容易使用;手機NFC功能要徹底變了;Flyme10修復了這些問題

溫迪的蝴蝶結怎么系?

“夏日夜經濟”火熱 激發消費新活力

每日消息!webhits.dll缺少打不開怎么辦

天天熱消息:蝴蝶結扣怎么系好看?

紐約記者:尼克斯內部有一些人士有意迪文岑佐|快訊

全球聚焦:收藏!高考查分報志愿時間表

市第八屆中華龍舟賽圓滿閉幕

剪輯視頻需要版權嗎?存在侵權嗎?

南方 16 條河流發生超警洪水,水利部門全力做好暴雨洪水防御 天天微資訊

山東高速駛入高質量發展“快車道” 當前視訊

聚焦尼山對話丨滿目是“尼”

西安經開區舉辦西安市“新征程、再出發”應急詩歌誦讀暨安全文化演出活動-全球滾動

老人發病將孫子托付路邊店主后病逝 疑似是心肌梗塞|今日關注

【世界時快訊】頂級影像旗艦——vivoX90Pro+,人手僅需5878元

世界消息!兩小時抵達 蘇州上?!巴ǖ罔F”

世界熱文:墾利區勝坨鎮召開安全生產工作專題會議

【環球新視野】Meta將在加拿大終止提供新聞服務


久久久精品2019中文字幕神马_欧美亚洲一区三区_欧美大人香蕉在线_精品88久久久久88久久久_中文字幕一区二区三区在线播放 _精品国产一区二区三区久久影院_欧洲av在线精品_粉嫩av一区二区三区_亚洲欧美一区二区三区极速播放_国产亚洲精品久久
久久综合精品国产一区二区三区| 亚洲免费三区一区二区| 久久一区二区三区四区| 精品一区二区三区免费| 日韩视频在线一区二区| 国产精品综合一区二区| 亚洲免费在线视频| 一本大道久久a久久综合| 亚洲mv在线观看| 精品国产网站在线观看| 欧美亚洲国产bt| 国产成人亚洲综合a∨猫咪| 亚洲一区电影777| 色婷婷av一区二区三区软件| 欧美成人免费网站| 国产精品亚洲成人| 国产精品二三区| 久久伊人蜜桃av一区二区| 欧美成人a在线| 国产美女主播视频一区| 午夜免费欧美电影| 中文字幕中文在线不卡住| 91视频.com| 国产成都精品91一区二区三| 久久综合九色综合欧美就去吻| 色综合色狠狠综合色| 丁香亚洲综合激情啪啪综合| 亚洲综合丁香婷婷六月香| 一区二区三区蜜桃| 免费看欧美女人艹b| 蜜桃av一区二区在线观看| 日韩福利电影在线| 毛片av一区二区| 精品国产百合女同互慰| 国产精品一区专区| 亚洲第一福利视频在线| 亚洲成a人片在线观看中文| 日韩一区精品字幕| 国产69精品久久777的优势| 久久国产视频网| 久久电影国产免费久久电影| 热久久国产精品| 蜜桃视频一区二区三区在线观看| 日韩一二在线观看| 欧美老肥妇做.爰bbww视频| 欧美一级免费大片| 91精品1区2区| 97se亚洲国产综合自在线不卡| 欧美伊人久久大香线蕉综合69| 国产+成+人+亚洲欧洲自线| 精品视频一区三区九区| 国产精品亚洲一区二区三区妖精| 国产麻豆精品一区二区| 欧美一区二区成人| 欧美三级午夜理伦三级中视频| 精品国产成人在线影院| 精品国产sm最大网站免费看 | 中文字幕一区三区| 国产成人日日夜夜| 久久综合久久鬼色中文字| 日韩中文字幕麻豆| 日韩欧美视频在线| 国内成人精品2018免费看| 成人精品鲁一区一区二区| 日本韩国精品在线| 日韩成人一级片| 欧美va日韩va| 成人综合婷婷国产精品久久蜜臀| 99re这里只有精品6| 一区二区三区资源| 欧美三级在线看| 国内外成人在线| 最好看的中文字幕久久| 9色porny自拍视频一区二区| 1024成人网色www| 久久久久久久久久久久电影| 99精品视频在线免费观看| 久久国产视频网| 亚洲丝袜另类动漫二区| 91小视频免费看| 日韩电影在线免费观看| 欧美xxxxxxxx| 69堂国产成人免费视频| 亚欧色一区w666天堂| 精品久久久久久久一区二区蜜臀| 日本aⅴ免费视频一区二区三区| 精品国产精品一区二区夜夜嗨| 国产成人三级在线观看| 五月婷婷久久综合| 亚洲国产视频一区| 日韩视频一区在线观看| 不卡的av在线| 九九视频精品免费| 久久www免费人成看片高清| 日韩精品一区二区在线| 欧美亚洲动漫精品| 91美女视频网站| 国产91精品露脸国语对白| 麻豆视频一区二区| 久久97超碰国产精品超碰| 韩国三级中文字幕hd久久精品| 亚洲色图在线看| 一区二区三区在线播| 亚洲自拍偷拍综合| 日韩毛片精品高清免费| 日韩欧美综合一区| 精品国产一区二区三区av性色 | 久久久综合精品| 欧美日韩一区久久| 97精品视频在线观看自产线路二| 日韩av一级片| 亚洲午夜免费视频| 精品午夜久久福利影院| 国产东北露脸精品视频| 成人激情小说乱人伦| 欧美日韩精品一区二区| 色狠狠综合天天综合综合| 国产成人av福利| 欧美一区二区精品久久911| 国产免费成人在线视频| 免费不卡在线观看| 色素色在线综合| 国产精品久久久久影院老司| 麻豆精品久久精品色综合| 色妞www精品视频| 亚洲精品乱码久久久久| 国产精品一区二区久久不卡| 91麻豆免费看| 亚洲综合男人的天堂| 不卡的电影网站| 国产日韩欧美a| 亚洲宅男天堂在线观看无病毒| 精品一区中文字幕| 日韩欧美一级精品久久| 亚洲va国产va欧美va观看| 欧美电影一区二区| 免费成人av在线播放| 日韩女优视频免费观看| 国产精品成人一区二区艾草| 国产乱码精品一品二品| 中文字幕第一区二区| 欧美亚洲日本一区| 国产在线视频精品一区| 亚洲欧美激情一区二区| 欧美一区二区三区喷汁尤物| 国产在线视频不卡二| 亚洲天堂av老司机| 欧美高清hd18日本| 成人午夜视频在线| 久久机这里只有精品| 欧美大片在线观看| 蜜臀av性久久久久蜜臀aⅴ四虎| 欧美v日韩v国产v| 欧美精品三级日韩久久| 一本大道久久精品懂色aⅴ | 久久先锋影音av| 97se亚洲国产综合自在线不卡| 亚洲成人手机在线| 日韩伦理av电影| 国产精品久久毛片| 久久精品亚洲精品国产欧美| 欧美日韩国产不卡| 欧美日韩一级二级| 欧美大片拔萝卜| 日韩免费在线观看| 色婷婷一区二区三区四区| 亚洲超丰满肉感bbw| 欧美大片一区二区三区| 成人激情综合网站| 91精品福利在线| 成人精品亚洲人成在线| 岛国一区二区在线观看| www.亚洲色图| 99久久伊人网影院| 91福利资源站| 777亚洲妇女| 中文字幕欧美日本乱码一线二线| 91丨九色丨蝌蚪丨老版| 国产iv一区二区三区| 国产高清久久久| 丁香婷婷深情五月亚洲| 国内精品伊人久久久久av影院| 九九九久久久精品| 亚洲精选免费视频| 极品少妇一区二区三区精品视频 | 国产精品国产三级国产aⅴ中文 | 精品久久久久久最新网址| 国内精品自线一区二区三区视频| 狠狠v欧美v日韩v亚洲ⅴ| 99国产精品久久久久| 在线不卡免费欧美| 日韩久久精品一区| 欧美一区二区日韩一区二区| 国产精品私人影院| 国产在线精品一区二区夜色| 91麻豆免费看| 欧美一区二区福利在线| 精品国产免费久久| 久久精品国产成人一区二区三区| 欧洲精品在线观看|