Bagaimana cara saya mendapatkan penyelesaian bash untuk bekerja dengan alias?

195

Inti masalah:

Saya menggunakan mac dengan bash v3.2.17, saya menggunakan git yang diinstal melalui macports dengan varian bash_completion.

Saat saya mengetik git checkout m<tab>. misalnya, saya menyelesaikannya sampai master.

Namun, saya punya alias untuk git checkout, gco. Saat saya mengetik gco m<tab>, saya tidak mendapatkan nama cabang yang dilengkapi secara otomatis.

Idealnya saya ingin pelengkapan otomatis hanya berfungsi secara ajaib untuk semua alias saya. Apa itu mungkin? Jika gagal, saya ingin menyesuaikannya secara manual untuk setiap alias. Jadi, bagaimana caranya?

kch
sumber
3
complete -o default -o nospace -F tidak berfungsi saat ini
eighteyes
5
Pertanyaan dengan jumlah suara lebih banyak daripada jawaban teratas sering kali menyiratkan permintaan fitur yang
Ciro Santilli 郝海东 冠状 病 六四 六四 事件
2
Jawaban lain dari pengguna super ketika seseorang menunjukkan kepada saya bahwa pertanyaan saya ada yang menipu ini. superuser.com/questions/436314/…
dstarh

Jawaban:

183

Sebagaimana dinyatakan dalam komentar di atas,

complete -o default -o nospace -F _git_checkout gco

tidak lagi berfungsi. Namun, ada __git_completefungsi di git-completion.bash yang dapat digunakan untuk mengatur penyelesaian untuk alias seperti:

__git_complete gco _git_checkout
chris_sutter
sumber
6
Ini adalah satu-satunya jawaban yang benar yang pernah saya lihat di antara banyak yang salah.
Eighteyes
45
Jika Anda menggunakan alias global "g" untuk git, Anda juga bisa menambahkan __git_complete g __git_mainuntuk menyelesaikan kode yang bekerja pada semua perintah git.
Ondrej Machulda
5
^^ Bagi yang baru git / shell / bash. Komentar di atas mengacu pada alias global shell, bukan alias git asli.
Elijah Lynn
14
Di mana saya harus meletakkan ini?
benregn
15
Akhirnya menemukan cara untuk melakukan ini dengan benar! Langkah 1) Salin git-completion.bashdari <your git install folder>/etc/bash-completion.d/ke ~/.git-completion.bash Langkah 2) tambahkan source ~/.git-completion.bashke .bash_profile Langkah Anda 3) Tambahkan di __git_complete gco _git_checkoutmana saja setelah baris di atas di .bash_profile Anda. Langkah 4) Reboot shell dan nikmati penyelesaian otomatis Anda! :)
kpsfoo
54

Saya mengalami masalah ini juga dan muncul dengan potongan kode ini. Ini secara otomatis akan memberi Anda penyelesaian untuk semua alias. Jalankan setelah mendeklarasikan semua (atau apa saja) alias.

# 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
sumber
6
saluran let COMP_CWORD+=$num_alias_argumentstidak berfungsi pada Mac OS X karena alasan tertentu. Menggantinya dengan ((COMP_CWORD+=$num_alias_arguments))memperbaikinya
Mario F
5
Wow, itu luar biasa - terima kasih! wrap_aliastersedak tanda kutip ganda dalam definisi alias, dan saya kira itu tidak masuk akal untuk alias multi-perintah ( alias 'foo=bar; baz'), jadi saya meletakkan tambahan | grep -v '[";|&]'setelah alias -p. Selain itu, agak lambat untuk ratusan definisi alias, tapi saya senang untuk mengonfirmasi bahwa menggunakan dan echobukannya evalmemipiskan output ke file cache (yang kemudian dapat di eval-edit sekaligus) berfungsi dengan baik dan sangat cepat .
Jo Liss
2
Petunjuk lain: wrap_aliasmembutuhkan penyelesaian yang harus diatur, jadi saya harus bergerak source /etc/bash_completiondi depan wrap_aliaskode.
Jo Liss
2
Ini bekerja untuk saya di OS X 10.7.2 setelah mengubah jalur let COMP_CWORD+=$num_alias_argumentske let \"COMP_CWORD+=$num_alias_arguments\".
irh
7
Lihat versi terbaru dari skrip ini di superuser.com/a/437508/102281 (misalnya, saya menambahkan dukungan untuk COMP_LINE dan COMP_POINT yang diperlukan untuk beberapa penyelesaian git).
John Mellor
18

Di git-completion.bashsana ada garis:

complete -o default -o nospace -F _git git

Melihat baris itu (dan fungsi _git) Anda dapat menambahkan baris ini ke .bash_profile:

complete -o default -o nospace -F _git_checkout gco
Chris Lloyd
sumber
4
beberapa fungsi git * bash tidak lagi berfungsi menggunakan metode ini
cmcginty
Ya ini digunakan untuk bekerja dengan baik sampai sesuatu berubah di git_completion.bash ... Sekarang berfungsi dengan perintah penuh tetapi tidak dengan alias.
Michael Smith
Lihat akhir halaman ini untuk jawaban yang bekerja di git modern.
Eighteyes
Tidakkah seharusnya kita mengubah jawaban yang diterima menjadi ini "benar", atau paling tidak memperbarui jawaban yang diterima untuk mencerminkan perubahan?
Tony K.
ini berfungsi dengan baik - menambahkan ini ke .bash_profile saya, dan berfungsi dengan baik dengan dan tanpa alias sejauh ini: github.com/larrybotha/dotfiles/blob/master/…
Larry
15

Saya memiliki alias g = 'git', dan dikombinasikan dengan alias git, saya mengetikkan hal-hal seperti

$ g co <branchname>

Perbaikan yang lebih mudah untuk kasus penggunaan khusus saya adalah menambahkan satu baris ke git-completion.

Tepat di bawah garis ini:

__git_complete git _git

Saya menambahkan baris ini untuk menangani alias 'g' tunggal saya:

__git_complete g _git
luar biasa
sumber
2
(Saya menggunakan Cygwin.) Saya tidak dapat menemukan file git-completionatau baris itu /etc/bash_completion.d/git, tetapi saya menambahkan complete -o default -o nospace -F _git gsetelah alias saya .bash_aliasesdan itu berhasil!
idbrii
Berhati-hatilah, bahwa jika Anda mengedit file masuk /etc/bash-completion.d/atau baru /usr/share/bash-completion/, Anda akan kehilangan perubahan Anda setiap kali file itu diperbarui menggunakan manajer paket Anda.
kub1x
14

Idealnya saya ingin pelengkapan otomatis hanya berfungsi secara ajaib untuk semua alias saya. Apa itu mungkin?

Ya, itu mungkin dengan proyek alias lengkap (di Linux). Dukungan untuk Mac bersifat eksperimental tetapi pengguna telah melaporkan keberhasilan.

Cyker
sumber
4
terima kasih banyak, ini jauh lebih baik daripada mencari tahu bagaimana setiap utilitas di dunia mengimplementasikan penyelesaian bash.
artm
2
Memang, menyelamatkan saya beberapa saat mengkonfigurasi pelengkap untuk alias.
Samir Alajmovic
2
Bekerja seperti jimat di Linux (tidak diuji pada Mac). Terima kasih telah menulisnya!
bitmask
1
Ini benar-benar luar biasa! Itu hanya bekerja, tidak ada masalah, lebih baik! Terima kasih!
emi
5

Anda juga bisa mencoba menggunakan alias Git. Misalnya, dalam ~/.gitconfigfile saya , saya memiliki bagian yang terlihat seperti ini:

[alias]
        co = checkout

Jadi Anda bisa mengetik git co m<TAB>, dan itu harus diperluas ke git co master, yang merupakan git checkoutperintah.

mipadi
sumber
5

Halaman forum ini menunjukkan solusinya.

Masukkan baris-baris ini ke dalam .bashrcatau .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

Solusi ini mirip dengan skrip balshetzer , tetapi hanya ini yang benar-benar berfungsi untuk saya. (Script balshetzer memiliki masalah dengan beberapa alias saya.)

hcs42
sumber
; Ini hampir berhasil - Saya mendapatkan beberapa kesalahan, tetapi penyelesaiannya berjalan. Ada lagi yang bisa saya lakukan? -bash: eval: line 28: unexpected EOF while looking for matching ''' -bash: eval: line 29: syntax error: unexpected end of file
pforhan
@ pforhan Saya bisa melihat masalah mengutip di atas ... "kutipan di dalam functionstring harus dikutip sebagai \". Ini mungkin memakan salah satu 'kutipan Anda di suatu tempat di sepanjang garis.
Tom Hale
5

Satu lagi pilihan adalah menggunakan ~/.bash_completionfile. Untuk membuat gcoalias git checkouthanya taruh ini di sana:

_xfunc git __git_complete gco _git_checkout

Maka di dalam ~/.bashrckamu harus meletakkan hanya alias itu sendiri:

alias gco='git checkout'

Dua baris. Itu dia.

Penjelasan:

Sumber ~/bash_completiondiperoleh di akhir skrip bash_completion utama. Di gentoo saya menemukan skrip utama di /usr/share/bash-completion/bash_completion.

The _xfunc gitbit mengurus sourcing git-completionfile untuk Anda sehingga Anda tidak perlu menempatkan apa pun di ~/.bashrc.

Jawaban yang diterima mengharuskan Anda untuk menyalin .git-completion.shdan sumbernya dari ~/.bashrcfile Anda yang saya temukan lumpuh.


PS: Saya masih mencoba mencari cara untuk tidak memasukkan seluruh git-completionskrip ke lingkungan bash saya. Silakan komentar atau edit jika Anda menemukan cara.

kub1x
sumber
Mengapa _xfunc gitdiperlukan?
Tom Hale
@ Tomale Saya mencoba meningkatkan jawabannya. Daripada melakukan, source ~/.git-completion.shsaya membiarkan _xfuncmelakukannya untuk saya. Rasanya lebih baik dan bersih untuk melakukannya semata-mata ~/.bash_completion. Tanpa _xfunc(atau sumber) __git_completefungsi tidak ada.
kub1x
1
Tidak perlu untuk ~/.bash_completionberkas - yang _xfuncgaris bekerja untuk saya di .bashrc.
Tom Hale
2

Anda hanya perlu menemukan completeperintah dan menduplikasi baris yang memiliki nama alias sebagai gantinya.

Saya punya alias d-m="docker-machine". Dengan kata lain, d-makan menjadi alias untuk docker-machine.

Jadi pada Mac (via minuman), file selesai dalam cd `brew --prefix`/etc/bash_completion.d/.
Untuk kasus saya, saya mengedit file bernama docker-machine.
Sepanjang jalan di bagian bawah ada:

complete -F _docker_machine docker-machine

Jadi saya baru saja menambahkan baris lain, dengan alias saya:

complete -F _docker_machine docker-machine
complete -F _docker_machine d-m
luckydonald
sumber
Ini adalah solusi terbaik untuk alias sederhana (satu lawan satu), seperti dockeralias d. Meskipun untuk contoh dalam pertanyaan, git checkoutalias gcolebih kompleks.
wisbucky
1

Pertama, cari perintah penyelesaian asli. Contoh:

$ complete | grep git

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

Sekarang tambahkan ini ke skrip startup Anda (mis. ~ / .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

The _completion_loadergaris mungkin tidak diperlukan. Tetapi untuk beberapa situasi, fungsi penyelesaian hanya dimuat secara dinamis setelah Anda mengetik perintah dan tekan TABpertama kali. Jadi jika Anda belum menggunakan perintah asli, dan coba alias + TAB, Anda mungkin mendapatkan kesalahan seperti "bash: completion: function '_docker' not found".

wisbucky
sumber
1

Ada banyak jawaban untuk pertanyaan ini dan seperti saya, saya bertaruh banyak pembaca yang bingung. Untuk kasus saya, saya juga memiliki persyaratan agar dotfile saya berfungsi pada beberapa platform dengan versi Git yang berbeda. Saya juga tidak alias g=gittetapi telah gdidefinisikan sebagai suatu fungsi.

Untuk mencapai ini, saya harus menampar jawaban yang berbeda di sini menjadi satu solusi. Meskipun ini mengulangi jawaban yang sudah saya pikir seseorang di kapal saya mungkin menemukan kompilasi ini berguna seperti yang akan saya miliki ketika saya pertama kali datang ke pertanyaan ini.

Ini mengasumsikan penyelesaian Git yang lebih lama dan lebih baru, default Ubuntu, dan brew install gitpada MacOS. Dalam kasus selanjutnya, kompilasi yang sudah selesai dibuat tidak diproses oleh bash (sesuatu yang akan saya diagnosa nanti).

# 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
sumber
0

Jika Anda menggunakan alias g='git', saya menambahkan baris kode ini di.bash_aliases

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