Làm thế nào để tôi hoàn thành bash để làm việc với bí danh?


195

Trường hợp tại điểm:

Tôi là một máy Mac có bash v3.2.17, tôi đang sử dụng git được cài đặt qua macports với biến thể bash_completion.

Khi tôi gõ git checkout m<tab>. Ví dụ, tôi nhận được nó hoàn thành để master.

Tuy nhiên, tôi đã có một bí danh git checkout, gco. Khi tôi gõ gco m<tab>, tôi không nhận được tên chi nhánh tự động hoàn thành.

Lý tưởng nhất là tôi muốn tự động hoàn thành để làm việc một cách kỳ diệu cho tất cả các bí danh của mình. Có thể không? Không, tôi muốn tùy chỉnh thủ công cho từng bí danh. Vì vậy, làm thế nào để tôi đi về một trong hai?


3
hoàn thành -o mặc định -o nospace -F hiện không hoạt động
tám giờ

5
Các câu hỏi có nhiều nội dung hơn câu trả lời hàng đầu thường ngụ ý các yêu cầu tính năng
Ciro Santilli 郝海东 冠状 六四

2
Một câu trả lời khác từ superuser khi ai đó chỉ ra cho tôi rằng câu hỏi của tôi có một bản sao của câu hỏi này. superuser.com/questions/436314/ từ
dstarh

Câu trả lời:


183

Như đã nêu trong các ý kiến ​​trên,

complete -o default -o nospace -F _git_checkout gco

sẽ không còn làm việc Tuy nhiên, có một __git_completehàm trong git-xong.bash có thể được sử dụng để thiết lập hoàn thành cho các bí danh như vậy:

__git_complete gco _git_checkout

6
Đây là câu trả lời đúng duy nhất tôi thấy trong số nhiều câu trả lời sai.
tám

45
Nếu bạn sử dụng bí danh toàn cầu "g" cho git, bạn cũng có thể thêm __git_complete g __git_mainđể hoàn thành mã làm việc trên tất cả các lệnh git.
Ondrej Machulda

5
^^ Đối với những người mới sử dụng git / shell / bash. Nhận xét trên đề cập đến một bí danh vỏ toàn cầu, không phải là bí danh git bản địa.
Elijah Lynn

14
Tôi nên đặt cái này ở đâu?
benregn

15
Cuối cùng tìm ra cách để làm điều này đúng! Bước 1) Sao chép git-completion.bashtừ <your git install folder>/etc/bash-completion.d/để ~/.git-completion.bash bước 2) thêm source ~/.git-completion.bashđể bạn .bash_profile bước 3) Thêm __git_complete gco _git_checkoutbất cứ nơi nào sau khi dòng trên trong .bash_profile của bạn. Bước 4) Khởi động lại shell và tận hưởng hoàn thành tự động bí danh của bạn! :)
kpsfoo

54

Tôi cũng gặp vấn đề này và đưa ra đoạn mã này. Điều này sẽ tự động cung cấp cho bạn hoàn thành cho tất cả các bí danh. Chạy nó sau khi khai báo tất cả (hoặc bất kỳ) bí danh.

# wrap_alias takes three arguments:
# $1: The name of the alias
# $2: The command used in the alias
# $3: The arguments in the alias all in one string
# Generate a wrapper completion function (completer) for an alias
# based on the command and the given arguments, if there is a
# completer for the command, and set the wrapper as the completer for
# the alias.
function wrap_alias() {
  [[ "$#" == 3 ]] || return 1

  local alias_name="$1"
  local aliased_command="$2"
  local alias_arguments="$3"
  local num_alias_arguments=$(echo "$alias_arguments" | wc -w)

  # The completion currently being used for the aliased command.
  local completion=$(complete -p $aliased_command 2> /dev/null)

  # Only a completer based on a function can be wrapped so look for -F
  # in the current completion. This check will also catch commands
  # with no completer for which $completion will be empty.
  echo $completion | grep -q -- -F || return 0

  local namespace=alias_completion::

  # Extract the name of the completion function from a string that
  # looks like: something -F function_name something
  # First strip the beginning of the string up to the function name by
  # removing "* -F " from the front.
  local completion_function=${completion##* -F }
  # Then strip " *" from the end, leaving only the function name.
  completion_function=${completion_function%% *}

  # Try to prevent an infinite loop by not wrapping a function
  # generated by this function. This can happen when the user runs
  # this twice for an alias like ls='ls --color=auto' or alias l='ls'
  # and alias ls='l foo'
  [[ "${completion_function#$namespace}" != $completion_function ]] && return 0

  local wrapper_name="${namespace}${alias_name}"

  eval "
function ${wrapper_name}() {
  let COMP_CWORD+=$num_alias_arguments
  args=( \"${alias_arguments}\" )
  COMP_WORDS=( $aliased_command \${args[@]} \${COMP_WORDS[@]:1} )
  $completion_function
  }
"

  # To create the new completion we use the old one with two
  # replacements:
  # 1) Replace the function with the wrapper.
  local new_completion=${completion/-F * /-F $wrapper_name }
  # 2) Replace the command being completed with the alias.
  new_completion="${new_completion% *} $alias_name"

  eval "$new_completion"
}

# For each defined alias, extract the necessary elements and use them
# to call wrap_alias.
eval "$(alias -p | sed -e 's/alias \([^=][^=]*\)='\''\([^ ][^ ]*\) *\(.*\)'\''/wrap_alias \1 \2 '\''\3'\'' /')"

unset wrap_alias

6
let COMP_CWORD+=$num_alias_argumentsVì lý do nào đó, dòng này không hoạt động trên Mac OS X. Thay thế nó bằng cách ((COMP_CWORD+=$num_alias_arguments))sửa nó mặc dù
Mario F

5
Wow, thật tuyệt vời - cảm ơn! wrap_aliascuộn cảm với các trích dẫn kép trong định nghĩa bí danh và tôi đoán nó không có ý nghĩa nhiều đối với các bí danh đa lệnh ( alias 'foo=bar; baz'), vì vậy tôi sẽ đặt thêm | grep -v '[";|&]'sau alias -p. Ngoài ra, nó hơi chậm đối với hàng trăm định nghĩa bí danh, nhưng tôi vui mừng xác nhận rằng sử dụng echothay vì evalvà dẫn đầu ra vào một tệp bộ đệm (sau đó có thể được thực hiện evaltrong một lần) hoạt động tốt và cực nhanh .
Jo Liss

2
Một gợi ý khác: wrap_aliasyêu cầu hoàn thành được thiết lập, vì vậy tôi phải di chuyển source /etc/bash_completiontrước wrap_aliasmã.
Jo Liss

2
Điều này làm việc cho tôi trên OS X 10.7.2 sau khi thay đổi dòng let COMP_CWORD+=$num_alias_argumentsthành let \"COMP_CWORD+=$num_alias_arguments\".
irh

7
Xem phiên bản cập nhật của tập lệnh này tại superuser.com/a/437508/102281 (ví dụ: tôi đã thêm hỗ trợ cho COMP_LINE và COMP_POINT cần thiết cho một số hoàn thành git).
John Mellor

18

Trong git-completion.bashđó có một dòng:

complete -o default -o nospace -F _git git

Nhìn vào dòng đó (và hàm _git), bạn có thể thêm dòng này vào .bash_profile:

complete -o default -o nospace -F _git_checkout gco

4
một số hàm git * bash không còn hoạt động bằng phương thức này
cmcginty

Có, điều này được sử dụng để làm việc tuyệt vời cho đến khi một cái gì đó thay đổi trong git_completion.bash ... Bây giờ nó hoạt động với lệnh đầy đủ nhưng không phải với bí danh.
Michael Smith

Xem phần cuối của trang này để biết câu trả lời hoạt động trong git hiện đại.
tám

Chúng ta không nên thay đổi câu trả lời được chấp nhận thành "câu trả lời đúng" hay ít nhất là cập nhật câu trả lời được chấp nhận để phản ánh sự thay đổi?
Tony K.

này hoạt động tốt - thêm này để .bash_profile của tôi, và hoạt động tốt có và không có bí danh cho đến nay: github.com/larrybotha/dotfiles/blob/master/...
Larry

15

Tôi có bí danh g = 'git', và kết hợp với bí danh git của tôi, tôi gõ những thứ như

$ g co <branchname>

Cách khắc phục đơn giản hơn cho trường hợp sử dụng cụ thể của tôi là thêm một dòng để hoàn thành git.

Ngay bên dưới dòng này:

__git_complete git _git

Tôi đã thêm dòng này để xử lý bí danh 'g' duy nhất của mình:

__git_complete g _git

2
(Tôi đang sử dụng Cygwin.) Tôi không thể tìm thấy tệp git-completionhoặc dòng đó /etc/bash_completion.d/git, nhưng tôi đã thêm complete -o default -o nospace -F _git gsau bí danh của mình .bash_aliasesvà nó đã hoạt động!
idbrii

Xin lưu ý rằng nếu bạn chỉnh sửa một tệp trong /etc/bash-completion.d/hoặc mới /usr/share/bash-completion/, bạn sẽ mất các thay đổi của mình bất cứ khi nào tệp đó được cập nhật bằng trình quản lý gói của bạn.
kub1x

14

Lý tưởng nhất là tôi muốn tự động hoàn thành để làm việc một cách kỳ diệu cho tất cả các bí danh của mình. Có thể không?

Có, có thể với dự án bí danh hoàn chỉnh (trên Linux). Hỗ trợ cho Mac là thử nghiệm nhưng người dùng đã báo cáo thành công.


4
cảm ơn rất nhiều, điều này tốt hơn nhiều so với việc tìm ra cách mọi tiện ích trên thế giới thực hiện hoàn thành bash.
artm

2
Thật vậy, tiết kiệm cho tôi một số thời gian cấu hình hoàn thành cho bí danh.
Samir Alajmovic

2
Hoạt động như một bùa mê trên Linux (không được thử nghiệm trên Mac). Cảm ơn đã viết nó!
bitmask

1
Điều này thật tuyệt vời! Nó chỉ hoạt động, không ồn ào xung quanh, tốt hơn nhiều! Cảm ơn!
emi

5

Bạn cũng có thể thử sử dụng bí danh Git. Ví dụ: trong ~/.gitconfigtệp của tôi , tôi có một phần trông như thế này:

[alias]
        co = checkout

Vì vậy, bạn có thể gõ git co m<TAB>, và rằng nên mở rộng ra git co master, đó là git checkoutlệnh.


5

Trang diễn đàn này cho thấy một giải pháp.

Đặt những dòng này vào .bashrchoặc .bash_profile:

# Author.: Ole J
# Date...: 23.03.2008
# License: Whatever

# Wraps a completion function
# make-completion-wrapper <actual completion function> <name of new func.>
#                         <command name> <list supplied arguments>
# eg.
#   alias agi='apt-get install'
#   make-completion-wrapper _apt_get _apt_get_install apt-get install
# defines a function called _apt_get_install (that's $2) that will complete
# the 'agi' alias. (complete -F _apt_get_install agi)
#
function make-completion-wrapper () {
    local function_name="$2"
    local arg_count=$(($#-3))
    local comp_function_name="$1"
    shift 2
    local function="
function $function_name {
    ((COMP_CWORD+=$arg_count))
    COMP_WORDS=( "$@" \${COMP_WORDS[@]:1} )
    "$comp_function_name"
    return 0
}"
    eval "$function"
}

# and now the commands that are specific to this SO question

alias gco='git checkout'

# we create a _git_checkout_mine function that will do the completion for "gco"
# using the completion function "_git"
make-completion-wrapper _git _git_checkout_mine git checkout

# we tell bash to actually use _git_checkout_mine to complete "gco"
complete -o bashdefault -o default -o nospace -F _git_checkout_mine gco

Giải pháp này tương tự như kịch bản của balshetzer , nhưng chỉ có giải pháp này thực sự hiệu quả với tôi. (kịch bản của balshetzer có vấn đề với một số bí danh của tôi.)


; Điều này gần như hoạt động - Tôi nhận được một vài lỗi, nhưng việc hoàn thành đã đi qua. Tôi có thể làm gì khác không? -bash: eval: line 28: unexpected EOF while looking for matching ''' -bash: eval: line 29: syntax error: unexpected end of file
pforhan

@pforhan Tôi có thể xem trích dẫn các vấn đề ở trên ... các "trích dẫn bên trong functionchuỗi nên được trích dẫn là \". Điều này có thể ăn một trong những 'trích dẫn của bạn ở đâu đó dọc theo dòng.
Tom Hale

5

Thêm một lựa chọn là sử dụng ~/.bash_completiontập tin. Để tạo gcobí danh cho git checkoutchỉ cần đặt cái này vào đó:

_xfunc git __git_complete gco _git_checkout

Sau đó, trong ~/.bashrcbạn phải đặt chính bí danh:

alias gco='git checkout'

Hai dòng. Đó là nó.

Giải trình:

Các ~/bash_completionnguồn được lấy ở cuối tập lệnh bash_completion chính. Trong gentoo tôi tìm thấy kịch bản chính trong /usr/share/bash-completion/bash_completion.

Các _xfunc gitchút sẽ chăm sóc của nguồn các git-completiontập tin cho bạn để bạn không cần phải đặt bất cứ điều gì khác trong ~/.bashrc.

Câu trả lời được chấp nhận yêu cầu bạn sao chép .git-completion.shvà lấy nguồn từ ~/.bashrctệp của bạn mà tôi thấy khập khiễng.


Tái bút: Tôi vẫn đang cố gắng tìm ra cách không đưa toàn bộ git-completiontập lệnh vào môi trường bash của mình. Hãy bình luận hoặc chỉnh sửa nếu bạn tìm thấy một cách.


Tại sao _xfunc gitcần thiết?
Tom Hale

@TomHale Tôi đã cố gắng cải thiện câu trả lời. Thay vì làm source ~/.git-completion.shtôi để _xfuncnó làm cho tôi. Nó chỉ cảm thấy đẹp hơn và sạch hơn để làm điều đó chỉ trong ~/.bash_completion. Không có _xfunc(hoặc tìm nguồn cung ứng), __git_completechức năng sẽ không tồn tại.
kub1x

1
Không cần ~/.bash_completiontệp - _xfuncdòng hoạt động cho tôi trong .bashrc.
Tom Hale

2

Bạn chỉ cần tìm completelệnh và sao chép dòng có tên bí danh thay thế.

Tôi có alias d-m="docker-machine". Trong các từ, d-msẽ là bí danh cho docker-machine.

Vì vậy, trên Mac (thông qua brew), các tệp hoàn thành nằm trong cd `brew --prefix`/etc/bash_completion.d/.
Đối với trường hợp của tôi, tôi chỉnh sửa các tập tin được gọi là docker-machine.
Tất cả các cách ở phía dưới có:

complete -F _docker_machine docker-machine

Vì vậy, tôi chỉ cần thêm một dòng khác, với bí danh của mình:

complete -F _docker_machine docker-machine
complete -F _docker_machine d-m

Đây là giải pháp tốt nhất cho các bí danh (một đến một), giống như dockerbí danh d. Mặc dù đối với ví dụ trong câu hỏi, git checkoutbí danh gcolà phức tạp hơn.
wvducky

1

Đầ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):

# 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

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

Các _completion_loaderdòng có thể không được yêu cầu. Nhưng đối với một số tình huống, chức năng hoàn thành chỉ được tải động sau khi bạn nhập lệnh và nhấn TABlần đầu tiên. Vì vậy, nếu bạn chưa sử dụng lệnh ban đầu và thử bí danh + TAB, bạn có thể gặp lỗi như "bash: xong: function '_docker' không tìm thấy".


1

Có rất nhiều câu trả lời cho câu hỏi này và giống như bản thân tôi, tôi cá là rất nhiều độc giả bối rối. Đối với trường hợp của tôi, tôi cũng đã có yêu cầu để các dotfiles của tôi hoạt động trên nhiều nền tảng với các phiên bản Git khác nhau. Tôi cũng không alias g=gitnhưng thay vào đó đã gđịnh nghĩa là một chức năng.

Để thực hiện điều này, tôi đã phải đưa các câu trả lời khác nhau vào đây thành một giải pháp. Mặc dù điều này nhắc lại các câu trả lời nhưng tôi nghĩ ai đó trong thuyền của tôi có thể thấy phần tổng hợp này hữu ích như tôi có khi tôi lần đầu tiên đến câu hỏi này.

Điều này giả định hoàn thành Git cũ hơn và mới hơn, mặc định Ubuntu và brew install gittrên MacOS. Trong trường hợp sau, việc hoàn thành cài đặt bia không được xử lý bằng bash (điều mà tôi sẽ chẩn đoán sau).

# Alias g to git

g() {
  if [[ $# > 0 ]]; then
    git "$@"
  else
    git status -sb
  fi
}

# Preload git completion in Ubuntu which is normally lazy loaded but we need
# the __git_wrap__git_main function available for our completion.
if [[ -e /usr/share/bash-completion/completions/git ]]; then
  source /usr/share/bash-completion/completions/git
elif [[ -e /usr/local/etc/bash_completion.d/git-completion.bash ]]; then
  source /usr/local/etc/bash_completion.d/git-completion.bash
fi

if command_exists __git_complete; then
  __git_complete g _git
elif command_exists __git_wrap__git_main; then
  complete -o bashdefault -o default -o nospace -F __git_wrap__git_main g
fi

0

Nếu bạn sử dụng alias g='git', tôi thêm dòng mã này vào.bash_aliases

complete -o default -o nospace -F _git g
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.