Làm cách nào tôi có thể nhận bash để thực hiện hoàn thành tab cho bí danh của mình?


45

Tôi có một loạt các kịch bản hoàn thành bash được thiết lập (chủ yếu sử dụng bash-it và một số thiết lập thủ công).

Tôi cũng có một loạt các thiết lập bí danh cho các tác vụ phổ biến như gcocho git checkout. Ngay bây giờ tôi có thể gõ git checkout dTabdevelophoàn thành cho tôi nhưng khi tôi gõ gco dTabnó không hoàn thành.

Tôi cho rằng điều này là do tập lệnh hoàn thành đang hoàn thành gitvà nó không thể xem được gco.

Có cách nào để tạo ra tất cả các tập lệnh hoàn thành của tôi để làm việc với các bí danh của tôi không? Không thể hoàn thành khi sử dụng loại bí danh đánh bại mục đích của bí danh.


Bạn đang sử dụng hệ điều hành và bash nào? Tôi đang sử dụng Ubuntu 11.10 và bash 4.2.10 (1) (x86_64-pc-linux-gnu) và tôi có chức năng này được tích hợp trong vỏ cho nhiều bí danh của tôi. btw bash --versionđể có được điều này (không sử dụng -v, đầu ra khác nhau).
Michael Durrant

Xin lỗi đã bỏ lỡ một chút thông tin - OSX Lion, GNU bash, phiên bản 3.2.48 (1) -release (x86_64-apple-darwin11)
dstarh

1
@killermist: trừ khi tôi hoàn toàn nhầm lẫn, zsh cũng không hoàn thành các lệnh bí danh ra khỏi hộp. Tuy nhiên, việc triển khai một chức năng bổ sung các bí danh đã xác định để hoàn thành có vẻ dễ dàng hơn nhiều so với bash, vì hệ thống hoàn thành của zhs dường như mạnh hơn và đơn giản hơn so với bash.
kopischke

Trang web trùng lặp trùng lặp: stackoverflow.com/questions/342969/
Mạnh

1
@MichaelDurrant Bạn có chắc chắn rằng điều này thực sự được xây dựng cho bí danh? Tôi đang dùng Ubuntu 15.10 với Bash 4.3.42 (1) -release (x86_64-pc-linux-gnu) và không có điều đó. Tôi cũng đã thử nghiệm một vài bản phát hành trước đó. Vì vậy, ví dụ nếu bạn gõ vào ll --[TAB]nó sẽ in một danh sách các tùy chọn cho ls? Tôi khá hoài nghi về điều này, nhưng nếu bạn chắc chắn một điều như vậy tồn tại trong 11.10, tôi sẽ tò mò tìm hiểu về nó và xác định những gì đã bị xóa.
Sáu

Câu trả lời:


42

Đoạn mã sau, được điều chỉnh từ câu trả lời Stack Overflow này và chuỗi thảo luận về Diễn đàn Ubuntu này sẽ thêm các phần hoàn chỉnh cho tất cả các bí danh đã xác định của bạn:

# 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

Đối với các bí danh đơn giản (chỉ lệnh, không có đối số), nó sẽ gán hàm hoàn thành ban đầu cho bí danh; đối với các bí danh có đối số, nó tạo ra một hàm bao bọc để chèn các đối số phụ vào hàm hoàn thành ban đầu.

Không giống như các tập lệnh mà nó đã phát triển từ, hàm này tôn trọng cả trích dẫn cho lệnh bí danh và các đối số của nó (nhưng trước đây phải được khớp với lệnh hoàn thành và không thể lồng nhau), và nó đáng tin cậy nên lọc ra các bí danh cho danh sách lệnhcác đường ống (được bỏ qua, vì không thể tìm ra những gì cần hoàn thành trong chúng mà không tạo lại logic phân tích cú pháp dòng lệnh shell hoàn chỉnh).

Sử dụng

Lưu mã dưới dạng tệp tập lệnh shell và nguồn trong hoặc sao chép hàm bán buôn vào, .bashrc(hoặc tệp dấu chấm thích hợp của bạn ). Điều quan trọng là gọi hàm sau khi cả hai hoàn thành bash và các định nghĩa bí danh đã được thiết lập (đoạn mã trên gọi hàm ngay sau định nghĩa của nó, trong một nguồn trên mạng và quên tinh thần, nhưng bạn có thể di chuyển cuộc gọi xuống bất cứ nơi nào nếu điều đó phù hợp với bạn hơn). Nếu bạn không muốn chức năng trong môi trường của mình sau khi nó thoát, bạn có thể thêm unset -f alias_completionsau khi gọi nó.

Ghi chú

Nếu bạn đang sử dụng bash4.1 trở lên và sử dụng các hoàn thành được tải động, tập lệnh sẽ cố gắng tải các hoàn thành cho tất cả các lệnh bí danh của bạn để nó có thể xây dựng các hàm bao cho các bí danh của bạn.


1
Làm thế nào tôi có thể cài đặt tập lệnh đó?
Der Hochstapler

1
@OliverSalzburg: bạn sẽ phải xử lý nó trong một trong các tệp hồ sơ shell của bạn, chủ yếu là sau khi hoàn thành bash - điều đó có thể sẽ làm cho nó ~/.bashrc. Lưu trữ nó dưới dạng tệp script shell và nguồn nó ( . /path/to/alias_completion.sh), hoặc sao chép và dán mã bán buôn.
kopischke

1
@OliverSalzburg: đã thêm hướng dẫn sử dụng (không thông báo ngay rằng bạn không phải là OP).
kopischke

1
@kopischke Xem câu hỏi này - dường như đối với các tệp bên dưới /usr/share/bash-completion/completions/chúng chỉ được tải lần đầu tiên khi người dùng thực sự nhấn [TAB]. Vì vậy, ngay cả khi hàm được tải từ ~/.bashrcnó sẽ không tạo ra sự hoàn thành cho các bí danh cho các lệnh trong đó. Sau khi đảm bảo hoạt complete -pđộng apt-getapt-cachetôi sao chép chức năng của bạn vào thiết bị đầu cuối và nó hoạt động chính xác.
jamadagni

1
@kopischke Vì vậy, tôi không chắc chắn làm thế nào để bắt buộc tìm nguồn cung ứng của tất cả các tệp hoàn thành được tải động, hoặc ngay cả khi nó được khuyến khích. Hiện tại tôi đã sao chép tệp hoàn thành được tạo từ /tmpđến ~/.bash_completionvà thêm thủ công vào lúc đầu các source /usr/share/bash-completion/completions/mục có liên quan (riêng cho apt-getapt-cache- apt-{cache,get}không hoạt động).
jamadagni

4

Có cách nào để tạo ra tất cả các tập lệnh hoàn thành của tôi để làm việc với các bí danh của tôi không?

Vâng, đây là dự án bí danh hoàn chỉnh giải quyết vấn đề của bạn một cách chính xác. Nó cung cấp hoàn thành bí danh chung và lập trình mà không cần sử dụng eval.


2

Đây là cách thủ công, cho những người đang tìm kiếm điều này.

Đầu tiên, tìm kiếm lệnh hoàn thành ban đầu. Thí dụ:

$ complete | grep git

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

Bây giờ hãy thêm chúng vào tập lệnh khởi động của bạn (ví dụ ~ / .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

nguồn: https://superuser.com/a/1004334

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.