Takma adları için sekme tamamlama işlemi gerçekleştirmek için nasıl bash elde edebilirim?


45

Bir sürü bas tamamlama betiği ayarlamıştım (çoğunlukla bash-it ve bazılarını el ile ayarlayarak).

Ben de böyle genel görevler için diğer adları kurulum bir grup var gcoiçin git checkout. Şu anda yazabilir git checkout dTabve developbenim için tamamlandı ama yazarken gco dTabtamamlanmadı.

Bunun, tamamlama komut dosyasının tamamlandığı gitve göremediği için olduğunu farz ediyorum gco.

Tüm tamamlama komut dosyalarımın takma adlarımla çalışmasını genel olarak / programatik olarak elde etmenin bir yolu var mı? Takma adı kullanırken tamamlanamaması, takma adın amacını yitirir.


Hangi işletim sistemi ve bash kullanıyorsunuz? Ubuntu 11.10 ve bash 4.2.10 (1) -teazıyorum (x86_64-pc-linux-gnu) ve birçok takma ad için kabuğumda yerleşik olarak bu işlevselliğe sahibim. btw bash --versionbunu almak için ( -vfarklı çıktı kullanmayın ).
Michael Durrant,

Özür dilerim, biraz bilgi eksik - OSX Lion, GNU bash, sürüm 3.2.48 (1) - sürüm (x86_64-apple-darwin11)
dstarh

1
@killermist: Tamamen yanılmıyorsam, zsh, diğer isimlendirilmiş komutları da kutudan çıkarmaz. Tanımlanmış takma adları tamamlamaya ekleyen bir işlev uygulamak, zhs'nin tamamlama sistemi bash'den daha güçlü ve daha basit göründüğü için bash için çok daha kolay gibi görünmektedir.
kopischke

Siteler arası kopya kopyası: stackoverflow.com/questions/342969/…
Ciro Santilli,

1
@MichaelDurrant Bunun aslında takma adlar için yerleşik olduğundan emin misiniz? Bash 4.3.42 (1) -resease (x86_64-pc-linux-gnu) ile Ubuntu 15.10'dayım ve böyle bir şey yok. Ayrıca birkaç önceki sürümleri de test ettim. Örneğin, eğer yazarsanız ll --[TAB], bir seçenek listesi yazdırır ls? Bundan şüpheliyim, ancak 11.10'da böyle bir şeyin var olduğundan eminseniz, araştırmak ve neyin kaldırıldığını belirlemek isterim.
Altı

Yanıtlar:


42

Bu Yığın Taşması yanıtından ve bu Ubuntu Forumları tartışma dizisinden uyarlanan aşağıdaki kod, tanımlanmış tüm takma adlarınız için tamamlamalar ekleyecektir:

# Automatically add completion for all aliases to commands having completion functions
function alias_completion {
    local namespace="alias_completion"

    # parse function based completion definitions, where capture group 2 => function and 3 => trigger
    local compl_regex='complete( +[^ ]+)* -F ([^ ]+) ("[^"]+"|[^ ]+)'
    # parse alias definitions, where capture group 1 => trigger, 2 => command, 3 => command arguments
    local alias_regex="alias ([^=]+)='(\"[^\"]+\"|[^ ]+)(( +[^ ]+)*)'"

    # create array of function completion triggers, keeping multi-word triggers together
    eval "local completions=($(complete -p | sed -Ene "/$compl_regex/s//'\3'/p"))"
    (( ${#completions[@]} == 0 )) && return 0

    # create temporary file for wrapper functions and completions
    rm -f "/tmp/${namespace}-*.tmp" # preliminary cleanup
    local tmp_file; tmp_file="$(mktemp "/tmp/${namespace}-${RANDOM}XXX.tmp")" || return 1

    local completion_loader; completion_loader="$(complete -p -D 2>/dev/null | sed -Ene 's/.* -F ([^ ]*).*/\1/p')"

    # read in "<alias> '<aliased command>' '<command args>'" lines from defined aliases
    local line; while read line; do
        eval "local alias_tokens; alias_tokens=($line)" 2>/dev/null || continue # some alias arg patterns cause an eval parse error
        local alias_name="${alias_tokens[0]}" alias_cmd="${alias_tokens[1]}" alias_args="${alias_tokens[2]# }"

        # skip aliases to pipes, boolean control structures and other command lists
        # (leveraging that eval errs out if $alias_args contains unquoted shell metacharacters)
        eval "local alias_arg_words; alias_arg_words=($alias_args)" 2>/dev/null || continue
        # avoid expanding wildcards
        read -a alias_arg_words <<< "$alias_args"

        # skip alias if there is no completion function triggered by the aliased command
        if [[ ! " ${completions[*]} " =~ " $alias_cmd " ]]; then
            if [[ -n "$completion_loader" ]]; then
                # force loading of completions for the aliased command
                eval "$completion_loader $alias_cmd"
                # 124 means completion loader was successful
                [[ $? -eq 124 ]] || continue
                completions+=($alias_cmd)
            else
                continue
            fi
        fi
        local new_completion="$(complete -p "$alias_cmd")"

        # create a wrapper inserting the alias arguments if any
        if [[ -n $alias_args ]]; then
            local compl_func="${new_completion/#* -F /}"; compl_func="${compl_func%% *}"
            # avoid recursive call loops by ignoring our own functions
            if [[ "${compl_func#_$namespace::}" == $compl_func ]]; then
                local compl_wrapper="_${namespace}::${alias_name}"
                    echo "function $compl_wrapper {
                        (( COMP_CWORD += ${#alias_arg_words[@]} ))
                        COMP_WORDS=($alias_cmd $alias_args \${COMP_WORDS[@]:1})
                        (( COMP_POINT -= \${#COMP_LINE} ))
                        COMP_LINE=\${COMP_LINE/$alias_name/$alias_cmd $alias_args}
                        (( COMP_POINT += \${#COMP_LINE} ))
                        $compl_func
                    }" >> "$tmp_file"
                    new_completion="${new_completion/ -F $compl_func / -F $compl_wrapper }"
            fi
        fi

        # replace completion trigger by alias
        new_completion="${new_completion% *} $alias_name"
        echo "$new_completion" >> "$tmp_file"
    done < <(alias -p | sed -Ene "s/$alias_regex/\1 '\2' '\3'/p")
    source "$tmp_file" && rm -f "$tmp_file"
}; alias_completion

Basit (yalnızca komut, argüman yok) takma adları için orijinal tamamlama işlevini takma adaya atayacaktır; argümanlara sahip diğer isimler için, ekstra argümanları orijinal tamamlama fonksiyonuna ekleyen bir sarmalayıcı fonksiyonu yaratır.

O fonksiyon saygı takma komut için tırnak hem de bağımsız değişkenleri, evrimleştiği (ama eski tamamlama komutuyla uydurulması gereken ve iç içe olamaz), ve güvenilir için takma adlar filtre gerektiğini gelmiştir komut aksine komuta listeleri ve Borular (bunlara atlandı, çünkü tam kabuk komut satırı ayrıştırma mantığını yeniden oluşturmadan içlerinde ne yapılması gerektiğini bulmak mümkün değil).

kullanım

Kodu bir kabuk komut dosyası dosyası olarak kaydedin ve kaynak olarak kaydedin ya da işlevi toptan içine .bashrc(veya ilgili nokta dosyanızla ) kopyalayın . Önemli olan, bash tamamlandıktan ve diğer ad tanımları ayarlandıktan sonra işlevi çağırmaktır (yukarıdaki kod, tanımı tanımlandıktan hemen sonra “kaynak ve unut” ruhu ile çağırır, ancak çağrıyı aşağı akışta herhangi bir yere taşıyabilirsiniz. sana daha çok yakışıyor). İşleviniz çıktıktan sonra ortamınızda istemiyorsanız, unset -f alias_completionçağırdıktan sonra ekleyebilirsiniz .

notlar

bash4.1 veya daha üstü kullanıyorsanız ve dinamik olarak yüklenmiş tamamlamaları kullanıyorsanız, komut dosyası diğer tüm komutlarınız için tamamlamaları yüklemeye çalışacak, böylece takma adlarınız için sarmalayıcı işlevleri oluşturabilecektir.


1
Nasıl hakkında gitmek yüklemeden o senaryoyu?
Der Hochstapler

1
@OliverSalzburg: Kabuk profil dosyalarınızdan birinde, kesin olarak bash işleminden sonra - işlem yapmanız gerekecek - bu muhtemelen mümkün olacak ~/.bashrc. Ya bir kabuk komut dosyası dosyası olarak saklayın ve kaynak ( . /path/to/alias_completion.sh) yapın ya da toptan kodu kopyalayıp yapıştırın.
kopischke

1
@OliverSalzburg: kullanım talimatları eklendi (hemen OP olmadığınızı farketmediniz).
kopischke

1
@kopischke Bu soruya bakın - görünüşe göre altındaki dosyalar için /usr/share/bash-completion/completions/yalnızca kullanıcı gerçekten ilk defa vurduğunda yüklenir [TAB]. Bu nedenle, işlev yüklense bile, ~/.bashrciçerdiği komutların takma adları için tamamlamalar oluşturmaz. Olduktan sonra complete -piçin çalıştığını apt-getve apt-cacheben terminale fonksiyonunu-yapıştırılan kopya ve düzgün çalışıyor.
jamadagni

1
@kopischke Bu nedenle, dinamik olarak yüklenen tüm tamamlama dosyalarının kaynaklanmasını nasıl zorlatacağımdan emin değilim, hatta tavsiye edilebilir olsa bile. Şimdilik ben oluşturulan tamamlama dosyasını kopyaladığınız /tmpiçin ~/.bash_completionelle onun ilgili başlayan eklenmiştir source /usr/share/bash-completion/completions/girdileri (için ayrı ayrı apt-getve apt-cache- apt-{cache,get}does not iş).
jamadagni

4

Tüm tamamlama komut dosyalarımın takma adlarımla çalışmasını genel olarak / programatik olarak elde etmenin bir yolu var mı?

Evet, işte sorununuzu tam olarak çözen tam diğer proje. Kullanmadan genel ve programatik diğer ad tamamlama sağlar eval.


2

Bu, bunun için arayanlar için manuel yoldur.

İlk önce orijinal tamamlama komutuna bakın. Örnek:

$ complete | grep git

complete -o bashdefault -o default -o nospace -F __git_wrap__git_main git

Şimdi bunları başlangıç ​​kodunuza ekleyin (örn. ~ / .Bashrc):

# load dynamically loaded completion functions (may not be required)
_completion_loader git

# copy the original statement, but replace the last command (git) with your alias (g)
complete -o bashdefault -o default -o nospace -F __git_wrap__git_main g

kaynak: https://superuser.com/a/1004334

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.