Я хочу написать функцию, которая выполнит команду оболочки и вернет ее выходные данные в виде строки, независимо от того, является ли это сообщением об ошибке или успешном завершении. Я просто хочу получить тот же результат, который я получил бы с помощью командной строки.
Каким был бы пример кода, который бы делал такую вещь?
check_output запускает единственную программу, которая принимает в качестве входных данных только аргументы.1 Возвращает результат в точности таким, в каком он был напечатан в stdout. Если вам нужно записать входные данные в stdin, переходите к разделам run или Popen. Если вы хотите выполнять сложные команды оболочки, смотрите Примечание к shell=True в конце этого ответа.
Функция check_output работает во всех официально поддерживаемых версиях Python. Но для более поздних версий доступен более гибкий подход.
Современные версии Python (3.5 или выше): run
Если вы используете Python 3.5+ и вам не нужна обратная совместимость, новая run функция рекомендована официальной документацией для большинства задач. Он предоставляет очень общий высокоуровневый API для subprocess модуля. Чтобы получить выходные данные программы, передайте subprocess.PIPE флаг в stdout аргумент ключевого слова. Затем получите доступ к stdout атрибуту возвращаемого CompletedProcess объекта:
Возвращаемое значение является bytes объектом, поэтому, если вам нужна соответствующая строка, вам понадобится decode она. Предполагая, что вызываемый процесс возвращает строку в кодировке UTF-8.:
Если вы хотите передать входные данные процессу stdin, вы можете передать bytes объект в input аргумент ключевого слова:
>>> cmd = ['awk', 'length($0) > 5'] >>> ip = 'foo\nfoofoo\n'.encode('utf-8') >>> result = subprocess.run(cmd, stdout=subprocess.PIPE, input=ip) >>> result.stdout.decode('utf-8') 'foofoo\n'
Вы можете фиксировать ошибки, передавая stderr=subprocess.PIPE (захват в result.stderr) или stderr=subprocess.STDOUT (захват в result.stdout вместе с обычным выводом). Если вы хотите run выдавать исключение, когда процесс возвращает ненулевой код выхода, вы можете передать его check=True. (Или вы можете проверить returncode атрибут result выше.) Когда безопасность не вызывает беспокойства, вы также можете запускать более сложные команды оболочки, передавая shell=True как описано в конце этого ответа.
Более поздние версии Python еще больше упростили вышесказанное. В Python 3.7+ приведенная выше однострочная строка может быть написана следующим образом:
Использование run этого способа добавляет немного сложности по сравнению со старым способом выполнения задач. Но теперь вы можете делать практически все, что вам нужно, с помощью одной только run функции.
Более старые версии Python (3-3.4): подробнее check_output
If you are using an older version of Python, or need modest backwards compatibility, you can use the check_output function as briefly described above. It has been available since Python 2.7.
subprocess.check_output(*popenargs, **kwargs)
It takes takes the same arguments as Popen (see below), and returns a string containing the program's output. The beginning of this answer has a more detailed usage example. In Python 3.5+, check_output is equivalent to executing run with check=True and stdout=PIPE, and returning just the stdout attribute.
You can pass stderr=subprocess.STDOUT to ensure that error messages are included in the returned output. When security is not a concern, you can also run more complex shell commands by passing shell=True as described at the end of this answer.
Если вам нужно выполнить передачу данных из stderr или передать входные данные процессу, check_output это не будет соответствовать задаче. В этом случае смотрите Popen Примеры ниже.
Сложные приложения и устаревшие версии Python (2.6 и ниже): Popen
Если вам нужна глубокая обратная совместимость или если вам нужна более сложная функциональность, чем предоставляет check_output or run, вам придется работать напрямую с Popen объектами, которые инкапсулируют низкоуровневый API для подпроцессов.
Popen Конструктор принимает либо единственную команду без аргументов, либо список, содержащий команду в качестве первого элемента, за которым следует любое количество аргументов, каждый как отдельный элемент в списке. shlex.split может помочь преобразовать строки в списки соответствующего формата. Popenобъекты также принимают множество различных аргументов для управления процессом ввода-вывода и низкоуровневой конфигурации.
Для отправки входных данных и захвата выходных данных communicate почти всегда является предпочтительным методом. Как в:
Обратите внимание на ответ Аарона Холла, который указывает, что в некоторых системах вам может потребоваться установить stdout, stderr и stdin all в PIPE (или DEVNULL), чтобы заставить communicate вообще работать.
В некоторых редких случаях вам может потребоваться сложный захват выходных данных в режиме реального времени. Ответ Vartec предлагает путь вперед, но методы, отличные от communicate, склонны к взаимоблокировкам, если не использовать их осторожно.
Как и во всех вышеперечисленных функциях, когда безопасность не вызывает беспокойства, вы можете запускать более сложные команды оболочки, передавая shell=True.
Примечания
1. Запуск команд оболочки: shell=True аргумент
Обычно каждый вызов run, check_output или Popen конструктора выполняет единственную программу,,,,,,,,,,,. Это означает отсутствие причудливых каналов в стиле bash. Если вы хотите запускать сложные команды оболочки, вы можете передать shell=True, который поддерживают все три функции. Например:
Однако при выполнении этого возникают проблемы безопасности. Если вы делаете что-то большее, чем простые сценарии, возможно, вам было бы лучше вызывать каждый процесс отдельно и передавать выходные данные от каждого в качестве входных данных следующему, через
Соблазн напрямую подключить каналы силен; сопротивляйтесь ему. В противном случае вы, вероятно, столкнетесь с взаимоблокировками или вам придется делать хакерские вещи, подобные этому.
Ответ 2
Это намного проще, но работает только в Unix (включая Cygwin) и Python2.7.
defrunProcess(exe): p = subprocess.Popen(exe, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) while(True): # returns None while subprocess is running retcode = p.poll() line = p.stdout.readline() yield line if retcode isnotNone: break
Обратите внимание, что я перенаправляю stderr на stdout, возможно, это не совсем то, что вы хотите, но мне также нужны сообщения об ошибках.
Эта функция выдает строку за строкой по мере их поступления (обычно вам нужно дождаться завершения подпроцесса, чтобы получить выходные данные в целом).
В вашем случае использование будет:
for line in runProcess('mysqladmin create test -uroot -pmysqladmin12'.split()): print line,