Чи можна налаштувати спосіб, як bash завершує імена каталогів?


8

Я хотів би доручити bash використовувати спеціальний метод для виконання завершення певних імен каталогів. Наприклад, bash закликає програму моєї для виконання завершення, якщо шлях починається з "$$", і виконує завершення зазвичай інакше.

Це взагалі можливо? Як би ти це реалізував?

Баунті : Я дуже вдячний відповіді на це питання. Мета полягає в тому, щоб дозволити автовіддачі виконувати шляхи для всіх команд, коли користувач запускає їх із певним префіксом. Так, наприклад, копіюючи файл із далекого каталогу, ви можете ввести:

cp $$patern + <Tab>

і автозарядження завершиться

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

і вам просто доведеться додати файл, де ви хочете помістити файл. Звичайно, я можу використовувати коментар ott, щоб додати його до кількох конкретних команд, але якщо хтось має кращу ідею, я буду дуже вдячний.


Дивіться розділ "Програмоване завершення" на сторінці bash man.

Якщо ви голосуєте, щоб закрити моє запитання, будь ласка, поясніть, чому.
Пельтьє

2
"завершений" підтримує "-G візерунок", щоб відповідати вашому $$ початку та "-F func" викликати власну функцію, але для роботи потрібні одне або більше імен команд.

Чому б просто не використовувати змінну середовища? Наприклад: cp $ префікс / файл / шлях / до / dest /
Xenoactive

@Xenoactive: тому що автовідтворювач повністю автоматизований і працює на більш ніж одному шляху. Використання вручну встановлених змінних середовищ не допомагає. А може, у вас є потужна ідея, яку я не розумію?
Пельтьє

Відповіді:


3

Це можна зробити, змінивши прив'язку за замовчуванням для TAB (^ i). Спочатку вам потрібно перекрити прив'язку TAB, потім вам потрібно побудувати функцію, яка викликає вашу команду, нарешті, вам потрібно взяти вихід з цієї команди та оновити змінну, що містить поточний командний рядок.

Ця функція приймає поточний командний рядок і змінює останні два символи на 'huugs'.

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"
}

Для вашого прикладу ви, мабуть, захочете змінити рядок new_argument, щоб він виглядав так:

  new_argument=$(autojump $argument)

Тепер замініть прив'язку ^ i:

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

Тепер перевірте, що це працює:

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

тому нормальне завершення все ще працює, ви можете протестувати $$ частину, виконавши cd $$ ... тощо

Якщо у вас виникли проблеми, увімкніть багатомовний режим:

$ set -x

Він буде друкувати все, що робить функція.

Я перевірив це на Ubuntu 11, використовуючи bash 4.2.8 (1) -release (за замовчуванням).


Мені здається, що це працює лише за першим параметром команди, а також може робити дивні речі, якщо вкладка використовується несподіваними способами (наприклад, після $$$ або після назви команди), чи я помиляюся?
harrymc

Добре, що він передає $ *, тому він буде працювати над більш ніж першим параметром (я взагалі не знаю автовідтворення, тому я не впевнений, чи може він взяти кілька аргументів). Ви можете переключитися до кінця і лише надіслати останнє до автовідтворення, або скористатися READLINE_POINT, щоб визначити, де курсор є серед аргументів команди, і надіслати лише це слово також для автовідтворення.
многочлен

Ваше рішення цікаве, але ви повинні визнати, що переймання клавіші вкладки - трохи екстремальне. Немає способу передбачити всі можливі випадки.
harrymc

Дякую за вашу відповідь, це приємне альтернативне рішення, і воно стосується частини мого питання "для всіх команд". Я погоджуюся з harrymc, що це трохи екстремально, але ... я думаю, якщо ніхто не придумає кращого рішення, я спробую його і переконаюся, чи він життєздатний.
Пельтьє

Я теж погоджуюся з harrymc, але намагався відповісти на запитання, як було задано. Особисто я би просто прив’язав це до іншої керуючої клавіші, наприклад ^ G або чогось іншого, щоб я міг залишити вкладку в спокої, але все-таки використовувати цю функціональність.
многочлен

1

Процедура завершення баш може бути запрограмована як сценарій оболонки.

Ось приклад оболонки-скрипту, який замінить будь-який параметр $$[Tab]на my replacement string, але тільки для конкретної команди mycommandі лише якщо параметр точно "$$":

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

Ви повинні джерело скрипту, щоб виконати bash через source <file-name>(або команду крапки), щоб почати його працювати, а потім:

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

Щоб завжди він працював для деяких або всіх користувачів, включіть це в одну з процедур баш-профілю .

Проблема з completeкомандою полягає в тому, що вона буде працювати тільки для одного або декількох імен команд, які вказані як параметри. Можна просто дати йому список усіх команд, які, можливо, можуть бути використані користувачами, або у відчайдушних випадках розширитись /bin/* /usr/bin/* ~/bin/*.

Тестовано на CentOS 5.5.

Цей простий сценарій заснований на джерелах, які я вказав у своїй іншій відповіді - тому, яке було видалено модератором studiohack. Якщо вам цікаво, просто попросіть його скасувати його.


Дякую за вашу відповідь. Моє запитання насправді не було з цього питання, оскільки я з'явився новим, це було можливо, але не виконати всі команди. Однак я думаю, що якщо рішення полінома не виявиться прийнятним, я реалізую щось подібне і спробую націлити на найпоширеніші команди.
Пельтьє
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.