Подтвердить что ты не робот

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

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

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

[email protected]:~$ admin-
admin-addrsync         admin-adduser          admin-delrsync         admin-deluser          admin-listsvn
admin-addsvn           admin-chmod            admin-delsvn           admin-listrsync

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

4b9b3361

Ответ 1

bash до версии 4.2 не позволяет контролировать выходной формат завершений, к сожалению.

Bash 4.2+ позволяет переключиться на вывод 1-предложение на строку в глобальном масштабе, как объясняется в полезный ответ Гриши Левит, который также ссылается на a умное обходное решение для достижения решения для каждой функции завершения.

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

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

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

Ограничения

  • Завершение работы работает только при применении к аргументу LAST в редактируемой командной строке.
  • Когда заполнение фактически вставлено в командную строку (как только совпадение однозначно), к нему не добавляется пробел (это поведение требуется для обходного пути).
  • Повторная переадресация запроса в первый раз после печати выходного файла с автоматическим форматированием может работать некорректно: повторная перерисовка командной строки, включая приглашение, должна быть смоделирована, и поскольку нет прямого способа получить расширенную версию строки определения подсказки, хранящейся в $PS1 используется обходной путь (вдохновленный fooobar.com/questions/283220/...), который должен работать в типичных случаях, но не является надежным.

Подход

  • Определяет и назначает пользовательскую функцию оболочки завершения для интересующей команды.
  • Пользовательская функция определяет совпадения и, если их счетчик находится в нужном диапазоне, обходит нормальный механизм завершения и создает выходные данные в формате. format.
  • Выход в формате форматированного текста (каждое совпадение в собственной строке) отправляется непосредственно на терминал >/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 /questions/283220/echo-expanded-ps1/1412737#1412737.
        # !! 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$/\1/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

Ответ 2

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

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

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

bind 'set completion-display-width 0'

Или измените файл ~/.inputrc 2 чтобы:

set completion-display-width 0

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

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

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