Я пытаюсь реализовать завершение 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-последовательности, когда я понимаю, что массив - это то, что разделяет аргументы, поэтому кажется, что экранирование не нужно. Есть ли полезная функция, которая безопасно удаляет эти побеги, или весь мой подход просто неверен?
-o filenames
имеет побочные эффекты (например, добавление косой черты к именам каталогов или подавление пробелов в конце), так что попробуйте без этой опции. - person pynexj   schedule 13.05.2017-o filenames
, - это то, что я хочу. Спасибо за ссылку на № 3, хотя в этом вопросе было предложение использоватьeval echo $words
, который выполняет работу по отмене экранирования до того, какCOMPREPLY
передаст аргументы внешней программе. Кажется, это исправляет приведенный выше пример, который уже был упрощен, но мне нужно немного больше работы, чтобы выяснить, решает ли он более сложные завершения, которые я пытаюсь реализовать. - person LVA   schedule 14.05.2017