Я хочу написать функцию, которая будет выполнять команду оболочки и возвращать ее вывод в виде строки , независимо от того, является ли это ошибкой или сообщением об успехе. Я просто хочу получить тот же результат, который я получил бы с командной строкой.
Каким был бы пример кода, который сделал бы такую вещь?
Например:
def run_command(cmd):
# ??????
print run_command('mysqladmin create test -uroot -pmysqladmin12')
# Should output something like:
# mysqladmin: CREATE DATABASE failed; error: 'Can't create database 'test'; database exists'
python
shell
subprocess
Серебряный свет
источник
источник
Ответы:
Ответ на этот вопрос зависит от версии Python, которую вы используете. Самый простой подход - использовать
subprocess.check_output
функцию:check_output
запускает одну программу, которая принимает только аргументы в качестве входных данных. 1 Возвращает результат в точности так, как напечатаноstdout
. Если вам нужно записать входные данныеstdin
, перейдите к разделамrun
илиPopen
. Если вы хотите выполнить сложные команды оболочки, см. Примечаниеshell=True
в конце этого ответа.check_output
Функция работает практически на всех версиях Python - прежнему широко используется (2.7+). 2 Но для более поздних версий это уже не рекомендуемый подход.Современные версии Python (3.5 или выше):
run
Если вы используете Python 3.5 или выше и не нуждаетесь в обратной совместимости , рекомендуется новая
run
функция . Он предоставляет очень общий высокоуровневый API дляsubprocess
модуля. Чтобы получить выходные данные программы, передайтеsubprocess.PIPE
флагstdout
аргументу ключевого слова. Затем получите доступ кstdout
атрибуту возвращенногоCompletedProcess
объекта:Возвращаемое значение является
bytes
объектом, поэтому, если вам нужна правильная строка, она вам понадобитсяdecode
. Предполагая, что вызываемый процесс возвращает строку в кодировке UTF-8:Все это может быть сжато до одной строки:
Если вы хотите передать входные данные процесса
stdin
, передайтеbytes
объект вinput
аргумент ключевого слова:Вы можете фиксировать ошибки, передавая
stderr=subprocess.PIPE
(capture toresult.stderr
) илиstderr=subprocess.STDOUT
(capture toresult.stdout
вместе с обычным выводом). Когда безопасность не имеет значения, вы также можете запускать более сложные команды оболочки, передавая,shell=True
как описано в примечаниях ниже.Это добавляет немного сложности по сравнению со старым способом ведения дел. Но я думаю, что это того стоит: теперь вы можете делать практически все, что вам нужно, с помощью
run
одной функции.Старые версии Python (2.7-3.4):
check_output
Если вы используете более старую версию Python или вам нужна скромная обратная совместимость, вы, вероятно, можете использовать
check_output
функцию, кратко описанную выше. Он был доступен с Python 2.7.Он принимает те же аргументы, что и
Popen
(см. Ниже), и возвращает строку, содержащую выходные данные программы. В начале этого ответа приведен более подробный пример использования. В Python 3.5 и вышеcheck_output
эквивалентно выполнениюrun
сcheck=True
иstdout=PIPE
и возвращению толькоstdout
атрибута.Вы можете перейти
stderr=subprocess.STDOUT
к тому , чтобы сообщения об ошибках включены в возвращенном выходе - но в некоторых версиях Python переходаstderr=subprocess.PIPE
кcheck_output
может привести к тупикам . Когда безопасность не имеет значения, вы также можете запускать более сложные команды оболочки, передавая,shell=True
как описано в примечаниях ниже.Если вам нужно
stderr
передать или передать входные данные процессу,check_output
не справится с задачей. СмотритеPopen
примеры ниже в этом случае.Сложные приложения и устаревшие версии Python (2.6 и ниже):
Popen
Если вам нужна глубокая обратная совместимость, или если вам нужна более сложная функциональность, чем
check_output
предоставляет, вам придется работать непосредственно сPopen
объектами, которые инкапсулируют низкоуровневый API для подпроцессов.Popen
Конструктор принимает либо одну команду без аргументов, или список , содержащий команду в качестве первого элемента, за которым следует любое количество аргументов, каждый из которых в качестве отдельного элемента в списке.shlex.split
может помочь разобрать строки в соответственно отформатированных списках.Popen
объекты также принимают множество различных аргументов для управления процессами ввода-вывода и низкоуровневой конфигурации.Для отправки ввода и захвата вывода,
communicate
почти всегда предпочтительный метод. Как в:Или
Если вы установите
stdin=PIPE
,communicate
также позволяет передавать данные в процесс черезstdin
:Примечание ответ Аарон Холла , который указывает , что на некоторых системах, вам может понадобиться набор
stdout
,stderr
иstdin
всеPIPE
(илиDEVNULL
) , чтобы получить ,communicate
чтобы работать на всех.В некоторых редких случаях вам может потребоваться сложный захват выходных данных в режиме реального времени. Ответ Вартека предлагает дальнейший путь, но методы, отличные от
communicate
тупиковых, если их не использовать осторожно.Как и во всех вышеперечисленных функциях, когда безопасность не имеет значения, вы можете передавать более сложные команды оболочки, передавая их
shell=True
.Ноты
1. Запуск команд оболочки:
shell=True
аргументКак правило, каждый вызов
run
,check_output
илиPopen
конструктор выполняет одну программу . Это означает, что нет причудливых трубок в стиле Баш. Если вы хотите запускать сложные команды оболочки, вы можете передатьshell=True
, что поддерживают все три функции.Однако при этом возникают проблемы с безопасностью . Если вы делаете что-то большее, чем простой сценарий, вам лучше вызывать каждый процесс отдельно и передавать выходные данные каждого из них как входные данные следующему через
Или
Искушение напрямую соединить трубы сильно; сопротивляться этому. В противном случае, вы , вероятно , увидеть тупики или должны сделать Hacky таких вещей , как это .
2. Юникод соображения
check_output
возвращает строку в Python 2, ноbytes
объект в Python 3. Стоит потратить некоторое время на изучение юникода, если вы этого еще не сделали.источник
check_output()
иcommunicate()
вы должны подождать, пока процесс не будет завершен, когдаpoll()
вы получите результат, как он есть. На самом деле зависит, что вам нужно.out
была<class 'bytes'>
для меня типа . Чтобы получить вывод в виде строки, мне пришлось декодировать его перед печатью так:out.decode("utf-8")
shell=True
? Меня устраивает. Вам не нужно,shlex.split
когда вы проходитеshell=True
.shlex.split
для команд без оболочки. Я думаю, что я собираюсь взять это немного, потому что это мутит воду.universal_newlines=True
который позволяет передавать и выводить строки Unicode в кодировке системы по умолчанию. В 3.7 это было переименовано в более разумноеtext=True
.encoding
параметрsubprocess.run
вместо того, чтобы использоватьresult.stdout.decode('utf-8')
, вы можете использоватьsubprocess.run(['ls', '-l'], stdout=subprocess.PIPE, encoding='utf-8')
.Это намного проще, но работает только на Unix (включая Cygwin) и Python2.7.
Возвращает кортеж с (return_value, output).
Для решения, которое работает как в Python2, так и в Python3, используйте
subprocess
вместо этого модуль:источник
Что-то такое:
Обратите внимание, что я перенаправляю stderr в stdout, это может быть не совсем то, что вы хотите, но я также хочу сообщения об ошибках.
Эта функция выдает построчно по мере их поступления (обычно вам нужно подождать, пока подпроцесс завершит работу, чтобы получить выходные данные в целом).
Для вашего случая использование будет:
источник
wait
иcall
функций.PIPE
значениеstdin
и закрыть этот файл, как толькоPopen
вернетесь.retcode
есть0
. Проверка должна бытьif retcode is not None
. Вы не должны давать пустые строки (даже пустая строка, по крайней мере один символ «\ п»):if line: yield line
. Позвонитеp.stdout.close()
в конце..readlines()
не вернется, пока не будет прочитан весь вывод, и поэтому он прерывается для большого вывода, который не помещается в памяти. Также, чтобы избежать пропущенных буферизованных данных после выхода из подпроцесса, должен быть аналогif retcode is not None: yield from p.stdout.readlines(); break
Ответ Вартека не читает все строки, поэтому я сделал версию, которая сделала:
Использование такое же, как принятый ответ:
источник
return iter(p.stdout.readline, b'')
вместо цикла whilep.stdout.readline()
может вернуть непустые ранее буферизованные выходные данные, даже если дочерний процесс уже завершился (p.poll()
не являетсяNone
).Это сложно, но супер просто решение, которое работает во многих ситуациях:
Временный файл (здесь tmp) создается с выводом команды, и вы можете прочитать из него желаемый вывод.
Дополнительное примечание к комментариям: Вы можете удалить файл tmp в случае разовой работы. Если вам нужно сделать это несколько раз, нет необходимости удалять TMP.
источник
mktemp
чтобы заставить его работать в многопоточных ситуациях, я думаюos.remove('tmp')
чтобы он был «без файлов».У меня была та же проблема, но я нашел очень простой способ сделать это:
Надеюсь, это поможет
Примечание: это решение специфично для Python3, так как
subprocess.getoutput()
не работает в Python2источник
Вы можете использовать следующие команды для запуска любой команды оболочки. Я использовал их на Ubuntu.
Примечание. Это устарело с версии Python 2.6. Теперь вы должны использовать
subprocess.Popen
. Ниже приведен примеристочник
os.popen()
устарела в Python 2.6, но не рекомендуется в Python 3.x, поскольку в 3.x она реализована с использованиемsubprocess.Popen()
.Ваш пробег может меняться, я попытался @ senderle прокрутить решение Vartec в Windows на Python 2.6.5, но я получал ошибки, и другие решения не работали. Моя ошибка была:
WindowsError: [Error 6] The handle is invalid
.Я обнаружил, что должен был назначить PIPE для каждого дескриптора, чтобы он возвращал ожидаемый результат - для меня сработало следующее.
и вызовите вот так (
[0]
получает первый элемент кортежаstdout
):Узнав больше, я считаю, что мне нужны эти аргументы конвейера, потому что я работаю над пользовательской системой, которая использует разные дескрипторы, поэтому мне пришлось напрямую контролировать все std.
Чтобы остановить всплывающие окна консоли (с Windows), сделайте это:
источник
DEVNULL
вместо из ,subprocess.PIPE
если не писать / читать из трубы в противном случае вы можете повесить дочерний процесс.У меня была немного другая разновидность той же проблемы со следующими требованиями:
выше ключевого слова yield
Я объединил и подправил предыдущие ответы, чтобы придумать следующее:
Этот код будет выполнен так же, как и предыдущие ответы:
источник
p.poll()
без перерыва между вызовами, мы бы тратили циклы ЦП, вызывая эту функцию миллионы раз. Вместо этого мы «дросселируем» наш цикл, сообщая ОС, что нам не нужно беспокоиться в течение следующей 1/10 секунды, чтобы она могла выполнять другие задачи. (Возможно, что p.poll () также спит, что делает наш оператор сна избыточным).Разделение начальной команды для команды
subprocess
может быть сложным и громоздким.Используйте,
shlex.split()
чтобы помочь себе.Пример команды
git log -n 5 --since "5 years ago" --until "2 year ago"
Код
Без
shlex.split()
кода выглядело бы следующим образомисточник
shlex.split()
это удобно, особенно если вы не знаете, как именно работает цитирование в оболочке; но вручную преобразовать эту строку в список['git', 'log', '-n', '5', '--since', '5 years ago', '--until', '2 year ago']
совсем не сложно, если вы понимаете цитирование.Если вам нужно запустить команду оболочки для нескольких файлов, это помогло мне.
Редактировать: Только что увидел решение Макса Перссона с предложением Дж. Ф. Себастьяна. Ушел вперед и включил это.
источник
Popen
принимает либо строку, но затем вам нужноshell=True
, либо список аргументов, в этом случае вы должны передать['nm', filename]
вместо строки. Последнее предпочтительнее, потому что оболочка добавляет сложности, не предоставляя здесь никакой ценности. Передача строки безshell=True
видимых действий работает в Windows, но это может измениться в любой следующей версии Python.Согласно @senderle, если вы используете Python3.6, как я:
Будет действовать так же, как вы запускаете команду в Bash
источник
check=True, universal_newlines=True
. Другими словами,subprocess.run()
уже делает все, что делает ваш код.Если вы используете
subprocess
модуль python, вы можете обрабатывать STDOUT, STDERR и код возврата команды отдельно. Вы можете увидеть пример полной реализации вызывающей команды. Конечно, вы можете расширить его,try..except
если хотите.Приведенная ниже функция возвращает код STDOUT, STDERR и Return, чтобы вы могли обрабатывать их в другом скрипте.
источник
subprocess.run()
. Не изобретай велосипед.например, execute ('ls -ahl') различает три / четыре возможных возврата и платформы ОС:
функция ниже
источник
Вывод может быть перенаправлен в текстовый файл, а затем прочитать его обратно.
источник
stdout=temp_file
?ecls.exe
кажется, что используется другой инструмент командной строки, поэтому простой способ иногда не работает.просто написал небольшой скрипт bash, чтобы сделать это с помощью curl
https://gist.github.com/harish2704/bfb8abece94893c53ce344548ead8ba5
источник