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

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

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

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

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

3 ответов


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

  1. этот вызов:

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

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

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

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

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

вот два проверенных фрагмента кода для моделирования из:

>>> 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 is правда обязательно поставить всю команду в одну строку, а не список отдельных полей.


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

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

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

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

grep 'foo12 *.log'