Wie bekomme ich die Bash-Vervollständigung, um mit Aliasnamen zu arbeiten?

195

Ein typisches Beispiel:

Ich bin ein Mac mit bash v3.2.17 und verwende git, das über macports mit der Variante bash_completion installiert wurde.

Wenn ich tippe git checkout m<tab>. Zum Beispiel bekomme ich es fertig master.

Ich habe jedoch einen Alias ​​für git checkout, gco. Wenn ich tippe gco m<tab>, wird der Filialname nicht automatisch vervollständigt.

Idealerweise möchte ich, dass die automatische Vervollständigung auf magische Weise für alle meine Aliase funktioniert. Ist es möglich? Andernfalls möchte ich es manuell für jeden Alias ​​anpassen. Also, wie gehe ich vor?

kch
quelle
3
komplett -o Standard -o nospace -F funktioniert heutzutage nicht
achtzehn Jahre
5
Fragen mit mehr Upvotes als die Top-Antwort implizieren oft großartige Feature-Anfragen
Ciro Santilli 法轮功 冠状 病 六四 事件 法轮功
2
Eine andere Antwort von Superuser, als mich jemand darauf hinwies, dass meine Frage dort ein Betrüger war. superuser.com/questions/436314/...
dstarh

Antworten:

183

Wie in den obigen Kommentaren angegeben,

complete -o default -o nospace -F _git_checkout gco

wird nicht mehr funktionieren. In __git_completegit-vervollständigung.bash gibt es jedoch eine Funktion, mit der die Vervollständigung für Aliase wie die folgende eingerichtet werden kann:

__git_complete gco _git_checkout
chris_sutter
quelle
6
Dies ist die einzig richtige Antwort, die ich unter vielen falschen gesehen habe.
Achtzehn Jahre
45
Wenn Sie den globalen Alias ​​"g" für git verwenden, können Sie auch hinzufügen __git_complete g __git_main, damit die Code-Vervollständigung für alle git-Befehle funktioniert.
Ondrej Machulda
5
^^ Für diejenigen, die neu bei git / shell / bash sind. Der obige Kommentar bezieht sich auf einen globalen Shell-Alias, nicht auf einen nativen Git-Alias.
Elijah Lynn
14
Wo soll ich das hinstellen?
Benregn
15
Endlich herausgefunden, wie man das richtig macht! Schritt 1) ​​Kopieren git-completion.bashvon <your git install folder>/etc/bash-completion.d/nach ~/.git-completion.bash Schritt 2) Hinzufügen source ~/.git-completion.bashzu Ihrem .bash_profile Schritt 3) Hinzufügen __git_complete gco _git_checkoutnach der obigen Zeile in Ihrem .bash_profile. Schritt 4) Starten Sie die Shell neu und genießen Sie die automatische Vervollständigung Ihres Alias! :)
kpsfoo
54

Ich bin auch auf dieses Problem gestoßen und habe mir dieses Code-Snippet ausgedacht. Dadurch erhalten Sie automatisch eine Vervollständigung für alle Aliase. Führen Sie es aus, nachdem Sie alle (oder einen beliebigen) Alias ​​deklariert haben.

# 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
Hesky Fisher
quelle
6
Die Leitung let COMP_CWORD+=$num_alias_argumentsfunktionierte unter Mac OS X aus irgendeinem Grund nicht. Ersetzen Sie es durch ((COMP_CWORD+=$num_alias_arguments))behoben
Mario F
5
Wow, das ist großartig - danke! wrap_aliasDrosseln in doppelten Anführungszeichen in der Alias-Definition, und ich denke, dass es für Aliase mit mehreren Befehlen ( alias 'foo=bar; baz') nicht viel Sinn macht , also setze ich ein Extra | grep -v '[";|&]'nach dem alias -p. Außerdem wird es für Hunderte von Alias-Definitionen etwas langsam, aber ich bin froh zu bestätigen, dass die Verwendung echoanstelle von evalund das Weiterleiten der Ausgabe in eine Cache-Datei (die dann evalauf einmal bearbeitet werden kann) gut funktioniert und superschnell ist .
Jo Liss
2
Ein weiterer Hinweis: wrap_aliasErfordert die Einrichtung der Vervollständigungen, sodass ich mich source /etc/bash_completionvor den wrap_aliasCode stellen musste.
Jo Liss
2
Dies funktionierte für mich unter OS X 10.7.2, nachdem die Zeile let COMP_CWORD+=$num_alias_argumentsauf geändert wurde let \"COMP_CWORD+=$num_alias_arguments\".
irh
7
Die aktualisierte Version dieses Skripts finden Sie unter superuser.com/a/437508/102281 (ich habe beispielsweise die Unterstützung für COMP_LINE und COMP_POINT hinzugefügt, die für einige Git-Vervollständigungen erforderlich sind).
John Mellor
18

Darin git-completion.bashsteht eine Zeile:

complete -o default -o nospace -F _git git

Wenn Sie sich diese Zeile (und die Funktion _git) ansehen, können Sie diese Zeile zu Ihrer hinzufügen .bash_profile:

complete -o default -o nospace -F _git_checkout gco
Chris Lloyd
quelle
4
Einige der Git * Bash-Funktionen funktionieren mit dieser Methode nicht mehr
cmcginty
Ja, das hat früher großartig funktioniert, bis sich in git_completion.bash etwas geändert hat ... Jetzt funktioniert es mit dem vollständigen Befehl, aber nicht mit dem Alias.
Michael Smith
Am Ende dieser Seite finden Sie Antworten, die in modernem Git funktionieren.
Achtzehn Jahre
Sollten wir die akzeptierte Antwort nicht so ändern, dass sie die "richtige" ist, oder zumindest die akzeptierte Antwort aktualisieren, um die Änderung widerzuspiegeln?
Tony K.
Dies funktioniert gut - hat dies zu meinem .bash_profile hinzugefügt und funktioniert bisher einwandfrei mit und ohne Aliase: github.com/larrybotha/dotfiles/blob/master/…
Larry
15

Ich habe g = 'git' aliasiert und in Kombination mit meinen git-Aliasen Dinge wie

$ g co <branchname>

Die einfachere Lösung für meinen speziellen Anwendungsfall bestand darin, der Git-Vervollständigung eine einzelne Zeile hinzuzufügen.

Direkt unter dieser Zeile:

__git_complete git _git

Ich habe diese Zeile hinzugefügt, um meinen einzelnen 'g'-Alias ​​zu behandeln:

__git_complete g _git
wundervoll
quelle
2
(Ich verwende Cygwin.) Ich konnte die Datei git-completionoder diese Zeile nicht finden /etc/bash_completion.d/git, aber ich habe sie complete -o default -o nospace -F _git gnach meinem Alias hinzugefügt .bash_aliasesund es hat funktioniert!
idbrii
Beachten Sie, dass Sie Ihre Änderungen verlieren , wenn Sie eine Datei in /etc/bash-completion.d/oder neu in bearbeiten /usr/share/bash-completion/, wenn diese Datei mit Ihrem Paketmanager aktualisiert wird.
Kub1x
14

Idealerweise möchte ich, dass die automatische Vervollständigung auf magische Weise für alle meine Aliase funktioniert. Ist es möglich?

Ja, dies ist mit dem Complete-Alias- Projekt (unter Linux) möglich. Die Unterstützung für Mac ist experimentell, aber Benutzer haben über Erfolge berichtet.

Cyker
quelle
4
Vielen Dank, dies ist so viel besser, als herauszufinden, wie jedes Dienstprogramm auf der Welt die Bash-Fertigstellung implementiert.
Artm
2
In der Tat habe ich einige Zeit beim Konfigurieren von Vervollständigungen für Aliase gespart.
Samir Alajmovic
2
Funktioniert wie ein Zauber unter Linux (nicht auf Mac getestet). Danke fürs Schreiben!
Bitmaske
1
Das ist einfach großartig! Es funktioniert einfach, keine Aufregung, viel besser! Vielen Dank!
Emi
5

Sie können auch versuchen, Git-Aliase zu verwenden. In meiner ~/.gitconfigDatei befindet sich beispielsweise ein Abschnitt, der folgendermaßen aussieht:

[alias]
        co = checkout

Sie könnten also tippen git co m<TAB>, und das sollte erweitert werden git co master, was der git checkoutBefehl ist.

Mipadi
quelle
5

Diese Forenseite zeigt eine Lösung.

Fügen Sie diese Zeilen in Ihr .bashrcoder ein .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

Diese Lösung ähnelt dem Skript von Balshetzer , aber nur diese funktioniert tatsächlich für mich. (Balshetzers Skript hatte Probleme mit einigen meiner Aliase.)

hcs42
quelle
; Das funktioniert fast - ich bekomme ein paar Fehler, aber die Fertigstellung geht durch. Kann ich sonst noch etwas tun? -bash: eval: line 28: unexpected EOF while looking for matching ''' -bash: eval: line 29: syntax error: unexpected end of file
Pforhan
@pforhan Ich kann oben zitierende Probleme sehen ... die "Anführungszeichen in der functionZeichenfolge sollten als zitiert werden \". Dies frisst wahrscheinlich eines Ihrer 'Zitate irgendwo auf der Linie.
Tom Hale
5

Eine weitere Option ist die Verwendung einer ~/.bash_completionDatei. So erstellen Sie den gcoAlias ​​für das Einfügen git checkout:

_xfunc git __git_complete gco _git_checkout

Dann müssen ~/.bashrcSie nur den Alias ​​selbst eingeben:

alias gco='git checkout'

Zwei Linien. Das ist es.

Erläuterung:

Das ~/bash_completionwird am Ende des Hauptskripts bash_completion bezogen. In Gentoo fand ich das Hauptskript in /usr/share/bash-completion/bash_completion.

Das _xfunc gitBit kümmert sich darum, die git-completionDatei für Sie zu beschaffen , sodass Sie nichts anderes eingeben müssen ~/.bashrc.

Die akzeptierte Antwort erfordert, dass Sie sie kopieren .git-completion.shund aus Ihrer ~/.bashrcDatei beziehen, die ich lahm finde.


PS: Ich versuche immer noch herauszufinden, wie ich nicht das gesamte git-completionSkript in meine Bash-Umgebung einbinden kann. Bitte kommentieren oder bearbeiten Sie, wenn Sie einen Weg finden.

kub1x
quelle
Warum ist _xfunc giterforderlich?
Tom Hale
@ TomHale Ich habe versucht, die Antwort zu verbessern. Anstatt es zu tun, source ~/.git-completion.shlasse _xfuncich es für mich tun. Es fühlt sich einfach schöner und sauberer an, es nur in zu tun ~/.bash_completion. Ohne das _xfunc(oder das Sourcing) existiert die __git_completeFunktion nicht.
Kub1x
1
Keine Notwendigkeit für die ~/.bash_completionDatei - die _xfuncZeile funktioniert für mich in .bashrc.
Tom Hale
2

Sie müssen nur den completeBefehl finden und stattdessen die Zeile mit dem Aliasnamen duplizieren.

Ich habe alias d-m="docker-machine". In Worten d-msoll der Alias ​​für sein docker-machine.

Auf dem Mac (über Brew) befinden sich die Abschlussdateien in cd `brew --prefix`/etc/bash_completion.d/.
Für meinen Fall habe ich die aufgerufene Datei bearbeitet docker-machine.
Ganz unten war:

complete -F _docker_machine docker-machine

Also habe ich einfach eine weitere Zeile mit meinem Alias ​​hinzugefügt:

complete -F _docker_machine docker-machine
complete -F _docker_machine d-m
Glückydonald
quelle
Dies ist die beste Lösung für einfache (eins zu eins) Aliase, wie dockerz d. Obwohl für das Beispiel in der Frage das git checkoutAliasing gcokomplexer ist.
wisbucky
1

Suchen Sie zunächst den ursprünglichen Abschlussbefehl. Beispiel:

$ complete | grep git

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

Fügen Sie diese nun Ihrem Startskript hinzu (z. B. ~ / .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

Die _completion_loaderLeitung ist möglicherweise nicht erforderlich. In einigen Situationen wird die Abschlussfunktion jedoch erst dynamisch geladen, nachdem Sie den Befehl eingegeben und TABdas erste Mal gedrückt haben. Wenn Sie also den ursprünglichen Befehl nicht verwendet haben und den Alias ​​+ ausprobieren TAB, wird möglicherweise eine Fehlermeldung wie "bash: finish: function '_docker' not found" angezeigt.

wisbucky
quelle
1

Es gibt viele Antworten auf diese Frage und wie ich wette ich viele verwirrte Leser. Für meinen Fall hatte ich auch die Anforderung, dass meine Punktedateien auf mehreren Plattformen mit verschiedenen Versionen von Git funktionieren. Ich habe es auch nicht alias g=gitaber stattdessen gals Funktion definiert.

Um dies zu erreichen, musste ich hier verschiedene Antworten zu einer Lösung zusammenfassen. Obwohl dies die Antworten bereits wiederholt, dachte ich, dass jemand in meinem Boot diese Zusammenstellung nützlich finden könnte, wie ich es getan hätte, als ich zum ersten Mal zu dieser Frage kam.

Dies setzt ältere und neuere Git-Vervollständigungen, Ubuntu-Standardeinstellungen und brew install gitMacOS voraus . Im späteren Fall wurden die installierten Fertigstellungen des Gebräus nicht durch Bash verarbeitet (was ich später diagnostizieren werde).

# 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
Sukima
quelle
0

Wenn Sie verwenden alias g='git', füge ich diese Codezeile hinzu.bash_aliases

complete -o default -o nospace -F _git g
Druta Ruslan
quelle