Подпроцесс Python Grep

Я пытаюсь использовать команду grep в python script с помощью модуля подпроцесса.

Вот что у меня есть:

userid = 'foo12'
p = subprocess.Popen(['grep', "%s *.log"%userid], stdout=subprocess.PIPE)

И он ничего не возвращает. Я не совсем уверен, что я делаю неправильно, поэтому кто-то может объяснить. Текущий метод, который я использую для этого, заключается в добавлении shell = true, который позволяет выводить правильный вывод, но, как указывают страницы справки, он небезопасен. Мне нужна помощь, пытаясь сделать эту работу, чтобы мой script был небезопасным.

Ответ 1

Я думаю, что вы столкнулись с двумя проблемами:

  • Этот вызов:

    p = subprocess.Popen(['grep', "%s *.log"%userid]...
    

    не будет работать так, как ожидалось, без shell=True, потому что список аргументов передается непосредственно на os.execvp, что требует, чтобы каждый элемент представлял собой одну строку, представляющую аргумент. Вы объединили два отдельных аргумента в одну строку (другими словами, grep интерпретирует "foo12 *.log" как шаблон для поиска, а не шаблон + список файлов).

    Вы можете исправить это, сказав:

    p = subprocess.Popen(['grep', userid, '*.log']...)
    
  • Вторая проблема заключается в том, что, опять же без shell=True, execvp не знает, что вы подразумеваете под *.log, и передает его непосредственно в grep, не проходя через механизм расширения подстановочных оболочек. Если вы не хотите использовать shell=True, вы можете сделать что-то вроде:

    import glob
    args = ['grep', userid]
    args.extend(glob.glob('*.log')
    p = subprocess.Popen(args, ...)
    

Ответ 2

Вот два тестируемых фрагмента кода для модели:

>>> print subprocess.check_output(['grep', 'python', 'api_talk.txt'])
Discuss python API patterns
Limitations of python
Introspection in python

>>> print subprocess.check_output('grep python *.txt', shell=True)

Используйте последнее, если вы хотите, чтобы оболочка делала для вас подстановочное расширение. Когда shell имеет значение True, обязательно поместите всю команду в одну строку, а не в список отдельных полей.

Ответ 3

Я предполагаю, что вы хотите grep для 'foo12' во всех файлах, заканчивающихся '.log', чтобы заставить это работать только с subprocess, вам нужно будет изменить свой код на следующее:

userid = 'foo12'
p = subprocess.Popen('grep %s *.log' % userid, stdout=subprocess.PIPE, shell=True)

shell=True необходим для расширения подстановочных знаков, и когда эта опция установлена, вам нужно предоставить строковую команду вместо списка.

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

grep 'foo12 *.log'