Как argparse (и устаревший optparse) реагирует на нажатие клавиши «tab» после имени программы python в bash?

Я проверил работу optcomplete с модулем optparse. Его пример представляет собой простой файл, поэтому я мог заставить его работать. Я также протестировал его с помощью модуля argparse, так как предыдущий устарел. Но я действительно не понимаю, как и кем вызывается программа python при нажатии табуляции. Я подозреваю, что bash вместе со строкой shebang и модулем argparse (или optparse) каким-то образом задействованы. Я пытался понять это (сейчас прочитаю исходный код).

У меня немного более сложная структура программы, которая включает в себя оболочку вокруг фрагмента кода, обрабатывающего аргументы. Его создание argparse.ArgumentParser() и вызовы add_argument(), которые переклассифицированы в другой промежуточный модуль, чтобы избежать дублирования кода, и вызываемая оболочка, находятся внутри функции.

Я хочу понять, как это завершение табуляции работает между bash и python (или, если уж на то пошло, любым другим интерпретатором, например perl).

ПРИМЕЧАНИЕ. У меня есть четкое представление о завершении bash (которое я узнал только сейчас), и я думаю, что понимаю пользовательское завершение bash (только).

ПРИМЕЧАНИЕ. Я читал другие подобные вопросы SO, и ни один из них не отвечает на этот вопрос.

Изменить: Вот функция bash.
Я уже понял, как модуль python узнает о словах, введенных в командной строке, путем чтения os.environ значений переменных

$COMP_WORDS
$COMP_CWORD
$COMP_LINE
$COMP_POINT
$COMPREPLY

Эти переменные имеют значения только при нажатии табуляции. Мой вопрос в том, как запускается модуль python?


person 0xc0de    schedule 05.03.2012    source источник
comment
В документах optcomplet говорится: вам также необходимо создать функцию Bash, а затем сообщить Bash, чтобы инициировать завершение optcomplete для определенных программ, которые ее используют: Если вы это сделали, почему вы все еще спрашиваете, как это работает? Должно быть очевидно, что вам просто нужно указать bash, какую программу вызывать, если требуется завершение.   -  person Niklas B.    schedule 05.03.2012
comment
Извините, я неправильно понял то, что прочитал. Я добавлю ответ на это.   -  person Niklas B.    schedule 05.03.2012


Ответы (1)


Чтобы понять, что здесь происходит, давайте проверим, что на самом деле делает эта функция bash:

COMPREPLY=( $( \
    COMP_LINE=$COMP_LINE  COMP_POINT=$COMP_POINT \
    COMP_WORDS="${COMP_WORDS[*]}"  COMP_CWORD=$COMP_CWORD \
    OPTPARSE_AUTO_COMPLETE=1 $1 ) )

Видите $1 в конце? Это означает, что он фактически вызывает файл Python, который мы хотим выполнить, с установленными специальными переменными среды! Чтобы проследить, что происходит, давайте подготовим небольшой скрипт для перехвата того, что делает optcomplete.autocomplete:

#!/usr/bin/env python2
import os, sys
import optparse, optcomplete
from cStringIO import StringIO

if __name__ == '__main__':    
    parser = optparse.OptionParser()

    parser.add_option('-s', '--simple', action='store_true',
                      help="Simple really simple option without argument.")

    parser.add_option('-o', '--output', action='store',
                      help="Option that requires an argument.")

    opt = parser.add_option('-p', '--script', action='store',
                            help="Option that takes python scripts args only.")
    opt.completer = optcomplete.RegexCompleter('.*\.py')

    # debug env variables
    sys.stderr.write("\ncalled with args: %s\n" % repr(sys.argv))
    for k, v in sorted(os.environ.iteritems()):
        sys.stderr.write("  %s: %s\n" % (k, v))

    # setup capturing the actions of `optcomplete.autocomplete`
    def fake_exit(i):
      sys.stderr.write("autocomplete tried to exit with status %d\n" % i)
    sys.stdout = StringIO()
    sys.exit = fake_exit

    # Support completion for the command-line of this script.
    optcomplete.autocomplete(parser, ['.*\.tar.*'])

    sys.stderr.write("autocomplete tried to write to STDOUT:\n")
    sys.stderr.write(sys.stdout.getvalue())
    sys.stderr.write("\n")

    opts, args = parser.parse_args()

Это дает нам следующее, когда мы пытаемся автозаполнить его:

$ ./test.py [tab]
called with args: ['./test.py']
  ...
  COMP_CWORD: 1
  COMP_LINE: ./test.py 
  COMP_POINT: 10
  COMP_WORDS: ./test.py 
  ...
  OPTPARSE_AUTO_COMPLETE: 1
  ...
autocomplete tried to exit with status 1
autocomplete tried to write to STDOUT:
-o -h -s -p --script --simple --help --output

Итак, optcomplete.autocomplete просто читает среду, подготавливает совпадения, записывает их в STDOUT и завершает работу. Результат -o -h -s -p --script --simple --help --output затем помещается в массив bash (COMPREPLY=( ... )) и возвращается в bash, чтобы предоставить выбор пользователю. Без магии :)

person Niklas B.    schedule 05.03.2012
comment
Эй, большое спасибо, на самом деле я заметил, что $ 1, когда я прочитал ваш комментарий и зашел на страницу, чтобы получить ссылку. Затем меня поразило то, что я уже знал, но никогда не использовал, поскольку я никогда не писал скриптов bash — $1 — это первый аргумент.- :S. Глупо было с моей стороны, что я не понял этого раньше. - person 0xc0de; 05.03.2012