Можно ли настроить способ, которым bash завершает имена каталогов?

8

Я бы хотел поручить bash использовать специальный метод для выполнения определенных имен каталогов. Например, bash будет вызывать мою программу для выполнения завершения, если путь начинается с «$$», и, как правило, выполнять завершение в противном случае.

Это вообще возможно? Как бы вы это реализовали?

Баунти : я действительно ценю ответ на этот вопрос. Цель состоит в том, чтобы позволить autojump завершать пути для всех команд, когда пользователь запускает их с определенным префиксом. Так, например, при копировании файла из удаленного каталога вы можете набрать:

cp $$patern + <Tab>

и автопрыжки будут завершены

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

и вам просто нужно добавить, куда вы хотите поместить файл. Конечно, я могу использовать комментарий Отта, чтобы добавить его к нескольким конкретным командам, но если у кого-то есть идея получше, я был бы очень благодарен.

Пельтье
источник
См. Раздел «Программируемое завершение» на странице руководства bash.
Если вы проголосуете, чтобы закрыть мой вопрос, пожалуйста, объясните почему.
Пельтье
2
«complete» поддерживает «-G pattern» для сопоставления $$ с началом и «-F func» для вызова вашей собственной функции, но для работы требуется одно или несколько имен команд.
Почему бы просто не использовать переменную окружения? Например: cp $ prefix / file / path / to / dest /
Xenoactive
@Xenoactive: потому что autojump полностью автоматизирован и работает по нескольким путям. Использование установленных вручную переменных среды не помогает. Или, может быть, у вас есть мощная идея, которую я не понимаю?
Пельтье

Ответы:

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) -релиз (по умолчанию).

многочлен
источник
Мне кажется, что это работает только с первым параметром команды, и может также делать странные вещи, если вкладка используется неожиданным образом (например, после $$$ или после имени команды), или я ошибаюсь?
Harrymc
Что ж, он передает $ *, поэтому он будет «работать» не только с первым параметром (я вообще не знаю autojump, поэтому не уверен, что он может принимать несколько аргументов). Вы можете перейти к концу и отправить только последний в autojump или использовать READLINE_POINT, чтобы определить, где находится курсор в аргументах команды, и также отправить только это слово в autojump.
полином
Ваше решение интересно, но вы должны признать, что переход на клавишу табуляции - это немного экстрим. Нет способа предвидеть все возможные случаи.
Harrymc
Спасибо за ваш ответ, это хорошее альтернативное решение, и оно касается части «для всех команд» моего вопроса. Я согласен с harrymc, что это немного экстремально, хотя ... Я думаю, если никто не придумает лучшего решения, я попробую и посмотрю, насколько оно жизнеспособно.
Пельтье
Я тоже согласен с harrymc, но пытался ответить на вопрос в том виде, в котором он был задан. Лично я просто привязал бы это к другой управляющей клавише, такой как ^ G или что-то еще, чтобы я мог оставить вкладку в покое, но все еще использовать эту функцию
полином
1

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

Вот пример shell-скрипта, который в любом параметре будет заменен $$[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

Вы должны получить исходный текст сценария для source <file-name>запуска через (или команду dot), чтобы он заработал, а затем:

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

Чтобы он всегда работал для некоторых или всех пользователей, включите его в одну из процедур профиля bash .

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

Протестировано на CentOS 5.5.

Этот простой сценарий основан на источниках, которые я перечислил в другом ответе, который был удален модератором studiohack. Если интересно, просто попроси его восстановить его.

harrymc
источник
Спасибо за Ваш ответ. Мой вопрос был не совсем об этом, так как я был новым, это было возможно, но я не буду выполнять все команды. Однако я думаю, что если решение полинома окажется неприемлемым, я реализую нечто подобное и попытаюсь нацелиться на наиболее распространенные команды.
Пельтье