วิธีกำหนดความสมบูรณ์ของคำสั่ง Bash เอง?


24

ในทุบตีมันง่ายพอที่จะตั้งค่าเสร็จสิ้นการอาร์กิวเมนต์คำสั่งที่กำหนดเองโดยใช้ในcompleteตัว ตัวอย่างเช่นหากคำสั่งสมมุติที่มีบทสรุปของfoo --a | --b | --cคุณสามารถทำได้complete -W '--a --b --c' foo

นอกจากนี้คุณยังสามารถปรับแต่งเสร็จสิ้นการที่คุณได้รับเมื่อคุณกดTabที่ว่างเปล่าพร้อมรับคำใช้เช่นcomplete -E complete -E -W 'foo bar'จากนั้นกดแท็บที่พร้อมท์ที่ว่างเปล่าจะแนะนำเท่านั้นและfoobar

ฉันจะกำหนดความสมบูรณ์ของคำสั่งเองได้ที่พรอมต์ที่ไม่ใช่ข้อยกเว้น เช่นถ้าฉันนั่งที่:

anthony@Zia:~$ f

วิธีทำเสร็จสิ้นการปรับแต่งเพื่อให้กดแท็บจะเสมอที่สมบูรณ์เพื่อfoo?

(กรณีจริงที่ฉันต้องการคือlocTABlocalcและพี่ชายของฉันซึ่งขอให้ฉันถามสิ่งนี้ต้องการด้วย mplayer)


2
คุณมีการพิจารณาเพียง aliasing locเพื่อlocalc? ฉันแนะนำทางเลือกเพราะหลังจากผ่านไประยะหนึ่งในการขุดและค้นหาฉันยังไม่พบวิธีในการปรับแต่ง bash ให้สมบูรณ์ด้วยวิธีนี้ มันอาจเป็นไปไม่ได้
jw013

@ jw013 ใช่ฉันมองไปครู่หนึ่งและไม่สามารถหาอะไรได้เลย ฉันคาดหวังว่าจะมีคนแนะนำให้เปลี่ยนมาใช้ zsh ด้วยเช่นกัน อย่างน้อยถ้า zsh ทำมันฉันสามารถพักผ่อนได้อย่างสบายใจที่รู้ว่า bash รุ่นต่อไปจะดีเช่นกัน 😀
derobert

คุณต้องกด TAB สองครั้งและจะทำคำสั่งให้เสร็จสมบูรณ์
ฟลอยด์

1
จะไม่ทำลายความสำเร็จอื่น ๆ ทั้งหมดใช่มั้ย ผมหมายถึงแม้ว่ามันจะเป็นไปได้ที่คุณจะไม่สามารถที่จะได้รับlocate, locale, lockfileหรือใด ๆ ของการขยายตัวอื่น ๆ locของ บางทีวิธีที่ดีกว่าคือการแมปกุญแจที่แตกต่างกับความสมบูรณ์ที่เฉพาะเจาะจงนั้น
terdon

1
คุณสามารถยกตัวอย่างของบริบทดังกล่าว (ซึ่งจะนำไปสู่ผลที่ต้องการloc<TAB>->localc)
damienfrancois

คำตอบ:


9

ความสำเร็จของคำสั่ง (พร้อมกับสิ่งอื่น ๆ ) จะถูกจัดการผ่านทุบตีReadLine เสร็จสิ้น สิ่งนี้ทำงานในระดับที่ต่ำกว่า "การทำโปรแกรมให้เสร็จสมบูรณ์" (ซึ่งถูกเรียกใช้เมื่อระบุคำสั่งและสองกรณีพิเศษที่คุณระบุไว้ด้านบน)

อัปเดต: bash-5.0 รุ่นใหม่ (ม.ค. 2019) เพิ่มcomplete -Iสำหรับปัญหานี้อย่างแน่นอน

คำสั่ง readline ที่เกี่ยวข้องคือ:

complete (TAB)
       Attempt to perform completion on the text  before  point.   Bash
       attempts completion treating the text as a variable (if the text
       begins with $), username (if the text begins with  ~),  hostname
       (if  the  text begins with @), or command (including aliases and
       functions) in turn.  If none of these produces a match, filename
       completion is attempted.

complete-command (M-!)
       Attempt  completion  on  the text before point, treating it as a
       command name.  Command completion attempts  to  match  the  text
       against   aliases,   reserved   words,  shell  functions,  shell
       builtins, and finally executable filenames, in that order.

ในทำนองเดียวกันกับที่พบมากขึ้นบางส่วนของนี้สามารถส่งมอบให้กับฟังก์ชั่นโดยใช้complete -Fbind -x

function _complete0 () {
    local -a _cmds
    local -A _seen
    local _path=$PATH _ii _xx _cc _cmd _short
    local _aa=( ${READLINE_LINE} )

    if [[ -f ~/.complete.d/"${_aa[0]}" && -x  ~/.complete.d/"${_aa[0]}" ]]; then
        ## user-provided hook
        _cmds=( $( ~/.complete.d/"${_aa[0]}" ) )
    elif [[ -x  ~/.complete.d/DEFAULT ]]; then
        _cmds=( $( ~/.complete.d/DEFAULT ) )
    else 
        ## compgen -c for default "command" complete 
        _cmds=( $(PATH=$_path compgen -o bashdefault -o default -c ${_aa[0]}) )  
    fi

    ## remove duplicates, cache shortest name
    _short="${_cmds[0]}"
    _cc=${#_cmds[*]} # NB removing indexes inside loop
    for (( _ii=0 ; _ii<$_cc ; _ii++ )); do
        _cmd=${_cmds[$_ii]}
        [[ -n "${_seen[$_cmd]}" ]] && unset _cmds[$_ii]
        _seen[$_cmd]+=1
        (( ${#_short} > ${#_cmd} )) && _short="$_cmd"
    done
    _cmds=( "${_cmds[@]}" )  ## recompute contiguous index

    ## find common prefix
    declare -a _prefix=()
    for (( _xx=0; _xx<${#_short}; _xx++ )); do
        _prev=${_cmds[0]}
        for (( _ii=0 ; _ii<${#_cmds[*]} ; _ii++ )); do
            _cmd=${_cmds[$_ii]}
             [[ "${_cmd:$_xx:1}" != "${_prev:$_xx:1}" ]] && break
            _prev=$_cmd
        done
        [[ $_ii -eq ${#_cmds[*]} ]] && _prefix[$_xx]="${_cmd:$_xx:1}"
    done
    printf -v _short "%s" "${_prefix[@]}"  # flatten 

    ## emulate completion list of matches
    if [[ ${#_cmds[*]} -gt 1 ]]; then
        for (( _ii=0 ; _ii<${#_cmds[*]} ; _ii++ )); do
            _cmd=${_cmds[$_ii]}
            [[ -n "${_seen[$_cmds]}" ]] && printf "%-12s " "$_cmd" 
        done | sort | fmt -w $((COLUMNS-8)) | column -tx
        # fill in shortest match (prefix)
        printf -v READLINE_LINE "%s" "$_short"
        READLINE_POINT=${#READLINE_LINE}  
    fi
    ## exactly one match
    if [[ ${#_cmds[*]} -eq 1 ]]; then
        _aa[0]="${_cmds[0]}"
        printf -v READLINE_LINE "%s " "${_aa[@]}"
        READLINE_POINT=${#READLINE_LINE}  
    else
        : # nop
    fi
}

bind -x '"\C-i":_complete0'

~/.complete.d/ซึ่งจะช่วยให้ตัวเองต่อคำสั่งหรือสตริงคำนำหน้าตะขอของคุณ เช่นถ้าคุณสร้างไฟล์ปฏิบัติการ~/.complete.d/locด้วย:

#!/bin/bash
echo localc

สิ่งนี้จะทำ (ประมาณ) สิ่งที่คุณคาดหวัง

ฟังก์ชั่นดังกล่าวข้างต้นไปกับความยาวบางส่วนที่จะเลียนแบบพฤติกรรมที่เสร็จสิ้นคำสั่งทุบตีปกติถึงแม้ว่ามันจะไม่สมบูรณ์ (โดยเฉพาะที่น่าสงสัยsort | fmt | columnที่นำติดตัวเพื่อแสดงรายการของการแข่งขัน)

อย่างไรก็ตามปัญหาที่ไม่สำคัญกับเรื่องนี้มันสามารถใช้ฟังก์ชั่นเพื่อแทนที่การผูกกับcompleteฟังก์ชั่นหลัก(เรียกใช้กับ TAB โดยค่าเริ่มต้น)

วิธีการนี้จะทำงานได้ดีกับการโยงคีย์ที่แตกต่างกันซึ่งใช้สำหรับการทำคำสั่งที่กำหนดเองให้เสร็จสมบูรณ์ แต่ก็ไม่ได้ใช้ตรรกะการเติมเต็มที่สมบูรณ์หลังจากนั้น (เช่นคำต่อมาในบรรทัดคำสั่ง) การทำเช่นนั้นจะต้องแยกวิเคราะห์บรรทัดคำสั่งจัดการกับตำแหน่งเคอร์เซอร์และสิ่งอื่น ๆ ที่อาจไม่ควรพิจารณาในเชลล์สคริปต์ ...


1

ผมไม่ทราบว่าถ้าผม unterstood ต้องการของคุณสำหรับนี้ ... นี้จะบ่งบอกว่าทุบตีของคุณเท่านั้นที่รู้คำสั่งหนึ่งที่เริ่มต้นด้วย
แนวคิดพื้นฐานของความสำเร็จคือ: ถ้ามันคลุมเครือให้พิมพ์ความเป็นไปได้ ดังนั้นคุณสามารถตั้งค่าเป็นไดเรกทอรีที่มีคำสั่งนี้เพียงคำเดียวและปิดใช้งาน bash builtins ทั้งหมดเพื่อให้ได้งานนี้f

PATH

อย่างไรก็ตามฉันสามารถให้วิธีแก้ปัญหากับคุณเช่นกัน:

alias _='true &&'
complete -W foo _

ดังนั้นถ้าคุณพิมพ์_ <Tab>มันจะเสร็จสิ้นการที่รัน_ foofoo

แต่อย่างไรก็ตามalias f='foo'จะง่ายกว่ามาก


0

คำตอบง่ายๆสำหรับคุณก็คือ

$ cd into /etc/bash_completion.d
$ ls

เพียงแค่เอาต์พุตพื้นฐาน

autoconf       gpg2               ntpdate           shadow
automake       gzip               open-iscsi        smartctl
bash-builtins  iconv              openssl           sqlite3
bind-utils     iftop              perl              ssh
brctl          ifupdown           pkg-config        strace
bzip2          info               pm-utils          subscription-manager
chkconfig      ipmitool           postfix           tar
configure      iproute2           procps            tcpdump
coreutils      iptables           python            util-linux
cpio           lsof               quota-tools       wireless-tools
crontab        lvm                redefine_filedir  xmllint
cryptsetup     lzma               rfkill            xmlwf
dd             make               rpm               xz
dhclient       man                rsync             yum.bash
e2fsprogs      mdadm              scl.bash          yum-utils.bash
findutils      module-init-tools  service
getent         net-tools          sh

เพียงเพิ่มโปรแกรมที่คุณต้องการในการทำให้สมบูรณ์โดยอัตโนมัติ


2
ไฟล์เหล่านั้นมีเชลล์สคริปต์อยู่ในนั้นบางอันค่อนข้างซับซ้อนหากฉันจำได้ถูกต้อง นอกจากนี้พวกเขายังทำข้อโต้แย้งให้สมบูรณ์เมื่อคุณพิมพ์คำสั่งแล้ว ... พวกเขาไม่ได้ทำตามคำสั่งให้เสร็จสมบูรณ์
Derobert

ฉันเข้าใจสิ่งที่คุณหมายถึง เมื่อคุณสามารถดูเอกสารนี้: debian-administr.org/article/316/…
unixmiah

-3

เรียกใช้คำสั่งด้านล่างเพื่อค้นหาตำแหน่งที่ติดตั้งไบนารีของ mplayer:

which mplayer

หรือใช้เส้นทางไปยัง mplayer binary หากคุณรู้ว่ามันอยู่ในคำสั่งด้านล่าง:

ln -s /path/to/mplayer /bin/mplayer

ทุกอย่างที่คุณพิมพ์จะถูกค้นหาในไดเรกทอรีทั้งหมดที่ระบุใน$PATHตัวแปร


2
สวัสดีแม็ตธิวยินดีต้อนรับสู่ Unix & Linux ฉันคิดว่าคำถามของ OP นั้นซับซ้อนกว่าคำตอบที่คุณแนะนำเล็กน้อย ฉันเข้าใจว่าmplayerมีอยู่แล้วในพวกเขา$PATHและพวกเขาต้องการสิ่งที่ต้องการmp<tab>ผลิตmplayerแทนที่จะเป็นไบนารีทั้งหมดที่ขึ้นต้นด้วยmp(เช่นmpage mpcd mpartition mplayerฯลฯ )
drs
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.