Как сделать Python скрипт "tab-complete" каталогами в терминале? - PullRequest
2 голосов
/ 13 мая 2019

У меня есть сценарий оболочки, скажем, run.sh, который читает пользовательский ввод с клавиатуры, а затем выполняет некоторые конкретные задачи. По некоторым техническим причинам я перевожу этот скрипт на Python, например, run.py, чтобы достичь той же цели.

В файле run.sh я спрашиваю пользователя о вводе, который обычно является файлом в файловой системе, поэтому я дал возможность «завершить табуляцию», и я достиг этого просто через строку:

read -e -p "Choose a file: " file

Флаг -e выполняет работу по заполнению вкладок пользователями. Например, если текущим каталогом пользователя является project, который следует структуре:

project
-- src
-- shared
   -- lib
   -- imgs
      -- image.png
-- include
-- README.txt

и входной файл image.png они могут действовать следующим образом:

sh<tab>i<tab><tab>

результат будет shared/imgs/image.png.

Теперь, как мне добиться этого внутри скрипта Python? Вы можете поверить, что существует множество связанных вопросов, но я не смог воспроизвести точно такой же результат в run.py.

Что я пробовал до сих пор:

1. Модуль Python os:

import os

os.system("read -e -p 'Choose a file:'")

Выход: sh: 1: read: Illegal option -e

2. Модуль Python subprocess

import subprocess

subprocess.run(['read', '-e', '-p', 'Choose a file'])

Выход:

Traceback (most recent call last):
  File "run.py", line 26, in <module>
    subprocess.run(['read', '-e', '-p', 'Choose a file'])
  File "/usr/lib/python3.7/subprocess.py", line 453, in run
    with Popen(*popenargs, **kwargs) as process:
  File "/usr/lib/python3.7/subprocess.py", line 756, in __init__
    restore_signals, start_new_session)
  File "/usr/lib/python3.7/subprocess.py", line 1499, in _execute_child
    raise child_exception_type(errno_num, err_msg, err_filename)
FileNotFoundError: [Errno 2] No such file or directory: 'read': 'read'

3. Модуль readline Python

import readline

readline.parse_and_bind("tab:complete")
file = input("Choose a file: ")

Кажется, что это почти работает, но есть одна большая проблема: он завершает только файлы в текущем каталоге пользователя. Если пользователь нажимает s<tab>, тогда появляются src и shared, но если они нажимают sh<tab>, каталоги lib и imgs не отображаются.

Я бы хотел какой-нибудь элегантный и простой способ добиться этого, но я уверен, что это может быть немного сложнее, чем ожидалось. Есть ли другие подходы, которые могут решить эту проблему?

1 Ответ

1 голос
/ 13 мая 2019

Установить разумные разделители завершения:

import readline

readline.set_completer_delims(' \t\n=')
readline.parse_and_bind("tab: complete")
option = input("Tab complete a file: ")

По умолчанию readline будет разделять в зависимости от любого из следующих:

>>> import readline
>>> readline.get_completer_delims()
' \t\n`~!@#$%^&*()-=+[{]}\\|;:\'",<>/?'

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...