Как заставить автозавершение bash работать с псевдонимами?

Дело в точке:

Я использую Mac с bash v3.2.17, я использую git, установленный через macports, с вариантом bash_completion.

Когда я набираю git checkout m<tab>. например, я завершил его до master.

Однако у меня есть псевдонимы git checkout, gco. Когда я набираю gco m<tab>, имя ветки не заполняется автоматически.

В идеале я бы хотел, чтобы автозаполнение просто волшебным образом работало для всех моих псевдонимов. Является ли это возможным? В противном случае я бы хотел вручную настроить его для каждого псевдонима. Итак, как мне поступить?


person kch    schedule 05.12.2008    source источник
comment
Complete -o default -o nospace -F в настоящее время не работает   -  person eighteyes    schedule 22.03.2013
comment
Вопросы, набравшие больше голосов, чем первый ответ, часто подразумевают отличные запросы функций   -  person Ciro Santilli 新疆再教育营六四事件ۍ    schedule 20.01.2014
comment
Еще один ответ от суперпользователя, поскольку кто-то указал мне, что мой вопрос был обманом этого. superuser.com/questions/436314/   -  person dstarh    schedule 21.01.2014


Ответы (14)


Как указано в комментариях выше,

complete -o default -o nospace -F _git_checkout gco

больше не будет работать. Однако в git-completed.bash есть __git_complete функция, которую можно использовать для настройки автозавершения для таких псевдонимов:

__git_complete gco _git_checkout
person chris_sutter    schedule 21.02.2013
comment
Если вы используете глобальный псевдоним g для git, вы также можете добавить __git_complete g __git_main, чтобы завершить работу над всеми командами git. - person Ondrej Machulda; 15.04.2013
comment
^^ Для новичков в git / shell / bash. Приведенный выше комментарий относится к глобальному псевдониму оболочки, а не к собственному псевдониму git. - person Elijah Lynn; 30.07.2013
comment
Что, если git имеет псевдоним g, а checkout - co, поэтому я делаю g co <tab>, но не автозаполнение тоже. - person Jürgen Paul; 10.10.2013
comment
Куда мне это поставить? - person benregn; 14.11.2013
comment
Наконец разобрался, как это правильно сделать! Шаг 1) Скопируйте git-completion.bash из <your git install folder>/etc/bash-completion.d/ в ~/.git-completion.bash Шаг 2) добавьте source ~/.git-completion.bash в ваш .bash_profile Шаг 3) Добавьте __git_complete gco _git_checkout в любом месте после указанной выше строки в вашем .bash_profile. Шаг 4) Перезагрузите оболочку и наслаждайтесь автозаполнением псевдонима! :) - person kpsfoo; 06.04.2014
comment
@benregn Я поместил его прямо под source ~/.git_completion.sh в моем ~/.bash_profile - person drees; 20.06.2014
comment
-1 Этот ответ, похоже, предполагает, что вы прочитали и поняли какой-то старый неправильный ответ (но какой?) И, следовательно, знаете, в каком файле и где в этом файле принадлежит эта строка текста. Старайтесь только предполагать знание вещей, установленных в вопросе. - person Theodore Murdock; 19.03.2015
comment
Есть хороший Gist, который предоставляет всю информацию, необходимую для его настройки. - person stempler; 06.05.2015
comment
Чтобы проверить количество ведущих символов подчеркивания для команд, отличных от __git_main и _git_checkout (например, _git_merge и _git_pull), выполните поиск в скрипт .git-completion.bash. Все общие команды (те, которые я псевдоним) имеют только один начальный знак подчеркивания. - person Jan Van Bruggen; 17.09.2015
comment
Что делать, если псевдоним, для которого вы хотите завершить, не имеет ничего общего с git; что делать, если в вашей системе / сервере не установлен git? - person Alexej Magura; 13.12.2016
comment
Это не настоящий ответ, потому что на самом деле он не говорит вам, что делать, а просто предоставляет некоторую информацию. Очень неполно. - person still_dreaming_1; 10.10.2018
comment
Для людей, которые ищут сценарий завершения: find / -name "git-completion.bash". - person ShellFish; 25.03.2020

Я тоже столкнулся с этой проблемой и придумал этот фрагмент кода. Это автоматически даст вам завершение для всех псевдонимов. Запустите его после объявления всех (или любых) псевдонимов.

# 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
person Hesky Fisher    schedule 24.11.2009
comment
строка let COMP_CWORD+=$num_alias_arguments по какой-то причине не работала в Mac OS X. Замена на ((COMP_CWORD+=$num_alias_arguments)) исправила это, хотя - person Mario F; 05.01.2011
comment
Вау, это круто - спасибо! wrap_alias подавляется двойными кавычками в определении псевдонима, и я думаю, это не имеет особого смысла для псевдонимов с несколькими командами (alias 'foo=bar; baz'), поэтому я добавляю дополнительный | grep -v '[";|&]' после alias -p. Кроме того, он становится немного медленным для сотен определений псевдонимов, но я рад подтвердить, что использование echo вместо eval и передача вывода в файл кеша (который затем может быть eval за один раз) работает нормально и является сверх быстрый. - person Jo Liss; 13.01.2011
comment
Еще один совет: wrap_alias требует настройки завершения, поэтому мне пришлось переместить source /etc/bash_completion перед кодом wrap_alias. - person Jo Liss; 13.01.2011
comment
Я думаю, что должно быть \" около \${COMP_WORDS[@]:1}, чтобы эта работа работала с пробелами в аргументах. (Но я действительно не знаю, что делаю, поэтому мне неудобно редактировать ответ в данный момент.) - person Jo Liss; 05.03.2011
comment
Это сработало для меня в OS X 10.7.2 после изменения строки let COMP_CWORD+=$num_alias_arguments на let \"COMP_CWORD+=$num_alias_arguments\". - person irh; 31.10.2011
comment
Сделал следующее, чтобы обернуть только указанные псевдонимы: function wrap_aliases {для cmdname в $ @; сделать cmdname = $ (псевдоним $ cmdname | sed 's / sudo //'); eval $ (echo $ cmdname | sed -e 's / alias ([^ =] [^ =] *) =' \ '' ([^] [^] *) * (. *) '\' '/ wrap_alias \ 1 \ 2 '\' '\ 3' \ '' / '); Выполнено } - person Graham; 23.12.2011
comment
OSX 10.7.2 здесь не работала ни с советами @irh, ни с советами Марио Фернандеса. Есть идеи, что может быть не так или как я могу это отладить? - person agentofuser; 30.01.2012
comment
Мне пришлось исключить следующие псевдонимы: [[ "_longopt" = $completion_function ]] && return 0 - person Julien Carsique; 28.01.2013
comment
Как я могу заставить эту работу работать с sudo? Я добавил alias agi='sudo apt-get install', но agi + emac ‹TAB› ничего не делает. - person agentofuser; 04.04.2014
comment
@ obvio171 Вам понадобится функция завершения для sudo. - person Hesky Fisher; 05.04.2014
comment
@HeskyFisher, не могли бы вы рассказать поподробнее? Извините, я не слишком разбираюсь в bash. - person agentofuser; 07.04.2014
comment
@ obvio171 Я предлагаю задать это как вопрос о переполнении стека. - person Hesky Fisher; 08.04.2014
comment
@ obvio171: Из ответа Грэма: добавьте | sed 's/sudo //' перед sed -e 's/alias', и это должно автоматически вызвать функцию завершения для команды после sudo. - person jamadagni; 25.10.2014
comment
Если у кого-то возникают проблемы с некоторыми псевдонимами, которые не получают правильного завершения, см. Мой комментарий здесь - person jamadagni; 25.10.2014
comment
См. Обновленную версию этого скрипта на странице superuser.com/a/437508/102281 (например, я добавил поддержку COMP_LINE и COMP_POINT, которые требуются для некоторых доработок git). - person John Mellor; 04.11.2014
comment
Мне очень жаль, но непоточные комментарии - НЕ подходящее место для совместной работы над кодом. Как минимум, это должно быть сутью. Но поскольку gists не позволяет создавать ни проблемы, ни предлагать запросы на вытягивание, это действительно должно быть реальное репозиторий git. (даже ссылка, которой поделился Джон Меллор, - это полные комментарии кодеров) - person Bruno Bronosky; 17.02.2017
comment
Ура, классный скрипт, но он терпит неудачу, когда это нетривиальный псевдоним, содержащий токены типа (($UID));) ... все же, очень круто. Я использую grep -v, чтобы избавиться от нескольких оскорбительных псевдонимов, и добавил их в последовательность каналов сразу после alias -p ... - person 0xC0000022L; 20.08.2018

В git-completion.bash есть строка:

complete -o default -o nospace -F _git git

Глядя на эту строку (и функцию _git), вы можете добавить эту строку в свой .bash_profile:

complete -o default -o nospace -F _git_checkout gco
person Chris Lloyd    schedule 05.12.2008
comment
некоторые из функций git * bash больше не работают с этим методом - person cmcginty; 23.09.2011
comment
Да, раньше это отлично работало, пока что-то не изменилось в git_completion.bash ... Теперь он работает с полной командой, но не с псевдонимом. - person Michael Smith; 24.01.2012
comment
В конце этой страницы вы найдете ответы, которые работают в современном git. - person eighteyes; 22.03.2013
comment
это работает хорошо - добавил это в мой .bash_profile, и до сих пор отлично работает с псевдонимами и без них: github.com/larrybotha/dotfiles/blob/master/ - person Larry; 02.07.2013

В идеале я бы хотел, чтобы автозаполнение просто волшебным образом работало для всех моих псевдонимов. Является ли это возможным?

Да, это возможно с помощью проекта complete-alias (в Linux). Поддержка Mac является экспериментальной, но пользователи сообщают об успехе.

person Cyker    schedule 24.12.2016
comment
Большое спасибо, это намного лучше, чем выяснять, как каждая утилита в мире реализует завершение bash. - person artm; 19.06.2017

У меня псевдоним g = 'git', и в сочетании с псевдонимами git я набираю такие вещи, как

$ g co <branchname>

Более простым исправлением для моего конкретного варианта использования было добавление одной строки в git-Completion.

Прямо под этой строкой:

__git_complete git _git

Я добавил эту строку для обработки моего единственного псевдонима 'g':

__git_complete g _git
person wonderfulthunk    schedule 22.05.2012
comment
(Я использую Cygwin.) Мне не удалось найти файл git-completion или эту строку в /etc/bash_completion.d/git, но я добавил complete -o default -o nospace -F _git g после своего псевдонима в .bash_aliases, и это сработало! - person idbrii; 04.12.2012
comment
Помните, что если вы отредактируете файл в /etc/bash-completion.d/ или только что в /usr/share/bash-completion/, вы потеряете свои изменения всякий раз, когда этот файл будет обновлен с помощью диспетчера пакетов. - person kub1x; 26.02.2016

Еще один вариант - использовать ~/.bash_completion файл. Чтобы создать gco псевдоним для git checkout, просто введите это:

_xfunc git __git_complete gco _git_checkout

Затем в ~/.bashrc вы должны указать только сам псевдоним:

alias gco='git checkout'

Две строчки. Вот и все.

Пояснение:

~/bash_completion берется в конце основного скрипта bash_completion. В gentoo я нашел основной скрипт в /usr/share/bash-completion/bash_completion.

Бит _xfunc git заботится об источнике git-completion файла, поэтому вам не нужно ничего помещать в ~/.bashrc.

Принятый ответ требует, чтобы вы скопировали .git-completion.sh и взяли его из своего ~/.bashrc файла, который я считаю неуместным.


PS: Я все еще пытаюсь понять, как не использовать весь git-completion скрипт в моей среде bash. Прокомментируйте или отредактируйте, если найдете способ.

person kub1x    schedule 26.02.2016
comment
Почему требуется _xfunc git? - person Tom Hale; 16.09.2016
comment
@TomHale Я попытался улучшить ответ. Вместо того, чтобы делать source ~/.git-completion.sh, я позволил _xfunc сделать это за меня. Просто кажется приятнее и чище делать это только в ~/.bash_completion. Без _xfunc (или источника) функция __git_complete не существует. - person kub1x; 18.09.2016
comment
Файл ~/.bash_completion не нужен - строка _xfunc у меня работает в .bashrc. - person Tom Hale; 21.09.2016

Вы также можете попробовать использовать псевдонимы Git. Например, в моем ~/.gitconfig файле есть раздел, который выглядит так:

[alias]
        co = checkout

Таким образом, вы можете ввести git co m<TAB>, и это должно расшириться до git co master, что является командой git checkout.

person mipadi    schedule 05.12.2008

На этой странице форума показано решение.

Поместите эти строки в свой .bashrc или .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

Это решение похоже на скрипт balshetzer, но на самом деле у меня работает только этот. (У скрипта Бальшетцера были проблемы с некоторыми из моих псевдонимов.)

person hcs42    schedule 16.01.2010
comment
; Это почти работает - я получаю пару ошибок, но доработка проходит. Что еще я могу сделать? -bash: eval: line 28: unexpected EOF while looking for matching ''' -bash: eval: line 29: syntax error: unexpected end of file - person pforhan; 11.10.2011
comment
@pforhan Я вижу проблемы с цитированием выше ... кавычки " внутри строки function должны быть указаны как \". Это, вероятно, съедает одну из ваших ' цитат где-то по ходу строки. - person Tom Hale; 28.04.2017

Вам просто нужно найти команду complete и вместо этого продублировать строку с псевдонимом.

У меня есть 2_. Проще говоря, d-m должен быть псевдонимом для docker-machine.

Итак, на Mac (через brew) файлы завершения находятся в cd `brew --prefix`/etc/bash_completion.d/.
В моем случае я редактировал файл с именем docker-machine.
Полностью внизу было:

complete -F _docker_machine docker-machine

Поэтому я просто добавил еще одну строку с моим псевдонимом:

complete -F _docker_machine docker-machine
complete -F _docker_machine d-m
person luckydonald    schedule 07.11.2016
comment
Это лучшее решение для простых (один в один) псевдонимов, например docker с псевдонимом d. Хотя для примера в вопросе git checkout с псевдонимом gco более сложен. - person wisbucky; 12.06.2018

Сначала найдите исходную команду завершения. Пример:

$ complete | grep git

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

Теперь добавьте их в свой сценарий запуска (например, ~ / .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_loader может не требоваться. Но в некоторых случаях функция завершения загружается динамически только после того, как вы наберете команду и нажмете TAB в первый раз. Поэтому, если вы не использовали исходную команду и попробовали использовать псевдоним + TAB, вы можете получить сообщение об ошибке типа «bash: Завершение: функция '_docker' не найдена».

person wisbucky    schedule 26.07.2018
comment
Строка _completion_loader требуется всегда, если сценарий завершения находится в /usr/share/bash-completion/completions/. Для обратной совместимости скрипты, расположенные в /etc/bash_completion.d, все равно будут загружаться при загрузке bash_completion. См .: фиксация завершения bash на github - person DerRockWolf; 16.05.2021

На этот вопрос есть много ответов, и, как и я, держу пари, что много сбитых с толку читателей. В моем случае у меня также было требование, чтобы мои точечные файлы работали на нескольких платформах с разными версиями Git. Я тоже не alias g=git, но вместо этого g определил как функцию.

Для этого мне пришлось объединить здесь разные ответы в одно решение. Хотя это уже повторяет ответы, я подумал, что кто-то в моей лодке может найти эту компиляцию полезной, как и я, когда впервые подошел к этому вопросу.

Это предполагает выполнение более старых и новых Git, значений по умолчанию для Ubuntu и brew install git в MacOS. В последнем случае установленные дополнения brew не обрабатывались bash (что я диагностирую позже).

# 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
person Sukima    schedule 19.03.2019

Если вы используете alias g='git', я добавляю эту строку кода в .bash_aliases

complete -o default -o nospace -F _git g
person Druta Ruslan    schedule 17.04.2019

Фелипе Контрерас, который уже достаточно активно использует функции завершения Git (см. Завершение Zsh в Git 2.30) предлагает (для - возможно - Git 2.31, Q1 2021) общедоступную функцию, которая поможет с автозаполнением псевдонимов.

Его предложение:

Назад в 2012 году я выступал за введение помощника, который позволил бы пользователям указывать псевдонимы, например:

git_complete gf git_fetch

Тогда был отказ, потому что не было четкого руководства для общедоступных функций (git_complete vs _git_complete vs _GIT_complete), а некоторые псевдонимы фактически не работали.

Перенесемся в 2020 год, и по-прежнему нет рекомендаций для общедоступных функций, и эти псевдонимы по-прежнему не работают (хотя я отправил исправления).

Это не помешало людям использовать эту функцию, которая явно необходима для настройки пользовательских псевдонимов (эта страница), и на самом деле это рекомендуемый способ.

Но неудобно, что пользователь должен вводить:

__git_complete gf _git_fetch

Или хуже:

__git_complete gk __gitk_main

8 лет - более чем достаточно времени, чтобы перестать ждать грядущего идеального; давайте определим общедоступную функцию (с тем же именем), которая действительно удобна для пользователя:

__git_complete gf git_fetch
__git_complete gk gitk

При этом сохраняется обратная совместимость.

Логика такова:

  1. Если $2 существует, используйте его напрямую
  2. Если нет, проверьте, существует ли __$2_main
  3. Если нет, проверьте, существует ли _$2
  4. Если нет, не получится
person VonC    schedule 29.12.2020

Вы можете привязать Tab к alias-expand-line и complete (его действие по умолчанию) в ~/.inputrc. Для этого вам сначала нужно связать каждое действие с ключом, а затем связать их вместе следующим образом:

"\M-z":alias-expand-line
"\M-x":complete
TAB:"\M-z\M-x"

Вы можете использовать любые комбинации клавиш, которые вам нравятся, я использую Meta, потому что это бесплатно. См. man 3 readline для получения дополнительной информации.

Теперь, если вы откроете новый терминал и наберете псевдоним:

gco m<TAB>

Линия будет преобразована в

git checkout master

Конечно, Tab будет работать как обычно, даже если не задействован псевдоним.

person Quasímodo    schedule 10.03.2021