Введение

Пользователи взаимодействуют с Linux при помощи многочисленных команд, вводимых в командной строке. Учитывая разнообразие этих команд и их параметров, не так просто запомнить все наизусть.

Однако в Linux предусмотрена удобная функция автодополнения (auto completion) для Bash. Этот инструмент, с которым обычно знакомятся на начальных этапах изучения Linux, значительно ускоряет и упрощает процесс ввода команд. Он автоматически дополняет имена файлов, каталогов или опции команд, когда вы вводите их в командной строке.

В данной статье мы подробно рассмотрим принцип работы автодополнения в Linux и покажем, как можно создать собственную систему автодополнения.

Команда Complete

Центральный инструмент для автодополнения — команда complete. Эта команда встроена в Bash и отвечает за основную механику автодополнения. Она позволяет устанавливать конкретные автодополнения для различных команд через ряд параметров.

complete: usage: complete [-abcdefgjksuv] [-pr] [-DE] [-o option] [-A action] 
  [-G globpat] [-W wordlist]  [-F function] [-C command] [-X filterpat] [-P prefix]
  [-S suffix] [name ...]

Рассмотрим пример использования команды complete для задания списка автодополнения к вымышленной команде foo:

$ complete -W "bar car" foo
$ foo [Tab][Tab]
bar car
$ foo b[Tab]
$ foo bar

В данном контексте параметр -W позволил нам установить конкретный список слов для автодополнения команды foo.

Для более сложных задач, таких как добавление в автодополнение имен файлов и каталогов, можно использовать параметры -f и -d:

$ touch a.txt
$ mkdir test
$ complete -f -d -W "bar car" foo
$ foo [Tab][Tab]
a.txt  bar    car    test/  

После выполнения данной последовательности команд, автодополнение для foo будет включать в себя как файлы и каталоги, так и заранее заданный список слов.

Применение пользовательских функций

В Bash существует возможность вызова определенной функции в процессе автодополнения. Данная функция может формировать и возвращать список слов для автодополнения. Для этого используется параметр -F команды complete. В практических приложениях это одна из наиболее часто используемых опций:

$ complete -F _mac_addresses foo
$ foo [Tab][Tab]
09:00:22:eb:1e:29  52:54:00:04:29:35  

В приведенном выше примере функция _mac_addresses вызывается при автодополнении. Эта функция является частью механизма автодополнения Bash и отображает MAC-адреса сетевых интерфейсов нашей машины. Поэтому, после нажатия клавиши Tab, были показаны соответствующие MAC-адреса.

Здесь, мы использовали заренее определенную функция, но стоит отметить, что вы также можете создавать и применять свои функции, которые будут доступны для вызова механизмом автодополнения.

Создание функции для автодополнения

Как упоминалось выше, Bash позволяет вызывать функцию в процессе автодополнения по нажатию клавиши Tab.

Для эффективной работы такая функция должна обладать следующими возможностями:

  • Содержать логику для формирования списка дополняемых слов

  • Получать аргументы командной строки.

  • Основываясь на аргументах командной строки, вычислять список для автодополнения.

  • Передавать сформированный список обратно в оболочку.

Для упрощения этого процесса в Bash предусмотрены некоторые заранее определенные переменные:

  • COMP_WORDS: массив, содержащий аргументы командной строки.

  • COMP_CWORD: индекс в этом массиве, указывающий на текущий элемент.

  • COMPREPLY: итоговый массив, который содержит сформированный список слов. Он, в конечном итоге и будет подставлен для автодополнения.

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

Размещение функции

Нам надо разместить нашу функцию в папке, из которой механизм автодополнения сможет её считать и загрузить.

Скрипт /etc/bash_completion отвечает за инициализацию автодополнения Bash. Этот скрипт вызывается при логине пользователя с последующей загрузкой скриптов из директории /etc/bash_completion.d.

Таким образом, файл с нашей пользовательской функцией мы должны разместить в директории /etc/bash_completion.d. После этого, при входе в систему, наша функция будет автоматически подключена и готова к вызову при автодополнении.

Внутри пользовательской функции нам надо определить логику создания списка слов для автодополнения. В Bash существует специальная команда как раз для такой задачи. Рассмотрим её подробнее.

Команда compgen

Команда compgen упрощает процесс сравнения с образцом при автодополнении. Она поддерживает большинство параметров команды complete.

Вот её синтаксис:

compgen: usage: compgen [-abcdefgjksuv] [-o option] [-A action] [-G globpat]
  [-W wordlist]  [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] 
  [word]

Рассмотрим пример использования:

$ compgen -W "bar car" -- ""
bar
car
$ compgen -W "bar car" -- "b"
bar

Здесь с помощью параметра -W мы указали список слов. Затем, после -- мы передали слово для сопоставления.

В первой команде мы передали пустую строку и в выводе мы получили все слова из указанного списка слов.

Во второй команде мы передали строку "b". В результате команда compgen показала только соответствующие варианты: слово "bar" начинается на букву "b".

Таким образом, эта команда оказывается очень полезной при подготовке списка автодополнения, т.к. она отфильтровывает возможные варианты по части строки.

Пример функции

Давайте завершим обзор функцией, которая бы автодополняла нашу условную команду foo.

Предположим, у команды foo есть две опции: bar и car. Для bar у нас есть дополнительные опции drink и eat. Точно так же, для car у нас есть drive и park.

Теперь рассмотрим функцию:

function _foo()
{
  latest="${COMP_WORDS[$COMP_CWORD]}"
  prev="${COMP_WORDS[$COMP_CWORD - 1]}"
  words=""
  case "${prev}" in
    foo)
      words="bar car"
      ;;
    bar)
      words="eat drink"
      ;;
    car)
      words="drive park"
      ;;
    *)
      ;;
  esac

  COMPREPLY=($(compgen -W "$words" -- $latest))
  return 0
}

complete -F _foo foo

Сначала создайте файл /etc/bash_completion.d/foo. Затем внутри файла определите функцию _foo. В конце файла вызовите complete для нашей команды foo.

Давайте разберём тело функции по частям.

  1. latest="${COMP_WORDS[$COMP_CWORD]}" - отбирается последнее введённое в командной строке слово

  2. prev="${COMP_WORDS[$COMP_CWORD - 1]}" - отбирает предпоследнее слово.

  3. Блок case в зависимости от значения prev устанавливает список слов для автодополнения.

  4. COPMREPLY=($(compgen -W "$words" -- $latest)) генерирует список автодополнения (выбранный в предыдущем блоке) для последнего слова в коммандной строке. Получается, если пользователь ввёл foo, то списком станет bar и car. Когда пользователь ввёдёт одно из них, например, bar и нажмёт tab, снова сработает эта функция и выберет новые слова автодополнения уже для bar.

Это простая функция призвана продемонстрировать основную концепцию автодополнений. Мы не определили спецификацию автодополнения для подкоманд. Однако это дает представление о том, как реализовать функцию.

Наконец, давайте подключим файл, чтобы проверить команду и убедиться, что автодополнение работает для команды:

$ source /etc/bash_completion.d/foo
$ foo [Tab][Tab]
bar car
$ foo bar[Tab][Tab]
drink eat

Заключение

В данной статье мы изучили, как работает автодополнение с использованием клавиши Tab. Мы рассмотрели принципы работы команд complete и compgen. Эти команды поддерживают различные опции, которые мы можем выбирать в зависимости от наших потребностей. В завершение мы обсудили, как реализовать функцию, делающую весь процесс автодополнения более гибким.

Комментарии (4)


  1. LinuxCertifiedInstructor
    30.09.2023 12:24

    Спасибо - Полезный перевод.

    Всё было нужно разобраться в вызове функция командой complete, но не позволяла (скорее всего лень) сложности перевода английской документации в bash (для zsh давно разобрался) - в итоге половину статьи прочитал и всё понял))


    1. alexisayenko Автор
      30.09.2023 12:24

      спасибо за отзыв :)


  1. misha55robby
    30.09.2023 12:24
    +1

    Забавно, но на Astra эти команды не работают


    1. alexisayenko Автор
      30.09.2023 12:24

      хм, интересно. какая версия bash в Astra LInux?