Завершение Bash для имен файлов, доступное только через другую программу

Я пытаюсь реализовать завершение bash для имен файлов, где список имен извлекается другой программой (например, извлекается по сети). У меня это почти работает, но автоматическое экранирование вызывает у меня некоторые проблемы. Приведенный ниже код является самым простым воссозданием проблемы, которую я могу собрать:

#!/bin/bash

_myscript()
{
    local IFS=$'
'

    # Debugging:
    #echo
    #echo "./myscript $COMP_CWORD ${COMP_WORDS[@]}"

    COMPREPLY=( $(./myscript $COMP_CWORD ${COMP_WORDS[@]}) 
}

complete -o filenames -F _myscript myscript

Где программа, которая может фактически получить имена файлов, моделируется этим сценарием с именем файла myscript:

#!/bin/bash

index=$(( $1 + 2 ))
cat matches.txt | fgrep "${!index}"

Упомянутый выше файл matches.txt:

abc
def
ghi=jkl
mnl opq

Таким образом, вкладка правильно завершает все, если вы вводите только первые несколько символов, создавая экранирование, которое я хотел бы:

./myscript 1 ./myscript gh<TAB>    ->    ... ghi\=jkl
./myscript 1 ./myscript mn<TAB>    ->    ... mnl\ opq

Проблема заключается в том, что при нажатии табуляции после равенства или пробела она не завершается:

./myscript 1 ./myscript ghi\=j<TAB>    (no change)
./myscript 1 ./myscript mnl\ o<TAB>    (no change)

Используя отладку, он, кажется, отправляет следующую команду в myscript (кавычки добавлены мной для обозначения группировки только потому, что она не отображается в операторе эха):

./myscript 1 ./myscript 'ghi\=j'
./myscript 1 ./myscript 'mnl\ o'

Это означает, что мой fgrep ищет имя файла, которое на самом деле включает escape-символ. Потребовалось время, чтобы добраться до этого момента, но реальный вопрос заключается в следующем:

Почему он дает мне экранированную версию текста, который я завершаю? Когда я в конце концов нажму кнопку ввода, escape-последовательности будут интерпретированы bash, и myscript их не получит. Таким образом, кажется, есть разница между тем, что я получаю для завершения табуляции, и тем, что я получаю, когда пользователь на самом деле нажимает ввод.

Я действительно не понимаю, почему $COMP_WORDS устанавливается с версией, содержащей escape-последовательности, когда я понимаю, что массив - это то, что разделяет аргументы, поэтому кажется, что экранирование не нужно. Есть ли полезная функция, которая безопасно удаляет эти побеги, или весь мой подход просто неверен?


person LVA    schedule 13.05.2017    source источник
comment
см. вопросы #1, #2, #3   -  person pynexj    schedule 13.05.2017
comment
-o filenames имеет побочные эффекты (например, добавление косой черты к именам каталогов или подавление пробелов в конце), так что попробуйте без этой опции.   -  person pynexj    schedule 13.05.2017
comment
Побег, предоставляемый -o filenames, - это то, что я хочу. Спасибо за ссылку на № 3, хотя в этом вопросе было предложение использовать eval echo $words, который выполняет работу по отмене экранирования до того, как COMPREPLY передаст аргументы внешней программе. Кажется, это исправляет приведенный выше пример, который уже был упрощен, но мне нужно немного больше работы, чтобы выяснить, решает ли он более сложные завершения, которые я пытаюсь реализовать.   -  person LVA    schedule 14.05.2017