Дело в точке:
Я использую Mac с bash v3.2.17, я использую git, установленный через macports, с вариантом bash_completion.
Когда я набираю git checkout m<tab>
. например, я доделал его до master
.
Однако у меня есть псевдоним git checkout
, gco
. Когда я набираю gco m<tab>
, имя ветки не заполняется автоматически.
В идеале я бы хотел, чтобы автозаполнение просто волшебным образом работало для всех моих псевдонимов. Является ли это возможным? В противном случае я бы хотел вручную настроить его для каждого псевдонима. Итак, как мне поступить?
Вопросы с большим количеством голосов, чем верхний ответ, часто подразумевают отличный запросы функций
Еще один ответ от суперпользователя, поскольку кто-то указал мне, что мой вопрос был обманом этого. superuser.com/questions/436314/…
В git-completion.bash
есть строчка:
complete -o default -o nospace -F _git git
Глядя на эту строку (и функцию _git), вы можете добавить эту строку в свой .bash_profile
:
complete -o default -o nospace -F _git_checkout gco
некоторые из функций мерзавец * bash больше не работают с этим методом
Да, раньше это отлично работало, пока что-то не изменилось в git_completion.bash ... Теперь он работает с полной командой, но не с псевдонимом.
См. В конце этой страницы ответы, которые работают в современном git.
это работает хорошо - добавил это в мой .bash_profile, и до сих пор отлично работает с псевдонимами и без них: github.com/larrybotha/dotfiles/blob/master/…
Вы также можете попробовать использовать псевдонимы Git. Например, в моем файле ~/.gitconfig
у меня есть такой раздел:
[alias]
co = checkout
Итак, вы можете ввести git co m<TAB>
, и это должно расшириться до git co master
, то есть команды git checkout
.
Я тоже столкнулся с этой проблемой и придумал этот фрагмент кода. Это автоматически даст вам завершение для всех псевдонимов. Запустите его после объявления всех (или любых) псевдонимов.
# 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
Линия let COMP_CWORD+=$num_alias_arguments
по какой-то причине не работала в Mac OS X. Замена его на ((COMP_CWORD+=$num_alias_arguments))
исправила его, хотя
Вау, это круто - спасибо! wrap_alias
подавляется двойными кавычками в определении псевдонима, и я думаю, это не имеет особого смысла для псевдонимов с несколькими командами (alias 'foo=bar; baz'
), поэтому я помещаю дополнительный | grep -v '[";|&]'
после alias -p
. Кроме того, он становится немного медленным для сотен определений псевдонимов, но я рад подтвердить, что использование echo
вместо eval
и передача вывода в файл кеша (который затем может быть записан в eval
за один раз) работает нормально и является сверх быстрый.
Еще один совет: wrap_alias
требует настройки доработок, поэтому мне пришлось переместить source /etc/bash_completion
перед кодом wrap_alias
.
Я думаю, что вокруг \"
должен быть \${COMP_WORDS[@]:1}
, чтобы эта работа работала с пробелами в аргументах. (Но я действительно не знаю, что делаю, поэтому мне неудобно редактировать ответ в данный момент.)
Это сработало для меня в OS X 10.7.2 после изменения строки let COMP_CWORD+=$num_alias_arguments
на let \"COMP_CWORD+=$num_alias_arguments\"
.
Сделал следующее, чтобы обернуть только указанные псевдонимы: function wrap_aliases {для cmdname в "$ @"; do cmdname = "$ (псевдоним $ cmdname | sed 's / sudo //')"; eval "$ (echo $ cmdname | sed -e 's / alias ([^ =] [^ =] *) =' \ '' ([^] [^] *) * (. *) '\' '/ wrap_alias \ 1 \ 2 '\' '\ 3' \ '' / ') "; Выполнено }
OSX 10.7.2 здесь не работала ни с советами @irh, ни с советами Марио Фернандеса. Есть идеи, что может быть не так или как я могу это отладить?
Пришлось исключить следующие псевдонимы: [[ "_longopt" = $completion_function ]] && return 0
В любом случае, я могу заставить эту работу работать с sudo? Я добавил alias agi='sudo apt-get install'
, но agi + emac <TAB> ничего не делает.
@ obvio171 Вам понадобится функция завершения для sudo.
@HeskyFisher, не могли бы вы рассказать поподробнее? Извините, я не слишком разбираюсь в bash.
@ obvio171 Я предлагаю задать это как вопрос о переполнении стека.
@ obvio171: Из ответа Грэма: добавьте | sed 's/sudo //'
перед sed -e 's/alias'
, и он автоматически включит функцию завершения для команды послеsudo
.
Если у кого-то возникли проблемы с некоторыми псевдонимами, которые не получают правильного завершения, см. Мой комментарий здесь
См. Обновленную версию этого скрипта по адресу superuser.com/a/437508/102281 (например, я добавил поддержку COMP_LINE и COMP_POINT, которые необходимы для некоторых завершений git).
Извините, но непоточные комментарии - НЕ подходящее место для совместной работы над кодом. Как минимум, это должно быть сутью. Но, поскольку gists не позволяет создавать ни вопросы, ни предлагать запросы на вытягивание, это действительно должно быть реальное репозиторий git. (даже ссылка, которой поделился Джон Меллор, - это полные комментарии кодеров)
Ура, классный скрипт, но он терпит неудачу, когда это нетривиальный псевдоним, содержащий токены типа (($UID))
;) ... все же, очень круто. Я использую grep -v
, чтобы избавиться от нескольких оскорбительных псевдонимов, и добавил это в последовательность каналов сразу после alias -p
...
Эта страница форума показывает решение.
Поместите эти строки в ваш .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
Это решение похоже на сценарий Бальшетцера, но только оно мне подходит. (У скрипта Бальшетцера были проблемы с некоторыми из моих псевдонимов.)
; Это почти работает - я получаю пару ошибок, но доработка проходит. Что еще я могу сделать? -bash: eval: line 28: unexpected EOF while looking for matching '''
-bash: eval: line 29: syntax error: unexpected end of file
@pforhan Я вижу проблемы с цитированием выше ... кавычки "
внутри строки function
должны быть указаны как \"
. Это, вероятно, съедает одну из ваших цитат из '
где-то по ходу дела.
У меня псевдоним g = 'git', и в сочетании с псевдонимами git я набираю такие вещи, как
$ g co <branchname>
Более простым исправлением для моего конкретного варианта использования было добавление одной строки в git-Completion.
Прямо под этой строкой:
__git_complete git _git
Я добавил эту строку для обработки моего единственного псевдонима 'g':
__git_complete g _git
(Я использую Cygwin.) Мне не удалось найти файл git-completion
или эту строку в /etc/bash_completion.d/git
, но я добавил complete -o default -o nospace -F _git g
после своего псевдонима в .bash_aliases
, и это сработало!
Помните, что если вы отредактируете файл в /etc/bash-completion.d/
или только что в /usr/share/bash-completion/
, вы потеряете свои изменения всякий раз, когда этот файл будет обновлен с помощью диспетчера пакетов.
Как указано в комментариях выше,
complete -o default -o nospace -F _git_checkout gco
больше не будет работать. Однако в git-completed.bash есть функция __git_complete
, которую можно использовать для настройки автозавершения для таких псевдонимов:
__git_complete gco _git_checkout
Если вы используете глобальный псевдоним «g» для git, вы также можете добавить __git_complete g __git_main
, чтобы завершить работу над всеми командами git.
^^ Для новичков в git / shell / bash. Приведенный выше комментарий относится к глобальному псевдониму оболочки, а не к собственному псевдониму git.
Что, если бы git
был наложен на g
, а checkout был привязан к co
, поэтому я использую g co <tab>
, но также не заполняю автозаполнение.
Куда мне это поставить?
Наконец разобрался, как это правильно сделать! Шаг 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) Перезагрузите оболочку и наслаждайтесь автозаполнением псевдонима! :)
@benregn Я поместил его прямо под source ~/.git_completion.sh
в моем ~/.bash_profile
-1 Этот ответ, похоже, предполагает, что вы прочитали и поняли какой-то старый неправильный ответ (но какой?) И, следовательно, знаете, в каком файле и где в этом файле принадлежит эта строка текста. Старайтесь только предполагать знание вещей, установленных в вопросе.
Есть хороший Суть, который предоставляет всю информацию, необходимую для его настройки.
Чтобы проверить количество ведущих символов подчеркивания для команд, отличных от __git_main
и _git_checkout
(таких как _git_merge
и _git_pull
), выполните поиск в сценарий .git-completion.bash. Все общие команды (те, которые я псевдоним) имеют только один начальный знак подчеркивания.
Что делать, если псевдоним, для которого вы хотите завершить, не имеет ничего общего с git; что делать, если в вашей системе / сервере не установлен git?
Это не настоящий ответ, потому что на самом деле он не говорит вам, что делать, а просто предоставляет некоторую информацию. Очень неполно.
Для людей, которые ищут сценарий завершения: find / -name "git-completion.bash"
.
Еще один вариант - использовать файл ~/.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. Прокомментируйте или отредактируйте, если найдете способ.
Зачем нужен _xfunc git
?
@TomHale Я попытался улучшить ответ. Вместо того, чтобы делать source ~/.git-completion.sh
, я позволил _xfunc
сделать это за меня. Просто кажется, что делать это только на ~/.bash_completion
приятнее и чище. Без _xfunc
(или источника) функции __git_complete
не существует.
Файл ~/.bash_completion
не нужен - линия _xfunc
у меня работает в .bashrc
.
Вам просто нужно найти команду complete
и вместо этого продублировать строку с псевдонимом.
У меня alias d-m = "docker-machine"
. Проще говоря, 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
Это лучшее решение для простых (один к одному) псевдонимов, таких как docker
с псевдонимом d
. Хотя для примера в вопросе git checkout
с псевдонимом gco
более сложен.
Ideally I'd like autocompletion to just magically work for all my aliases. Is it possible?
Да, это возможно с проектом полный псевдоним (в Linux). Поддержка Mac является экспериментальной, но пользователи сообщают об успехе.
Большое спасибо, это намного лучше, чем выяснять, как каждая утилита в мире реализует завершение bash.
Сначала найдите исходную команду завершения. Пример:
$ 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' не найдена».
На этот вопрос можно найти множество ответов, и, как и я, держу пари, что много сбитых с толку читателей. В моем случае у меня также было требование, чтобы мои точечные файлы работали на нескольких платформах с разными версиями 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
Если вы используете alias g='git'
, я добавляю эту строку кода в .bash_aliases
complete -o default -o nospace -F _git g
Фелипе Контрерас, который уже достаточно активен для функций завершения Git (см. Завершение Zsh в Git 2.30), предлагает (для - возможно - Git 2.31, Q1 2021) общедоступную функцию, которая поможет с автозаполнением псевдонимов.
Его предложение:
Back in 2012 I argued for the introduction of a helper that would allow users to specify aliases like:
git_complete gf git_fetch
Back then there was pushback because there was no clear guideline for public functions (
git_complete
vs_git_complete
vs_GIT_complete
), and some aliases didn't actually work.Fast-forward to 2020 and there's still no guideline for public functions, and those aliases still don't work (even though I sent the fixes).
This has not prevented people from using this function that is clearly needed to setup custom aliases (this page), and in fact it's the recommended way.
But it is cumbersome that the user must type:
__git_complete gf _git_fetch
Or worse:
__git_complete gk __gitk_main
8 years is more than enough time to stop waiting for the perfect to come; let's define a public function (with the same name) that is actually user-friendly:
__git_complete gf git_fetch __git_complete gk gitk
While also maintaining backwards compatibility.
The logic is:
- If
$2
exists, use it directly- If not, check if
__$2_main
exists- If not, check if
_$2
exists- If not, fail
Вы можете привязать 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 по-прежнему будет работать в обычном режиме, даже если не указан псевдоним.
Complete -o default -o nospace -F в настоящее время не работает