Jak uzyskać ukończenie bash do pracy z aliasami?


195

Przykładem:

Jestem na Macu z bash v3.2.17, używam git zainstalowanego przez macports z wariantem bash_completion.

Po wpisaniu git checkout m<tab>. na przykład, ukończę to master.

Jednak mam alias git checkout, gco. Kiedy piszę gco m<tab>, nazwa oddziału nie jest automatycznie uzupełniana.

Idealnie byłoby, gdyby autouzupełnianie działało magicznie dla wszystkich moich aliasów. Czy to możliwe? W przeciwnym razie chciałbym ręcznie dostosować go dla każdego aliasu. Więc jak mam to zrobić?


3
zupełny -o domyślny -o nospace -F obecnie nie działa
— eighteyes

5
Pytania o większej liczbie głosów pozytywnych niż najlepsza odpowiedź często oznaczają wspaniałe prośby o nowe funkcje
— Ciro Santilli 20 冠状 病 六四 事件 法轮功

2
Kolejna odpowiedź superużytkownika, gdy ktoś wskazał mi, że moje pytanie było duplikatem tego. superuser.com/questions/436314/…
— dstarh

Odpowiedzi:


183

Jak stwierdzono w komentarzach powyżej,

complete -o default -o nospace -F _git_checkout gco

przestanie działać. Jednak __git_completew git-uzupełnianie.bash jest funkcja, której można użyć do skonfigurowania zakończenia dla takich aliasów:

__git_complete gco _git_checkout

6
To jedyna poprawna odpowiedź, jaką widziałem wśród wielu niewłaściwych.
— eighteyes

45
Jeśli używasz globalnego aliasu „g” dla git, możesz również dodać, __git_complete g __git_mainaby uzyskać uzupełnianie kodu działające na wszystkich poleceniach git.
— Ondrej Machulda

5
^^ Dla nowych użytkowników git / shell / bash. Powyższy komentarz odnosi się do globalnego aliasu powłoki, a nie natywnego aliasu git.
— Elijah Lynn

14
Gdzie mam to położyć?
— benregn

15
Wreszcie wymyśliłem, jak to zrobić poprawnie! Krok 1) Skopiuj git-completion.bashz <your git install folder>/etc/bash-completion.d/do ~/.git-completion.bash kroku 2) dodaj source ~/.git-completion.bashdo .bash_profile kroku 3) Dodaj __git_complete gco _git_checkoutdowolne miejsce po powyższej linii w pliku .bash_profile. Krok 4) Uruchom ponownie powłokę i ciesz się automatycznym uzupełnianiem aliasu! :)
— kpsfoo,

54

Natknąłem się również na ten problem i wymyśliłem ten fragment kodu. Spowoduje to automatyczne uzupełnienie wszystkich aliasów. Uruchom go po zadeklarowaniu wszystkich (lub dowolnych) aliasów.

# 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
linia let COMP_CWORD+=$num_alias_argumentsz jakiegoś powodu nie działała na Mac OS X. Zastąpienie go ((COMP_CWORD+=$num_alias_arguments))naprawiono
— Mario F

5
Wow, to niesamowite - dzięki! wrap_aliasdusi się w podwójnych cudzysłowach w definicji aliasu i myślę, że nie ma to większego sensu dla aliasów wielozadaniowych ( alias 'foo=bar; baz'), więc umieszczam dodatkowy | grep -v '[";|&]'po alias -p. Poza tym robi się trochę powolny w przypadku setek definicji aliasów, ale z przyjemnością potwierdzam, że użycie echozamiast evali przekazanie danych wyjściowych do pliku pamięci podręcznej (który można następnie eval„za jednym zamachem”) działa dobrze i jest super szybkie .
— Jo Liss,

2
Kolejna wskazówka: wrap_aliaswymaga skonfigurowania uzupełnień, więc musiałem przejść source /etc/bash_completionprzed wrap_aliaskodem.
— Jo Liss,

2
To działało dla mnie w OS X 10.7.2 po zmianie linii let COMP_CWORD+=$num_alias_argumentsna let \"COMP_CWORD+=$num_alias_arguments\".
— irh

7
Zobacz zaktualizowaną wersję tego skryptu na superuser.com/a/437508/102281 (na przykład dodałem obsługę COMP_LINE i COMP_POINT, które są wymagane do niektórych uzupełnień git).
— John Mellor,

18

W git-completion.bashistnieje linia:

complete -o default -o nospace -F _git git

Patrząc na tę linię (i funkcję _git) możesz dodać tę linię do .bash_profile:

complete -o default -o nospace -F _git_checkout gco

4
niektóre funkcje git * bash nie działają już przy użyciu tej metody
— cmcginty

Tak, to działało świetnie, dopóki coś się nie zmieniło w git_completion.bash ... Teraz działa z pełną komendą, ale nie z aliasem.
— Michael Smith

Na końcu tej strony znajdziesz odpowiedzi, które działają w nowoczesnym git.
— eighteyes

Czy nie powinniśmy zmienić przyjętej odpowiedzi na „poprawną”, a przynajmniej zaktualizować zaakceptowaną odpowiedź, aby odzwierciedlić zmianę?
— Tony K.

to działa dobrze - dodaje to do mojego bash_profile i działa dobrze i bez aliasów do tej pory: github.com/larrybotha/dotfiles/blob/master/...
— Larry

15

Alias ​​g = „git” i w połączeniu z aliasami git piszę takie rzeczy

$ g co <branchname>

Prostszym rozwiązaniem dla mojego konkretnego przypadku użycia było dodanie pojedynczej linii do git-complete.

Tuż poniżej tej linii:

__git_complete git _git

Dodałem tę linię, aby obsługiwać mój pojedynczy alias „g”:

__git_complete g _git

2
(Używam Cygwin.) Nie mogłem znaleźć pliku git-completionani tego wiersza /etc/bash_completion.d/git, ale dodałem complete -o default -o nospace -F _git gpo moim aliasie .bash_aliasesi zadziałało!
— idbrii

Uwaga: jeśli edytujesz plik w /etc/bash-completion.d/lub w nowym /usr/share/bash-completion/, utracisz zmiany za każdym razem, gdy plik zostanie zaktualizowany za pomocą menedżera pakietów.
— kub1x

14

Idealnie byłoby, gdyby autouzupełnianie działało magicznie dla wszystkich moich aliasów. Czy to możliwe?

Tak, jest to możliwe dzięki projektowi z pełnym aliasem (w systemie Linux). Obsługa komputerów Mac jest eksperymentalna, ale użytkownicy zgłosili sukces.


4
wielkie dzięki, jest to o wiele lepsze niż wymyślenie, jak każde narzędzie na świecie implementuje zakończenie bash.
— artm

2
Rzeczywiście, zaoszczędziłem trochę czasu na konfigurowanie uzupełnień dla aliasów.
— Samir Alajmovic

2
Działa jak urok w Linuksie (nie testowany na Macu). Dzięki za napisanie tego!
— maska ​​bitowa

1
To jest po prostu niesamowite! To po prostu działa, bez zamieszania, znacznie lepiej! Dzięki!
— emi

5

Możesz także spróbować użyć aliasów Git. Na przykład w moim ~/.gitconfigpliku mam sekcję, która wygląda następująco:

[alias]
        co = checkout

Więc możesz wpisać git co m<TAB>, a to powinno rozwinąć się do git co master, które jest git checkoutpoleceniem.


5

Ta strona forum pokazuje rozwiązanie.

Umieść te linie w swoim .bashrclub .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

To rozwiązanie jest podobne do skryptu balshetzera , ale tylko to faktycznie działa dla mnie. (skrypt balshetzera miał problemy z niektórymi moimi pseudonimami).


; To prawie działa - otrzymuję kilka błędów, ale proces dobiega końca. Coś jeszcze mogę zrobić? -bash: eval: line 28: unexpected EOF while looking for matching ''' -bash: eval: line 29: syntax error: unexpected end of file
— pforhan

@pforhan Widzę problemy z cytowaniem powyżej ... "cytaty wewnątrz functionciągu powinny być cytowane jako \". To prawdopodobnie zjada jeden z twoich 'cytatów gdzieś wzdłuż linii.
— Tom Hale

5

Jeszcze jedną opcją jest użycie ~/.bash_completionpliku. Aby utworzyć gcoalias, po git checkoutprostu wstaw to tutaj:

_xfunc git __git_complete gco _git_checkout

Następnie ~/.bashrcmusisz wstawić sam alias:

alias gco='git checkout'

Dwie linie. Otóż ​​to.

Wyjaśnienie:

~/bash_completionDostaje pozyskiwane na końcu głównego skryptu bash_completion. W Gentoo znalazłem główny skrypt /usr/share/bash-completion/bash_completion.

_xfunc gitNieco dba o zaopatrywaniu się git-completionplik dla Ciebie, dzięki czemu nie trzeba kłaść indziej ~/.bashrc.

Akceptowana odpowiedź wymaga skopiowania .git-completion.shi pobrania jej z ~/.bashrcpliku, który uważam za kiepski.


PS: Nadal próbuję wymyślić, jak nie pobierać całego git-completionskryptu do mojego środowiska bash. Skomentuj lub edytuj, jeśli znajdziesz sposób.


Dlaczego jest to _xfunc gitwymagane?
— Tom Hale,

@TomHale Próbowałem poprawić odpowiedź. Zamiast robić source ~/.git-completion.shNiech I _xfunczrobić to za mnie. To po prostu przyjemniejsze i czystsze, gdy robi się to wyłącznie w ~/.bash_completion. Bez _xfunc(lub pozyskiwania) __git_completefunkcja nie istnieje.
— kub1x

1
~/.bash_completionPlik nie jest potrzebny - _xfunclinia działa dla mnie w .bashrc.
— Tom Hale,

2

Musisz po prostu znaleźć completepolecenie i powielić wiersz o nazwie alias.

Mam alias d-m="docker-machine". Innymi słowy, d-mbędzie to pseudonim docker-machine.

Tak więc na Macu (przez napar) znajdują się pliki ukończenia cd `brew --prefix`/etc/bash_completion.d/.
W moim przypadku edytowałem plik o nazwie docker-machine.
Na dole było:

complete -F _docker_machine docker-machine

Właśnie dodałem kolejną linię z moim aliasem:

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

Jest to najlepsze rozwiązanie dla prostych aliasów (jeden do jednego), takich jak dockeralias do d. Chociaż dla przykładu w pytaniu, git checkoutalias do gcojest bardziej złożony.
— wisbucky

1

Najpierw wyszukaj oryginalne polecenie zakończenia. Przykład:

$ complete | grep git

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

Teraz dodaj je do skryptu uruchamiania (np. ~ / .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

_completion_loaderMoże nie być wymagana linia. Ale w niektórych sytuacjach funkcja uzupełniania jest ładowana dynamicznie dopiero po wpisaniu polecenia i TABpierwszym naciśnięciu . Jeśli więc nie użyłeś oryginalnej komendy i wypróbowałeś alias + TAB, możesz otrzymać błąd typu „bash: complete: nie znaleziono funkcji” _docker ”.


1

Istnieje wiele odpowiedzi na to pytanie i podobnie jak ja stawiam na wielu zdezorientowanych czytelników. W moim przypadku miałem również wymaganie, aby moje pliki dot działały na wielu platformach z różnymi wersjami Git. Ja też nie, alias g=gitale zamiast tego gzdefiniowałem jako funkcję.

Aby to osiągnąć, musiałem połączyć różne odpowiedzi tutaj w jedno rozwiązanie. Chociaż to powtórzy już odpowiedzi, myślałem, że ktoś w mojej łodzi może uznać tę kompilację za przydatną, tak jak zrobiłbym to, kiedy po raz pierwszy zadałem to pytanie.

Zakłada to starsze i nowsze zakończenie Git, domyślne ustawienia Ubuntu i brew install gitna MacOS. W późniejszym przypadku uzupełnienia instalacji naparu nie były przetwarzane przez bash (coś zdiagnozuję później).

# 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

Jeśli używasz alias g='git', dodaję ten wiersz kodu.bash_aliases

complete -o default -o nospace -F _git g
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.