Аргумент командной строки -option после заданного пути - PullRequest
0 голосов
/ 28 апреля 2018

Я новичок в python и в настоящее время экспериментирую с использованием argparse для добавления параметров командной строки. Однако мой код не работает, несмотря на то, что я смотрю на различные онлайн-уроки и читаю на argparse, я до сих пор не до конца его понимаю. Моя проблема заключается в том, что всякий раз, когда я пытаюсь вызвать мой -option, возникает ошибка find.py: аргумент regex:

Вот мой звонок:

./find.py ../Python -name '[0-9]*\.txt'

.. / Python является одним каталогом позади моего текущего и имеет список файлов / каталогов. Без опции -name я распечатываю файлы по их пути (это работает нормально), но с опцией -name я хочу распечатать файлы, соответствующие регулярному выражению, но это не будет работать. Вот что у меня сейчас есть:

#!/usr/bin/python2.7

import os, sys, argparse,re 
from stat import *

def regex_type(s, pattern=re.compile(r"[a-f0-9A-F]")):
   if not pattern.match(s):
      raise argparse.ArgumentTypeError
   return s

def main():
   direc = sys.argv[1]

   for f in os.listdir(direc):
      pathname = os.path.join(direc, f)
      mode = os.stat(pathname).st_mode
      if S_ISREG(mode):
          print pathname

   parser = argparse.ArgumentParser()
   parser.add_argument(
    '-name', default=[sys.stdin], nargs="*")
   parser.add_argument('regex', type=regex_type) 
   args = parser.parse_args()



if __name__ == '__main__': 

      main()

1 Ответ

0 голосов
/ 28 апреля 2018

Я настроил вашу функцию типа для большей информативности:

def regex_type(s, pattern=re.compile(r"[a-f0-9A-F]")):
   print('regex string', s)
   if not pattern.match(s):
      raise argparse.ArgumentTypeError('pattern not match')
   return s

Вызывается с

2104:~/mypy$ python2 stack50072557.py .

Я получаю:

<director list>
('regex string', '.')
usage: stack50072557.py [-h] [-name [NAME [NAME ...]]] regex
stack50072557.py: error: argument regex: pattern not match

Поэтому он пытается передать sys.argv[1], первую строку после имени скрипта, в функцию regex_type. Если это не удается, выдает сообщение об ошибке и использование.

ОК, проблема была ..; Я сделаю каталог:

2108:~/mypy$ mkdir foo
2136:~/mypy$ python2 stack50072557.py foo
('regex string', 'foo')
Namespace(name=[<open file '<stdin>', mode 'r' at 0x7f3bea2370c0>], regex='foo')

2138:~/mypy$ python2 stack50072557.py foo -name a b c
('regex string', 'foo')
Namespace(name=['a', 'b', 'c'], regex='foo')

Строки, следующие за '-name', назначены этому атрибуту. В вашем коде нет ничего, что могло бы их протестировать или передать через функцию regex_type. Только первая строка без флага делает это.

Чтение sys.argv[1] изначально не удаляет его из списка. Это все еще там для использования парсером.

Я бы настроил парсер, который использует аргумент store_true --name и 2 позиционера - один для dir, а другой для regex.

После разбора проверьте args.name. Если false, выведите содержимое args.dir. Если true, выполните фильтр args.regex для этого содержимого. glob может быть полезно.

Парсер узнает, чего хочет ваш пользователь. Ваш собственный код действует на него. Особенно новичку легче и чётче разделить два этапа.


С:

def parse(argv=None):
    parser = argparse.ArgumentParser()
    parser.add_argument('-n', '--name', action='store_true')
    parser.add_argument('--dir', default='.')
    parser.add_argument('--regex', default=r"[a-f0-9A-F]")
    args = parser.parse_args(argv)
    print(args)
    return args

def main(argv=None):
    args = parse(argv)
    dirls = os.listdir(args.dir)
    if args.name:
        dirls = [f for f in dirls if re.match(args.regex, f)]
        print(dirls)
    else:
        print(dirls)

Я получаю пробеги как:

1005:~/mypy$ python stack50072557.py 
Namespace(dir='.', name=False, regex='[a-f0-9A-F]')
['test.npz', 'stack49909128.txt', 'stack49969840.txt', 'stack49824248.py', 'test.h5', 'stack50072557.py', 'stack49963862.npy', 'Mcoo.npz', 'test_attribute.h5', 'stack49969861.py', 'stack49969605.py', 'stack49454474.py', 'Mcsr.npz', 'Mdense.npy', 'stack49859957.txt', 'stack49408644.py', 'Mdok', 'test.mat5', 'stack50012754.py', 'foo', 'test']
1007:~/mypy$ python stack50072557.py -n
Namespace(dir='.', name=True, regex='[a-f0-9A-F]')
['foo']
1007:~/mypy$ python stack50072557.py -n --regex='.*\.txt'
Namespace(dir='.', name=True, regex='.*\\.txt')
['stack49909128.txt', 'stack49969840.txt', 'stack49859957.txt']

и справка:

1007:~/mypy$ python stack50072557.py -h
usage: stack50072557.py [-h] [-n] [--dir DIR] [--regex REGEX]

optional arguments:
  -h, --help     show this help message and exit
  -n, --name
  --dir DIR
  --regex REGEX

Если я изменю строку dir на:

parser.add_argument('dir', default='.')

справка теперь

1553:~/mypy$ python stack50072557.py -h
usage: stack50072557.py [-h] [-n] [--regex REGEX] dir

positional arguments:
  dir

optional arguments:
  -h, --help     show this help message and exit
  -n, --name
  --regex REGEX

и работает:

1704:~/mypy$ python stack50072557.py -n
usage: stack50072557.py [-h] [-n] [--regex REGEX] dir
stack50072557.py: error: too few arguments

1705:~/mypy$ python stack50072557.py . -n
Namespace(dir='.', name=True, regex='[a-f0-9A-F]')
['foo']

1705:~/mypy$ python stack50072557.py ../mypy -n --regex='.*\.txt'
Namespace(dir='../mypy', name=True, regex='.*\\.txt')
['stack49909128.txt', 'stack49969840.txt', 'stack49859957.txt']

Я получаю сообщение об ошибке, потому что теперь для него требуется каталог, даже если это '.'.

Обратите внимание, что скрипт все еще использует:

if __name__ == '__main__': 
    main()

My main загружает dir и применяет фильтр regex к этому списку имен. Мой args.dir заменяет ваш direc.

...