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

Дело в точке:

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

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

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

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

Complete -o default -o nospace -F в настоящее время не работает

eighteyes 22.03.2013 23:20

Вопросы с большим количеством голосов, чем верхний ответ, часто подразумевают отличный запросы функций

Ciro Santilli新疆棉花TRUMP BAN BAD 20.01.2014 13:16

Еще один ответ от суперпользователя, поскольку кто-то указал мне, что мой вопрос был обманом этого. superuser.com/questions/436314/…

dstarh 21.01.2014 18:09
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
204
3
32 470
14
Перейти к ответу Данный вопрос помечен как решенный

Ответы 14

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

complete -o default -o nospace -F _git git

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

complete -o default -o nospace -F _git_checkout gco

некоторые из функций мерзавец * bash больше не работают с этим методом

cmcginty 23.09.2011 05:37

Да, раньше это отлично работало, пока что-то не изменилось в git_completion.bash ... Теперь он работает с полной командой, но не с псевдонимом.

Michael Smith 24.01.2012 07:21

См. В конце этой страницы ответы, которые работают в современном git.

eighteyes 22.03.2013 23:19

это работает хорошо - добавил это в мой .bash_profile, и до сих пор отлично работает с псевдонимами и без них: github.com/larrybotha/dotfiles/blob/master/…

Larry 02.07.2013 18:25

Вы также можете попробовать использовать псевдонимы 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)) исправила его, хотя

Mario F 05.01.2011 23:17

Вау, это круто - спасибо! wrap_alias подавляется двойными кавычками в определении псевдонима, и я думаю, это не имеет особого смысла для псевдонимов с несколькими командами (alias 'foo=bar; baz'), поэтому я помещаю дополнительный | grep -v '[";|&]' после alias -p. Кроме того, он становится немного медленным для сотен определений псевдонимов, но я рад подтвердить, что использование echo вместо eval и передача вывода в файл кеша (который затем может быть записан в eval за один раз) работает нормально и является сверх быстрый.

Jo Liss 13.01.2011 23:07

Еще один совет: wrap_alias требует настройки доработок, поэтому мне пришлось переместить source /etc/bash_completion перед кодом wrap_alias.

Jo Liss 13.01.2011 23:30

Я думаю, что вокруг \" должен быть \${COMP_WORDS[@]:1}, чтобы эта работа работала с пробелами в аргументах. (Но я действительно не знаю, что делаю, поэтому мне неудобно редактировать ответ в данный момент.)

Jo Liss 05.03.2011 02:52

Это сработало для меня в OS X 10.7.2 после изменения строки let COMP_CWORD+=$num_alias_arguments на let \"COMP_CWORD+=$num_alias_arguments\".

irh 31.10.2011 16:29

Сделал следующее, чтобы обернуть только указанные псевдонимы: function wrap_aliases {для cmdname в "$ @"; do cmdname = "$ (псевдоним $ cmdname | sed 's / sudo //')"; eval "$ (echo $ cmdname | sed -e 's / alias ([^ =] [^ =] *) =' \ '' ([^] [^] *) * (. *) '\' '/ wrap_alias \ 1 \ 2 '\' '\ 3' \ '' / ') "; Выполнено }

Graham 23.12.2011 13:14

OSX 10.7.2 здесь не работала ни с советами @irh, ни с советами Марио Фернандеса. Есть идеи, что может быть не так или как я могу это отладить?

agentofuser 30.01.2012 17:11

Пришлось исключить следующие псевдонимы: [[ "_longopt" = $completion_function ]] && return 0

Julien Carsique 28.01.2013 19:00

В любом случае, я могу заставить эту работу работать с sudo? Я добавил alias agi='sudo apt-get install', но agi + emac <TAB> ничего не делает.

agentofuser 04.04.2014 20:49

@ obvio171 Вам понадобится функция завершения для sudo.

Hesky Fisher 05.04.2014 23:45

@HeskyFisher, не могли бы вы рассказать поподробнее? Извините, я не слишком разбираюсь в bash.

agentofuser 07.04.2014 04:09

@ obvio171 Я предлагаю задать это как вопрос о переполнении стека.

Hesky Fisher 08.04.2014 05:02

@ obvio171: Из ответа Грэма: добавьте | sed 's/sudo //' перед sed -e 's/alias', и он автоматически включит функцию завершения для команды послеsudo.

jamadagni 25.10.2014 15:07

Если у кого-то возникли проблемы с некоторыми псевдонимами, которые не получают правильного завершения, см. Мой комментарий здесь

jamadagni 25.10.2014 20:05

См. Обновленную версию этого скрипта по адресу superuser.com/a/437508/102281 (например, я добавил поддержку COMP_LINE и COMP_POINT, которые необходимы для некоторых завершений git).

John Mellor 04.11.2014 20:24

Извините, но непоточные комментарии - НЕ подходящее место для совместной работы над кодом. Как минимум, это должно быть сутью. Но, поскольку gists не позволяет создавать ни вопросы, ни предлагать запросы на вытягивание, это действительно должно быть реальное репозиторий git. (даже ссылка, которой поделился Джон Меллор, - это полные комментарии кодеров)

Bruno Bronosky 17.02.2017 20:51

Ура, классный скрипт, но он терпит неудачу, когда это нетривиальный псевдоним, содержащий токены типа (($UID));) ... все же, очень круто. Я использую grep -v, чтобы избавиться от нескольких оскорбительных псевдонимов, и добавил это в последовательность каналов сразу после alias -p ...

0xC0000022L 20.08.2018 23:58

Эта страница форума показывает решение.

Поместите эти строки в ваш .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 11.10.2011 17:03

@pforhan Я вижу проблемы с цитированием выше ... кавычки " внутри строки function должны быть указаны как \". Это, вероятно, съедает одну из ваших цитат из ' где-то по ходу дела.

Tom Hale 28.04.2017 09:08

У меня псевдоним 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, и это сработало!

idbrii 04.12.2012 23:07

Помните, что если вы отредактируете файл в /etc/bash-completion.d/ или только что в /usr/share/bash-completion/, вы потеряете свои изменения всякий раз, когда этот файл будет обновлен с помощью диспетчера пакетов.

kub1x 26.02.2016 16:20
Ответ принят как подходящий

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

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.

Ondrej Machulda 15.04.2013 16:03

^^ Для новичков в git / shell / bash. Приведенный выше комментарий относится к глобальному псевдониму оболочки, а не к собственному псевдониму git.

Elijah Lynn 30.07.2013 17:33

Что, если бы git был наложен на g, а checkout был привязан к co, поэтому я использую g co <tab>, но также не заполняю автозаполнение.

Jürgen Paul 10.10.2013 01:38

Куда мне это поставить?

benregn 14.11.2013 19:26

Наконец разобрался, как это правильно сделать! Шаг 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) Перезагрузите оболочку и наслаждайтесь автозаполнением псевдонима! :)

kpsfoo 06.04.2014 01:14

@benregn Я поместил его прямо под source ~/.git_completion.sh в моем ~/.bash_profile

drees 20.06.2014 17:44

-1 Этот ответ, похоже, предполагает, что вы прочитали и поняли какой-то старый неправильный ответ (но какой?) И, следовательно, знаете, в каком файле и где в этом файле принадлежит эта строка текста. Старайтесь только предполагать знание вещей, установленных в вопросе.

Theodore Murdock 19.03.2015 02:28

Есть хороший Суть, который предоставляет всю информацию, необходимую для его настройки.

stempler 06.05.2015 16:13

Чтобы проверить количество ведущих символов подчеркивания для команд, отличных от __git_main и _git_checkout (таких как _git_merge и _git_pull), выполните поиск в сценарий .git-completion.bash. Все общие команды (те, которые я псевдоним) имеют только один начальный знак подчеркивания.

Jan Van Bruggen 17.09.2015 18:59

Что делать, если псевдоним, для которого вы хотите завершить, не имеет ничего общего с git; что делать, если в вашей системе / сервере не установлен git?

Alexej Magura 13.12.2016 23:25

Это не настоящий ответ, потому что на самом деле он не говорит вам, что делать, а просто предоставляет некоторую информацию. Очень неполно.

still_dreaming_1 10.10.2018 20:26

Для людей, которые ищут сценарий завершения: find / -name "git-completion.bash".

ShellFish 25.03.2020 21:29

Еще один вариант - использовать файл ~/.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?

Tom Hale 16.09.2016 16:13

@TomHale Я попытался улучшить ответ. Вместо того, чтобы делать source ~/.git-completion.sh, я позволил _xfunc сделать это за меня. Просто кажется, что делать это только на ~/.bash_completion приятнее и чище. Без _xfunc (или источника) функции __git_complete не существует.

kub1x 18.09.2016 11:23

Файл ~/.bash_completion не нужен - линия _xfunc у меня работает в .bashrc.

Tom Hale 21.09.2016 18:08

Вам просто нужно найти команду 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 более сложен.

wisbucky 12.06.2018 02:59

Ideally I'd like autocompletion to just magically work for all my aliases. Is it possible?

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

Большое спасибо, это намного лучше, чем выяснять, как каждая утилита в мире реализует завершение bash.

artm 19.06.2017 11:56

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

$ 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:

  1. If $2 exists, use it directly
  2. If not, check if __$2_main exists
  3. If not, check if _$2 exists
  4. 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 по-прежнему будет работать в обычном режиме, даже если не указан псевдоним.

Другие вопросы по теме