bash завершення для шаблонів імен файлів або каталогів


13

Я намагаюся налаштувати скрипт для завершення башти і маю деякі проблеми.

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

Проблема, яка у мене виникає, полягає в тому, що єдиний спосіб я можу отримати доповнення до файлів і каталогів, використовуючи щось на кшталт -o plusdirs -f -X '!*.txt', але коли я дозволяю bash завершити один з каталогів, він просто додає пробіл у кінці, а не коса риса.

_xyz()
{
  local cur=${COMP_WORDS[COMP_CWORD]}
  local prev=${COMP_WORDS[COMP_CWORD-1]}

  #COMPREPLY=( $( compgen -f -X '!*.txt' -- $cur ) )
  #COMPREPLY=( $( compgen -f -G '*.txt' -- $cur ) )
  #COMPREPLY=( $( compgen -o filenames -f -X '!*.txt' -- $cur ) )
  #COMPREPLY=( $( compgen -o dirnames  -f -X '!*.txt' -- $cur ) )
  COMPREPLY=( $( compgen -o plusdirs  -f -X '!*.txt' -- $cur ) )
  return 0
}

complete -F _xyz xyz

Я також спробував усі коментовані рядки теж, але вони навіть не розширюють каталоги.

Для тестування я запускав це в каталозі з одним .txt-файлом та однією директорією "dir" (з файлом .txt всередині нього, хоча це ще не має значення). Введення за xyz <TAB>допомогою цієї функції перераховує каталог і файл .txt, але введення xyz d<TAB>розгортається до xyz dir(ну, з пробілом після "dir").

Відповіді:


10

Якщо ви подивитеся на функцію _cd()в / etc / bash_completion , ви побачите, що вона додає саму косу рису і що завершує виклик з опцією -o nospaceдля cd .

Ви можете зробити те ж саме для xyz , але потрібно окремо перевірити, чи знайдений збіг - це каталог (якщо так, додайте косу рису) або файл (якщо так, додайте пробіл). Це слід зробити в циклі for для обробки всіх знайдених збігів.

Крім того, щоб правильно обробляти контури, що містять пробіли, потрібно встановити для внутрішнього розділювача файлів лише новий рядок та пропустити пробіли. Використання IFS=$'\n'в поєднанні з « printf %qРобота з завершенням» працює майже з усіма символами. 1 Необхідно бути особливо обережним, щоб не уникнути місця, що залишається.

Слід працювати:

_xyz ()
{
    local IFS=$'\n'
    local LASTCHAR=' '

    COMPREPLY=($(compgen -o plusdirs -f -X '!*.txt' \
        -- "${COMP_WORDS[COMP_CWORD]}"))

    if [ ${#COMPREPLY[@]} = 1 ]; then
        [ -d "$COMPREPLY" ] && LASTCHAR=/
        COMPREPLY=$(printf %q%s "$COMPREPLY" "$LASTCHAR")
    else
        for ((i=0; i < ${#COMPREPLY[@]}; i++)); do
            [ -d "${COMPREPLY[$i]}" ] && COMPREPLY[$i]=${COMPREPLY[$i]}/
        done
    fi

    return 0
}

complete -o nospace -F _xyz xyz

1 Символ нового рядка є очевидним винятком тут, оскільки це внутрішній роздільник файлів.


Це чудово (хоча це дуже погано, він не вбудований). Спасибі!
Роб І

1
Будь-яка причина не використовувати "$ 2" замість "$ {COMP_WORDS [COMP_CWORD]}"?
Едвард Фолк

3

Я думаю, що це просте рішення працює в тому, що воно:

  1. Збігає каталоги та файли, які закінчуються .txt
  2. Обробляє пробіли в іменах файлів
  3. Додає косу рису в кінці завершення папки, не маючи місця
  4. Додає пробіл в кінці відповідності файлу

Ключ переходив -o filenamesдо завершення. Це було випробувано на базі GNU 3.2.25 на RHEL 5.3 та GNU bash 4.3.18 на osx

_xyz()
{
  local cur=${COMP_WORDS[COMP_CWORD]}

  local IFS=$'\n'
  COMPREPLY=( $( compgen -o plusdirs  -f -X '!*.txt' -- $cur ) )
}

complete -o filenames -F _xyz xyz

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