Apakah mungkin untuk mengkonfigurasi cara bash melengkapi nama direktori?

8

Saya ingin menginstruksikan bash untuk menggunakan metode khusus untuk melakukan penyelesaian pada nama direktori tertentu. Misalnya, bash akan memanggil program saya untuk melakukan penyelesaian jika jalur dimulai dengan "$$", dan melakukan penyelesaian secara normal sebaliknya.

Apakah ini mungkin? Bagaimana Anda mengimplementasikannya?

Bounty : Saya sangat menghargai jawaban untuk pertanyaan itu. Tujuannya adalah untuk memungkinkan autojump untuk menyelesaikan jalur untuk semua perintah ketika pengguna memulai dengan awalan tertentu. Jadi misalnya saat menyalin file dari direktori jauh, Anda dapat mengetik:

cp $$patern + <Tab>

dan autojump akan selesai

cp /home/user/CompliCatedDireCTOry/long/path/bla/bla

dan Anda hanya perlu menambahkan di mana Anda ingin meletakkan file. Tentu saja saya dapat menggunakan komentar ott untuk menambahkannya ke beberapa perintah tertentu, tetapi jika ada yang punya ide yang lebih baik, saya akan sangat berterima kasih.

Peltier
sumber
Lihat bagian "Penyelesaian yang Dapat Diprogram" di halaman bash man.
Jika Anda memilih untuk menutup pertanyaan saya, tolong jelaskan mengapa.
Peltier
2
"selesai" mendukung "pola -G" untuk mencocokkan $$ Anda dengan permulaan dan "-F func" untuk memanggil fungsi Anda sendiri, tetapi dibutuhkan satu atau lebih nama perintah untuk berfungsi.
Mengapa tidak menggunakan variabel lingkungan saja? Misalnya: cp $ awalan / file / path / ke / dest /
Xenoactive
@ Xenoactive: karena autojump sepenuhnya otomatis, dan bekerja di lebih dari satu jalur. Menggunakan variabel lingkungan yang diatur secara manual tidak membantu. Atau mungkin Anda punya ide kuat yang tidak saya mengerti?
Peltier

Jawaban:

3

Anda dapat melakukan ini dengan mengganti pengikatan default untuk TAB (^ i). Pertama Anda perlu mengganti TAB mengikat, maka Anda perlu membangun fungsi yang memanggil perintah Anda, terakhir Anda perlu mengambil output dari perintah itu dan memperbarui variabel yang berisi baris perintah saat ini.

Fungsi ini mengambil baris perintah saat ini dan mengubah dua karakter terakhir menjadi 'pelukan'.

function my_awesome_tab_completion_function () {
  set -- $READLINE_LINE
  command="$1"
  shift
  argument="$*"
  argument_length=$(echo -n $argument | wc -c)
  if echo $argument | grep '^$$' >/dev/null 2>&1; then
    new_argument=$(echo $argument | sed 's/..$/huugs/') # put your autojump here
  else
    new_argument=$(compgen -d $argument)
  fi
  new_argument_length=$(echo -n $new_argument | wc -c)
  READLINE_POINT=$(( $new_argument_length - $argument_length + $READLINE_POINT ))
  READLINE_LINE="$command $new_argument"
}

Sebagai contoh Anda, Anda mungkin ingin mengubah baris new_argument agar terlihat seperti ini:

  new_argument=$(autojump $argument)

Sekarang timpa ikatan ^ i:

$ bind -x '"\C-i"':'my_awesome_tab_completion_function'

Sekarang uji apakah itu berfungsi:

$ cd /ro<TAB>
changes my command to:
$ cd /root

jadi penyelesaian normal masih berfungsi, Anda dapat menguji bagian $$ dengan melakukan cd $$ ... dll

Jika Anda mengalami masalah, nyalakan mode verbose:

$ set -x

Ini akan mencetak semua fungsi yang sedang dilakukan.

Saya menguji ini pada Ubuntu 11 menggunakan bash 4.2.8 (1) -release (default).

jumlahnya banyak
sumber
Menurut saya ini hanya berfungsi pada parameter pertama dari perintah, dan juga dapat melakukan hal-hal aneh jika tab digunakan dengan cara yang tidak terduga (misalnya setelah $ $ atau setelah nama perintah), atau apakah saya salah?
harrymc
Yah itu melewati $ * jadi itu akan 'bekerja' pada lebih dari sekedar parameter pertama (saya tidak tahu autojump sama sekali jadi saya tidak yakin apakah itu dapat mengambil beberapa argumen). Anda dapat beralih ke akhir dan hanya mengirim yang terakhir ke autojump, atau menggunakan READLINE_POINT untuk menentukan di mana kursor berada di antara argumen perintah dan hanya mengirim 'kata' itu ke autojump juga.
polinomial
Solusi Anda menarik, tetapi Anda harus mengakui bahwa mengambil alih tombol tab agak ekstrem. Tidak mungkin Anda bisa mengantisipasi semua kemungkinan kasus.
harrymc
Terima kasih atas jawaban Anda, itu solusi alternatif yang bagus, dan itu menjawab bagian "untuk semua perintah" dari pertanyaan saya. Saya setuju dengan harrymc bahwa ini agak ekstrem, tapi ... Saya kira jika tidak ada yang menemukan solusi yang lebih baik, saya akan mencobanya dan melihat apakah itu layak.
Peltier
Ya saya setuju dengan harrymc juga, tetapi mencoba menjawab pertanyaan seperti yang ditanyakan. Secara pribadi saya hanya akan mengikat ini ke kunci kontrol lain seperti ^ G atau sesuatu sehingga saya bisa meninggalkan tab sendiri tetapi masih menggunakan fungsi ini.
polinomial
1

Rutin penyelesaian bash dapat diprogram sebagai skrip shell.

Berikut adalah contoh skrip shell yang akan menggantikan parameter apa pun $$[Tab]dengan my replacement string, tetapi hanya untuk perintah tertentu mycommanddan hanya jika parameternya persis "$$":

_mycomplete()
{
        if [ ${COMP_WORDS[COMP_CWORD]} == \$\$ ]
        then
                COMPREPLY='my replacement string'
        fi
}
complete -o default -o bashdefault -F _mycomplete mycommand

Anda harus sumber skrip untuk mem-bash melalui source <file-name>(atau perintah dot) untuk mulai bekerja, dan kemudian:

mycommand $$[Tab] -> mycommand my replacement string
mycommand $$$[Tab] -> mycommand $$$ (beep)
mycommand whatever[Tab] -> (will complete "whatever" in the normal bash manner)

Agar selalu berfungsi untuk sebagian atau semua pengguna, sertakan ini di salah satu rutinitas profil bash .

Masalah dengan completeperintah, adalah bahwa itu hanya akan berfungsi untuk satu atau lebih nama perintah, yang ditentukan sebagai parameter. Seseorang dapat dengan mudah memberikan daftar semua perintah yang mungkin dapat digunakan oleh pengguna, atau dalam kasus putus asa berkembang /bin/* /usr/bin/* ~/bin/*.

Diuji pada CentOS 5.5.

Skrip sederhana ini didasarkan pada sumber yang telah saya daftarkan dalam jawaban saya yang lain - yang telah dihapus oleh moderator studiohack. Jika tertarik, minta saja dia untuk membatalkan penghapusan.

harrymc
sumber
Terima kasih atas jawaban anda. Pertanyaan saya tidak benar-benar tentang itu karena saya baru itu mungkin, tetapi tidak akan menyelesaikan semua perintah. Namun saya berpikir bahwa jika solusi polinomial ternyata tidak dapat diterima, saya akan mengimplementasikan sesuatu seperti itu dan mencoba menargetkan perintah yang paling umum.
Peltier