Настройка вывода завершения bash: каждое предложение в новой строке

когда вы вводите что-то, вы часто используете автозаполнение bash: вы начинаете писать команду, например, и вы вводите TAB чтобы получить остальную часть слова.

как вы, вероятно, заметили, когда несколько вариантов соответствуют вашей команде, bash отображает их следующим образом:

foobar@myserv:~$ admin-
admin-addrsync         admin-adduser          admin-delrsync         admin-deluser          admin-listsvn
admin-addsvn           admin-chmod            admin-delsvn           admin-listrsync

Я ищу решение для отображения каждого возможного решения в новой строке, аналогично последнему столбцу на ls -l. Еще лучше,это было бы прекрасно если бы я мог применить правило такое: "если вы найдете менее 10 предложений, отображать их по одной строке, если больше = > фактический дисплей".

2 ответов


bash до версии 4.2 не допускает никакого контроля над формат соревнования, к сожалению.

Bash 4.2 + позволяет переключиться на выход 1-suggestion-per-line , как пояснил полезный ответ Гриши Левита, а также к умное решение достижения per-completion-function решение.

следующий это хитрый обходной на таможни завершение. Решение этой проблемы в общем, for все определенные завершения, было бы гораздо сложнее (если бы был способ вызвать readline функции напрямую, это может быть проще,но я не нашел способ сделать это).

тестирование доказательство концепции ниже:

  • сохранить в файл и источник он (. file) в интерактивной оболочке - это:
    • определите команду с именем foo (функция панциря)
    • чьи аргументы завершаются на основе совпадающих имен файлов в текущем каталоге.
    • (при foo на самом деле вызывается, он просто печатает свой аргумент в диагностической форме.)
  • вызвать как: foo [fileNamePrefix], нажмите клавишу tab:
    • если между 2 и 9 файлов в текущий каталог соответствует, вы увидите желаемое отображение строки за строкой.
    • в противном случае (1 матч или 10 или более матчей), нормальное завершение.

ограничения:

  • завершение работает только при применении к последнему аргументу в редактируемой командной строке.
  • когда завершение фактически вставляется в командную строку (как только совпадение однозначно), пробел не добавлено к нему (это поведение требуется для обходного пути).
  • перерисовка приглашения в первый раз после печати вывода в пользовательском формате может работать неправильно: перерисовка командной строки, включая приглашение, должна быть имитация и так как нет прямого способа получить расширен версия строки определения приглашения, хранящейся в $PS1, a решение (навеяно https://stackoverflow.com/a/24006864/45375), которая должна работать в типичный случаи, но не является надежным.

подход:

  • определяет и назначает пользовательскую функцию оболочки завершения команде интереса.
  • пользовательская функция определяет совпадения и, если их количество находится в желаемом диапазоне, обходит обычный механизм завершения и создает пользовательский формат выход.
  • пользовательский форматированный вывод (каждый матч в своей собственной строке) отправляется непосредственно на терминал >/dev/tty, а затем приглашение и командная строка вручную "перерисовываются", чтобы имитировать стандартное поведение завершения.
  • см. комментарии в исходном коде для деталей реализации.
# Define the command (function) for which to establish custom command completion.
# The command simply prints out all its arguments in diagnostic form.
foo() { local a i=0; for a; do echo "$$((i+=1))=[$a]"; done; }

# Define the completion function that will generate the set of completions
# when <tab> is pressed.
# CAVEAT:
#  Only works properly if <tab> is pressed at the END of the command line,
#  i.e.,  if completion is applied to the LAST argument.
_complete_foo() {

  local currToken="${COMP_WORDS[COMP_CWORD]}" matches matchCount

  # Collect matches, providing the current command-line token as input.
  IFS=$'\n' read -d '' -ra matches <<<"$(compgen -A file "$currToken")"

  # Count matches.
  matchCount=${#matches[@]}

  # Output in custom format, depending on the number of matches.
  if (( matchCount > 1 && matchCount < 10 )); then

      # Output matches in CUSTOM format:
      # print the matches line by line, directly to the terminal.
    printf '\n%s' "${matches[@]}" >/dev/tty
      # !! We actually *must* pass out the current token as the result,
      # !! as it will otherwise be *removed* from the redrawn line,
      # !! even though $COMP_LINE *includes* that token.
      # !! Also, by passing out a nonempty result, we avoid the bell
      # !! signal that normally indicates a failed completion.
      # !! However, by passing out a single result, a *space* will
      # !! be appended to the last token - unless the compspec
      # !! (mapping established via `complete`) was defined with 
      # !! `-o nospace`.
    COMPREPLY=( "$currToken" )
      # Finally, simulate redrawing the command line.
        # Obtain an *expanded version* of `$PS1` using a trick
        # inspired by https://stackoverflow.com/a/24006864/45375.
        # !! This is NOT foolproof, but hopefully works in most cases.
    expandedPrompt=$(PS1="$PS1" debian_chroot="$debian_chroot" "$BASH" --norc -i </dev/null 2>&1 | sed -n '${s/^\(.*\)exit$//p;}')
    printf '\n%s%s' "$expandedPrompt" "$COMP_LINE" >/dev/tty


  else # Just 1 match or 10 or more matches?

      # Perform NORMAL completion: let bash handle it by 
      # reporting matches via array variable `$COMPREPLY`.
    COMPREPLY=( "${matches[@]}" )    

  fi 

}

# Map the completion function (`_complete_foo`) to the command (`foo`).
# `-o nospace` ensures that no space is appended after a completion,
# which is needed for our workaround.
complete -o nospace -F _complete_foo -- foo

bash 4.2+ (и, в более общем плане, приложения, использующие readline 6.2+) поддержка с использованием completion-display-width переменной.

количество столбцов экрана, используемых для отображения возможных совпадений при выполнении завершения. Значение игнорируется, если оно меньше 0 или больше ширины экрана терминала. значение 0 приведет к отображению совпадений по одному в строке. значение по умолчанию -1.

выполните следующие действия, чтобы задать поведение для всех завершений1 для текущей сессии:

bind 'set completion-display-width 0'

или измените свой ~/.inputrc2 есть:

set completion-display-width 0

чтобы изменить поведение для всех новых оболочек.

1 посмотреть здесь для метода управления этим поведением для индивидуального пользовательского завершения функции.

2 путь поиска для файла инициализации readline -$INPUTRC, ~/.inputrc, /etc/inputrc поэтому измените файл, подходящий для вас.