Как выполнить программу или вызвать системную команду из Python

Как вызвать внешнюю команду (как если бы я набрал ее в оболочке Unix или в командной строке Windows) из сценария Python?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
5 201
0
3 620 194
62
Перейти к ответу Данный вопрос помечен как решенный

Ответы 62

import os
os.system("your command")

Обратите внимание, что это опасно, поскольку команда не очищается. Я оставляю на ваше усмотрение поиск в Google соответствующей документации по модулям 'os' и 'sys'. Есть несколько функций (exec * и spawn *), которые будут делать похожие вещи.

Понятия не имею, что я имел в виду почти десять лет назад (проверьте дату!), Но если бы я должен был догадаться, это было бы так, что не было сделано никакой проверки.

nimish 06.06.2018 19:01

Теперь это должно указывать на subprocess как на более универсальное и портативное решение. Выполнение внешних команд, конечно, по своей сути непереносимо (вы должны убедиться, что команда доступна для каждой архитектуры, которую вам нужно поддерживать), а передача пользовательского ввода в качестве внешней команды по своей сути небезопасна.

tripleee 03.12.2018 08:11

Обратите внимание на временную метку этого парня: «правильный» ответ имеет 40-кратное количество голосов и является ответом №1.

nimish 03.12.2018 21:41

Единственное решение, которое сработало для меня для работы с NodeJS.

Nikolay Shindarov 29.10.2019 23:49

import os
cmd = 'ls -al'
os.system(cmd)

Если вы хотите вернуть результаты команды, вы можете использовать os.popen. Однако это устарело с версии 2.6 в пользу модуль подпроцесса, что хорошо покрыто другими ответами.

popen не рекомендуется в пользу подпроцесс.

Tris - archived 08.08.2014 04:22

Вы также можете сохранить свой результат с помощью вызова os.system, поскольку он работает как сама оболочка UNIX, например, os.system ('ls -l> test2.txt')

Stefan Gruenwald 08.11.2017 02:19
Ответ принят как подходящий

Используйте модуль subprocess в стандартной библиотеке:

import subprocess
subprocess.run(["ls", "-l"])

Преимущество subprocess.run перед os.system в том, что он более гибкий (вы можете получить stdout, stderr, "настоящий" код статуса, лучше обработка ошибок и т. д.).

Даже документация для os.system рекомендует вместо этого использовать subprocess:

The subprocess module provides more powerful facilities for spawning new processes and retrieving their results; using that module is preferable to using this function. See the Replacing Older Functions with the subprocess Module section in the subprocess documentation for some helpful recipes.

В Python 3.4 и более ранних версиях используйте subprocess.call вместо .run:

subprocess.call(["ls", "-l"])

Есть ли способ использовать подстановку переменных? IE Я попытался сделать echo $PATH с помощью call(["echo", "$PATH"]), но он просто повторил буквальную строку $PATH вместо выполнения какой-либо замены. Я знаю, что могу получить переменную среды PATH, но мне интересно, есть ли простой способ заставить команду вести себя точно так, как если бы я выполнил ее в bash.

Kevin Wheeler 02.09.2015 02:17

@KevinWheeler Для этого вам нужно использовать shell=True.

SethMMorton 02.09.2015 23:38

@KevinWheeler Вы НЕ должны использовать shell=True, для этой цели Python поставляется с os.path.expandvars. В вашем случае вы можете написать: os.path.expandvars("$PATH"). @SethMMorton, пожалуйста, пересмотрите свой комментарий -> Почему бы не использовать shell = True

Murmel 11.11.2015 23:24

блокирует вызов? то есть, если я хочу запустить несколько команд в цикле for, как мне это сделать, чтобы он не блокировал мой скрипт python? Меня не волнует вывод команды, я просто хочу запустить их много.

Charlie Parker 24.10.2017 22:07

Если вы хотите создать список из команды с параметрами, список, который можно использовать с subprocess, когда shell=False, тогда используйте shlex.split для простого способа сделать это docs.python.org/2/library/shlex.html#shlex.split

Daniel F 20.09.2018 21:05

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

Daniel F 20.09.2018 21:15

@CharlieParker: блоки call, check_call, check_output и run. Если вы хотите неблокировать, используйте subprocess.Popen.

Lie Ryan 03.12.2018 16:44

Вы также можете передать строку вместо списка строк: subprocess.run("ls -l")

tuket 23.09.2019 17:33

Если они хотят назвать его run вместо call, почему бы просто не сделать его псевдонимом? Некоторые типы обратной совместимости трудны и позволяют продолжить работу подверженных ошибкам шаблонов, но создание run == call легко, просто и почти не требует затрат. Почему call для версий Python до 3.5 вместо новых и старых версий?

Samuel Muldoon 07.11.2019 07:28

@SamuelMuldoon Проблема в том, что subprocess.call имеет совершенно другую семантику, чем subprocess.run. subprocess.call все еще существует в Python 3.5–3.8 (для обратной совместимости), просто, если он у вас есть, subprocess.run безусловно лучше.

FeRD 08.11.2019 15:54

Я пытаюсь использовать эту команду для запуска команд excalibur с python для подключения к локальному хосту, но это не работает, я получаю FileNotFoundError. import subprocess subprocess.run(["excalibur initdb", "excalibur webserver"])

Chacho Fuva 01.05.2020 23:26

@ChachoFuva список, который вы передаете subprocess.run, представляет собой список слов, представляющих 1 команду, а не список команд. Это должно быть subprocess.run(["excalibur", "initdb"]), затем subprocess.run(["excalibur", "webserver"])

Boris 17.11.2020 21:35

Любое значение в создании нового потока с помощью subprocess.run () и при условии, что исходный поток убивает его, если он превышает некоторый тайм-аут?

grambo 23.12.2020 23:12

Я бы рекомендовал использовать модуль подпроцесс вместо os.system, потому что он выполняет экранирование оболочки за вас и, следовательно, намного безопаснее.

subprocess.call(['ping', 'localhost'])

Если вы хотите создать список из команды с параметрами, список, который можно использовать с subprocess, когда shell=False, тогда используйте shlex.split для простого способа сделать это docs.python.org/2/library/shlex.html#shlex.split (это рекомендуемый способ в соответствии с документами docs.python.org/2/library/subprocess.html#popen-constructor)

Daniel F 20.09.2018 21:07

Это неверно: «он убегает за вас и поэтому намного безопаснее». subprocess не выполняет экранирование оболочки, подпроцесс не передает вашу команду через оболочку, поэтому нет необходимости в экранировании оболочки.

Lie Ryan 04.12.2018 11:36

Используйте подпроцесс.

... или очень простой командой:

import os
os.system('cat testfile')

os.system в порядке, но немного устарел. Это тоже не очень безопасно. Вместо этого попробуйте subprocess. subprocess не вызывает sh напрямую и поэтому более безопасен, чем os.system.

Получить дополнительную информацию здесь.

Хотя я согласен с общей рекомендацией, subprocess не устраняет всех проблем с безопасностью и имеет собственные неприятные проблемы.

tripleee 03.12.2018 08:36

Вот краткое изложение способов вызова внешних программ, а также преимущества и недостатки каждого из них:

  1. os.system("some_command with args") передает команду и аргументы в оболочку вашей системы. Это хорошо, потому что вы можете одновременно запускать несколько команд таким образом и настраивать каналы и перенаправление ввода / вывода. Например:

    os.system("some_command < input_file | another_command > output_file")  
    

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

  1. stream = os.popen("some_command with args") будет делать то же самое, что и os.system, за исключением того, что он предоставляет вам объект в виде файла, который вы можете использовать для доступа к стандартному вводу / выводу для этого процесса. Есть еще 3 варианта popen, которые обрабатывают ввод-вывод немного по-разному. Если вы передадите все как строку, ваша команда будет передана оболочке; если вы передадите их в виде списка, вам не нужно беспокоиться о том, чтобы от чего-либо уйти. См. документация.

  2. Класс Popen модуля subprocess. Он предназначен для замены os.popen, но имеет недостаток в том, что он немного сложнее из-за того, что он настолько всеобъемлющий. Например, вы бы сказали:

    print subprocess.Popen("echo Hello World", shell=True, stdout=subprocess.PIPE).stdout.read()
    

    вместо:

    print os.popen("echo Hello World").read()
    

    но приятно иметь все параметры в одном унифицированном классе вместо 4 разных функций popen. См. документация.

  3. Функция call из модуля subprocess. По сути, он похож на класс Popen и принимает все те же аргументы, но просто ждет, пока команда завершится, и выдаст вам код возврата. Например:

    return_code = subprocess.call("echo Hello World", shell=True)  
    

    См. документация.

  4. Если вы используете Python 3.5 или новее, вы можете использовать новую функцию subprocess.run, которая очень похожа на приведенную выше, но даже более гибкая и возвращает объект CompletedProcess, когда команда завершает выполнение.

  5. Модуль os также имеет все функции fork / exec / spawn, которые есть в программе на C, но я не рекомендую использовать их напрямую.

Модуль subprocess, вероятно, должен быть тем, что вы используете.

Наконец, имейте в виду, что для всех методов, в которых вы передаете последнюю команду, которая должна выполняться оболочкой в ​​виде строки, вы несете ответственность за ее экранирование. Есть серьезные проблемы с безопасностью, если какой-либо части передаваемой вами строки нельзя полностью доверять. Например, если пользователь вводит некоторую / любую часть строки. Если вы не уверены, используйте эти методы только с константами. Чтобы дать вам представление о последствиях, рассмотрим этот код:

print subprocess.Popen("echo %s " % user_input, stdout=PIPE).stdout.read()

и представьте, что пользователь вводит что-то «моя мама не любила меня && rm -rf /», что может стереть всю файловую систему.

Хороший ответ / объяснение. Как этот ответ оправдывает девиз Python, описанный в этой статье? fastcompany.com/3026446/… «Стилистически Perl и Python имеют разные философии. Самый известный девиз Perl -« Есть более чем один способ сделать это ». Python разработан таким образом, чтобы иметь один очевидный способ сделать это« Кажется, должно быть и наоборот! В Perl я знаю только два способа выполнить команду - с помощью обратного тика или open.

Jean 27.05.2015 00:16

Если вы используете Python 3.5+, используйте subprocess.run(). docs.python.org/3.5/library/subprocess.html#subprocess.run

phoenix 07.10.2015 19:37

Обычно нужно знать, что делается с STDOUT и STDERR дочернего процесса, потому что, если они игнорируются при некоторых (довольно распространенных) условиях, в конечном итоге дочерний процесс выдаст системный вызов для записи в STDOUT (STDERR тоже?) это превысит выходной буфер, предоставленный для процесса ОС, и ОС заставит его блокироваться до тех пор, пока какой-либо процесс не прочитает из этого буфера. Итак, с учетом рекомендуемых в настоящее время способов, subprocess.run(..), что именно означает «По умолчанию это не захватывает stdout или stderr».? А как насчет subprocess.check_output(..) и STDERR?

Evgeni Sergeev 01.06.2016 13:44

какая из команд, которые вы рекомендовали, блокирует мой скрипт? то есть, если я хочу запустить несколько команд в цикле for, как мне это сделать, чтобы он не блокировал мой скрипт python? Меня не волнует вывод команды, я просто хочу запустить их много.

Charlie Parker 24.10.2017 22:08

@phoenix Я не согласен. Ничто не мешает вам использовать os.system в python3 docs.python.org/3/library/os.html#os.system

Qback 08.12.2017 12:27

Возможно, это неправильный путь. Большинству людей нужен только subprocess.run() или его старшие братья и сестры subprocess.check_call() et al. В случаях, когда этого недостаточно, см. subprocess.Popen(). os.popen(), возможно, не следует упоминать вообще или даже после того, как «взломайте свой собственный код fork / exec / spawn».

tripleee 03.12.2018 09:00

Типовая реализация:

import subprocess

p = subprocess.Popen('ls', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line in p.stdout.readlines():
    print line,
retval = p.wait()

Вы можете делать что хотите с данными stdout в трубе. Фактически, вы можете просто опустить эти параметры (stdout= и stderr=), и он будет вести себя как os.system().

.readlines() читает строки все сразу, то есть блокируется до тех пор, пока подпроцесс не завершится (закрывает свой конец канала). Чтобы читать в реальном времени (если нет проблем с буферизацией), вы можете: for line in iter(p.stdout.readline, ''): print line,

jfs 16.11.2012 18:12

Не могли бы вы пояснить, что вы имеете в виду, говоря «если нет проблем с буферизацией»? Если процесс определенно блокируется, вызов подпроцесса также блокируется. То же самое могло произойти и с моим исходным примером. Что еще может случиться с буферизацией?

EmmEff 17.11.2012 17:25

дочерний процесс может использовать блочную буферизацию в неинтерактивном режиме вместо буферизации строк, поэтому p.stdout.readline() (примечание: нет s в конце) не будет видеть никаких данных, пока дочерний процесс не заполнит свой буфер. Если ребенок не производит много данных, результат не будет в реальном времени. См. Вторую причину в В: Почему бы просто не использовать канал (popen ())?. Предусмотрены некоторые обходные пути в этом ответе (pexpect, pty, stdbuf)

jfs 17.11.2012 17:51

проблема с буферизацией имеет значение только в том случае, если вы хотите выводить данные в реальном времени, и не относится к вашему коду, который ничего не печатает, пока не будут получены данные все

jfs 17.11.2012 17:53

Этот ответ был хорош для своего времени, но мы больше не должны рекомендовать Popen для простых задач. Это также без нужды указывает shell=True. Попробуйте один из ответов subprocess.run().

tripleee 03.12.2018 08:39

Здесь есть еще одно отличие, о котором ранее не упоминалось.

subprocess.Popen выполняет <команду> как подпроцесс. В моем случае мне нужно выполнить файл <a>, который должен взаимодействовать с другой программой <b>.

Я попробовал подпроцесс, и выполнение прошло успешно. Однако <b> не смог связаться с <a>. Все нормально, когда оба запускаю с терминала.

Еще один: (ПРИМЕЧАНИЕ: kwrite ведет себя иначе, чем другие приложения. Если вы попробуете описанное ниже с Firefox, результаты будут разными.)

Если вы попробуете os.system("kwrite"), выполнение программы зависнет, пока пользователь не закроет kwrite. Чтобы преодолеть это, я попробовал os.system(konsole -e kwrite). На этот раз программа продолжала работать, но kwrite стал подпроцессом консоли.

Любой запускает kwrite, не являющийся подпроцессом (т.е. в системном мониторе он должен отображаться на крайнем левом краю дерева).

Что вы имеете в виду под "Кто-нибудь запускает kwrite, не являясь подпроцессом"?

Peter Mortensen 03.06.2018 23:14

Некоторые подсказки по отсоединению дочернего процесса от вызывающего (запуск дочернего процесса в фоновом режиме).

Предположим, вы хотите запустить длинную задачу из сценария CGI. То есть дочерний процесс должен жить дольше, чем процесс выполнения сценария CGI.

Классический пример из документации модуля подпроцесса:

import subprocess
import sys

# Some code here

pid = subprocess.Popen([sys.executable, "longtask.py"]) # Call subprocess

# Some more code here

Идея здесь в том, что вы не хотите ждать в строке «call subprocess», пока longtask.py не завершится. Но непонятно, что происходит после строки «еще немного кода» из примера.

Моей целевой платформой была FreeBSD, но разработка велась в Windows, поэтому сначала я столкнулся с проблемой в Windows.

В Windows (Windows XP) родительский процесс не завершится, пока longtask.py не завершит свою работу. Это не то, что вам нужно в сценарии CGI. Проблема не только в Python; в сообществе PHP проблемы те же.

Решение состоит в том, чтобы передать DETACHED_PROCESS Флаг создания процесса в базовую функцию CreateProcess в Windows API. Если вы установили pywin32, вы можете импортировать флаг из модуля win32process, в противном случае вы должны определить его самостоятельно:

DETACHED_PROCESS = 0x00000008

pid = subprocess.Popen([sys.executable, "longtask.py"],
                       creationflags=DETACHED_PROCESS).pid

/ * UPD 2015.10.27 @eryksun в комментарии ниже отмечает, что семантически правильный флаг - CREATE_NEW_CONSOLE (0x00000010) * /

В FreeBSD у нас есть еще одна проблема: когда родительский процесс завершается, он также завершает дочерние процессы. И это не то, что вам нужно в сценарии CGI. Некоторые эксперименты показали, что проблема заключалась в совместном использовании sys.stdout. И рабочее решение было таким:

pid = subprocess.Popen([sys.executable, "longtask.py"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)

Я не проверял код на других платформах и не знаю причин такого поведения на FreeBSD. Если кто знает, поделитесь, пожалуйста, своими идеями. Поиск в Google по запуску фоновых процессов в Python пока не проливает света.

Я заметил возможную "причуду" при разработке приложений py2exe в pydev + eclipse. я смог сказать, что основной скрипт не был отсоединен, потому что окно вывода eclipse не закрывалось; даже если сценарий выполняется до конца, он все еще ожидает возврата. но когда я попытался скомпилировать исполняемый файл py2exe, происходит ожидаемое поведение (процессы запускаются как отсоединенные, а затем завершаются). Я не уверен, но имени исполняемого файла больше нет в списке процессов. это работает для всех подходов (os.system ("start *"), os.spawnl с os.P_DETACH, subprocs и т. д.)

maranas 09.04.2010 12:09

Попадание в Windows: несмотря на то, что я создал процесс с помощью DETACHED_PROCESS, когда я убил своего демона Python, все порты, открытые им, не освободились, пока все порожденные процессы не завершились. WScript.Shell решил все мои проблемы. Пример здесь: pastebin.com/xGmuvwSx

Alexey Lebedev 16.04.2012 14:04

вам также может понадобиться флаг CREATE_NEW_PROCESS_GROUP. См. Popen, ожидающий дочернего процесса, даже если непосредственный дочерний процесс завершился

jfs 16.11.2012 18:16

Я вижу, что import subprocess as sp;sp.Popen('calc') не ждет завершения подпроцесса. Кажется, что флаги создания не нужны. Что мне не хватает?

ubershmekel 28.10.2014 00:01

@ubershmekel, я не понимаю, что вы имеете в виду, и у меня нет установки Windows. Если я правильно помню, без флагов вы не можете закрыть экземпляр cmd, из которого вы запустили calc.

newtover 28.10.2014 15:25

Я на Windows 8.1 и calc вроде пережил закрытие python.

ubershmekel 30.10.2014 08:45

Имеет ли значение использование «0x00000008»? Это конкретное значение, которое необходимо использовать, или один из нескольких вариантов?

SuperBiasedMan 05.05.2015 16:13

Следующее неверно: «[o] n windows (win xp), родительский процесс не завершится, пока longtask.py не закончит свою работу». Родительский процесс завершится нормально, но окно консоли (экземпляр conhost.exe) закрывается только при выходе из последнего присоединенного процесса, а потомок, возможно, унаследовал родительскую консоль. Установка DETACHED_PROCESS в creationflags позволяет избежать этого, не позволяя дочернему элементу наследовать или создавать консоль. Если вместо этого вам нужна новая консоль, используйте CREATE_NEW_CONSOLE (0x00000010).

Eryk Sun 27.10.2015 03:27

Я не имел в виду, что выполнение как отдельного процесса некорректно. Тем не менее, вам может потребоваться установить стандартные дескрипторы для файлов, каналов или os.devnull, потому что в противном случае некоторые консольные программы завершаются с ошибкой. Создайте новую консоль, если вы хотите, чтобы дочерний процесс взаимодействовал с пользователем одновременно с родительским процессом. Было бы непросто попытаться сделать и то, и другое в одном окне.

Eryk Sun 27.10.2015 20:37

stdout=subprocess.PIPE заставит ваш код зависнуть, если у вас долгий вывод от ребенка. Подробнее см. thraxil.org/users/anders/posts/2008/03/13/….

Dr_Zaszuś 08.03.2018 11:56

нет ли независимого от ОС способа запустить процесс в фоновом режиме?

Charlie Parker 24.02.2019 22:05

мне ваш ответ кажется странным. Я только что открыл subprocess.Popen, и ничего плохого не произошло (не пришлось ждать). Почему именно нам нужно беспокоиться о сценарии, который вы указываете? Я настроен скептически.

Charlie Parker 24.02.2019 22:38

Также проверьте библиотеку Python "pexpect".

Он позволяет интерактивно управлять внешними программами / командами, даже ssh, ftp, telnet и т. д. Вы можете просто ввести что-то вроде:

child = pexpect.spawn('ftp 192.168.0.24')

child.expect('(?i)name .*: ')

child.sendline('anonymous')

child.expect('(?i)password')

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

Если вам нужен вывод команды, которую вы вызываете, тогда вы можете использовать subprocess.check_output (Python 2.7+).

>>> subprocess.check_output(["ls", "-l", "/dev/null"])
'crw-rw-rw- 1 root root 1, 3 Oct 18  2007 /dev/null\n'

Также обратите внимание на параметр ракушка.

If shell is True, the specified command will be executed through the shell. This can be useful if you are using Python primarily for the enhanced control flow it offers over most system shells and still want convenient access to other shell features such as shell pipes, filename wildcards, environment variable expansion, and expansion of ~ to a user’s home directory. However, note that Python itself offers implementations of many shell-like features (in particular, glob, fnmatch, os.walk(), os.path.expandvars(), os.path.expanduser(), and shutil).

Обратите внимание, что check_output требует списка, а не строки. Если вы не полагаетесь на пробелы в кавычках, чтобы сделать ваш вызов действительным, самый простой и читаемый способ сделать это - subprocess.check_output("ls -l /dev/null".split()).

Bruno Bronosky 30.01.2018 21:18

Я всегда использую fabric для таких вещей, как:

from fabric.operations import local
result = local('ls', capture=True)
print "Content:/n%s" % (result, )

Но это хороший инструмент: sh (интерфейс подпроцесса Python).

Взгляните на пример:

from sh import vgdisplay
print vgdisplay()
print vgdisplay('-v')
print vgdisplay(v=True)

os.system не позволяет сохранять результаты, поэтому, если вы хотите сохранить результаты в каком-то списке или чем-то еще, subprocess.call подойдет.

Вы можете использовать Popen, а затем вы можете проверить статус процедуры:

from subprocess import Popen

proc = Popen(['ls', '-l'])
if proc.poll() is None:
    proc.kill()

Проверьте subprocess.Popen.

Самый простой способ запустить любую команду и вернуть результат:

from commands import getstatusoutput

try:
    return getstatusoutput("ls -ltr")
except Exception, e:
    return None

Будет ли это устаревшим в Python 3.0?

719016 04.03.2014 18:16

Действительно, Документация commands из Python 2.7 говорит, что он устарел в версии 2.6 и будет удален в версии 3.0.

tripleee 03.12.2018 08:06

Мне очень нравится shell_command за его простоту. Он построен поверх модуля подпроцесса.

Вот пример из документации:

>>> from shell_command import shell_call
>>> shell_call("ls *.py")
setup.py  shell_command.py  test_shell_command.py
0
>>> shell_call("ls -l *.py")
-rw-r--r-- 1 ncoghlan ncoghlan  391 2011-12-11 12:07 setup.py
-rw-r--r-- 1 ncoghlan ncoghlan 7855 2011-12-11 16:16 shell_command.py
-rwxr-xr-x 1 ncoghlan ncoghlan 8463 2011-12-11 16:17 test_shell_command.py
0

Вот как я запускаю свои команды. В этом коде есть все, что вам нужно в значительной степени

from subprocess import Popen, PIPE
cmd = "ls -l ~/"
p = Popen(cmd , shell=True, stdout=PIPE, stderr=PIPE)
out, err = p.communicate()
print "Return code: ", p.returncode
print out.rstrip(), err.rstrip()

Я думаю, что это приемлемо для жестко запрограммированных команд, если это увеличивает читаемость.

Adam Matan 02.04.2014 17:07

Обновлять:

subprocess.run - это рекомендуемый подход начиная с Python 3.5, если вашему коду не требуется поддерживать совместимость с более ранними версиями Python. Он более последовательный и предлагает ту же простоту использования, что и Envoy. (Однако трубопровод не так прост. См. этот вопрос о том, как.)

Вот несколько примеров из документация.

Запустить процесс:

>>> subprocess.run(["ls", "-l"])  # Doesn't capture output
CompletedProcess(args=['ls', '-l'], returncode=0)

Рейз при неудачном беге:

>>> subprocess.run("exit 1", shell=True, check=True)
Traceback (most recent call last):
  ...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1

Вывод захвата:

>>> subprocess.run(["ls", "-l", "/dev/null"], stdout=subprocess.PIPE)
CompletedProcess(args=['ls', '-l', '/dev/null'], returncode=0,
stdout=b'crw-rw-rw- 1 root root 1, 3 Jan 23 16:23 /dev/null\n')

Оригинальный ответ:

Рекомендую попробовать Посланник. Это оболочка для подпроцесса, которая, в свою очередь, стремится заменить для более старых модулей и функций. Посланник - это подпроцесс для людей.

Пример использования из README:

>>> r = envoy.run('git config', data='data to pipe in', timeout=2)

>>> r.status_code
129
>>> r.std_out
'usage: git config [options]'
>>> r.std_err
''

Трубка тоже:

>>> r = envoy.run('uptime | pbcopy')

>>> r.command
'pbcopy'
>>> r.status_code
0

>>> r.history
[<Response 'uptime'>]

Со стандартной библиотекой

Используйте модуль подпроцесса (Python 3):

import subprocess
subprocess.run(['ls', '-l'])

Это рекомендуемый стандартный способ. Однако создание и написание более сложных задач (конвейеры, вывод, ввод и т. д.) Может быть утомительным.

Примечание по версии Python: если вы все еще используете Python 2, subprocess.call работает аналогичным образом.

Подсказка: shlex.split может помочь вам разобрать команду для run, call и других функций subprocess, если вы не хотите (или не можете!) Предоставлять их в виде списков:

import shlex
import subprocess
subprocess.run(shlex.split('ls -l'))

С внешними зависимостями

Если вы не против внешних зависимостей, используйте отвес:

from plumbum.cmd import ifconfig
print(ifconfig['wlan0']())

Это лучшая обертка subprocess. Он кроссплатформенный, т.е. работает как в Windows, так и в Unix-подобных системах. Установите pip install plumbum.

Еще одна популярная библиотека - ш:

from sh import ifconfig
print(ifconfig('wlan0'))

Однако sh отказался от поддержки Windows, так что это уже не так здорово, как раньше. Установите pip install sh.

Есть много разных способов запуска внешних команд в Python, и у всех есть свои плюсы и минусы.

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

Также существуют разные способы обработки кода возврата и ошибок, и вы можете захотеть проанализировать вывод и предоставить новый ввод (в стиле ожидать). Или вам нужно будет перенаправить stdin, stdout и stderr для запуска на другом tty (например, при использовании screen).

Так что вам, вероятно, придется написать много оболочек вокруг внешней команды. Итак, вот модуль Python, который мы написали, который может обрабатывать почти все, что вам нужно, а если нет, он очень гибкий, поэтому вы можете легко его расширить:

https://github.com/hpcugent/vsc-base/blob/master/lib/vsc/utils/run.py

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

модуль подпроцесса, описанный выше Эли, очень мощный, но синтаксис для выполнения стандартного системного вызова и проверки его вывода излишне многословен.

Самый простой способ сделать системный вызов - использовать модуль команд (только для Linux).

> import commands
> commands.getstatusoutput("grep matter alice-in-wonderland.txt")
(0, "'Then it doesn't matter which way you go,' said the Cat.")

Первый элемент в кортеже - это код возврата процесса. Второй элемент - это стандартный вывод (и стандартная ошибка, объединенная).


Разработчики Python «устарели» модуль команд, но это не значит, что вы не должны его использовать. Только то, что они больше не разрабатывают его, и это нормально, потому что он уже совершенен (в своей маленькой, но важной функции).

Устаревший означает не только «больше не разрабатывается», но и «вам не рекомендуется использовать это». Устаревшие функции могут выйти из строя в любой момент, могут быть удалены в любое время или могут быть опасными. Вы никогда не должны использовать это в важном коде. Устаревание - это просто лучший способ, чем немедленное удаление функции, потому что это дает программистам время адаптироваться и заменить устаревшие функции.

Misch 19.04.2013 12:07

Просто чтобы доказать свою точку зрения: «Не рекомендуется, начиная с версии 2.6: модуль команд был удален в Python 3. Вместо этого используйте модуль подпроцесса».

Misch 19.04.2013 12:14

Это не опасно! Разработчики Python осторожны только в том, чтобы разбивать функции между основными выпусками (то есть между 2.x и 3.x). Я использую модуль команд с Python 2.4 2004 года. То же самое и сегодня работает в Python 2.7.

Colonel Panic 23.04.2013 20:09

Под опасным я не имел в виду, что его можно удалить в любое время (это другая проблема), и я не говорил, что использовать этот конкретный модуль опасно. Однако это может стать опасным, если будет обнаружена уязвимость в системе безопасности, но модуль не будет развиваться и не поддерживается. (Я не хочу сказать, что этот модуль уязвим или не уязвим для проблем безопасности, просто говорю об устаревших вещах в целом)

Misch 23.04.2013 20:23

Чтобы добавить к обсуждению, если вы включаете использование консоли Python, вы можете вызывать внешние команды из IPython. Находясь в приглашении IPython, вы можете вызывать команды оболочки с помощью префикса «!». Вы также можете комбинировать код Python с оболочкой и назначать вывод сценариев оболочки переменным Python.

Например:

In [9]: mylist = !ls

In [10]: mylist
Out[10]:
['file1',
 'file2',
 'file3',]

После некоторого исследования у меня есть следующий код, который мне очень подходит. Он в основном печатает как stdout, так и stderr в реальном времени.

stdout_result = 1
stderr_result = 1


def stdout_thread(pipe):
    global stdout_result
    while True:
        out = pipe.stdout.read(1)
        stdout_result = pipe.poll()
        if out == '' and stdout_result is not None:
            break

        if out != '':
            sys.stdout.write(out)
            sys.stdout.flush()


def stderr_thread(pipe):
    global stderr_result
    while True:
        err = pipe.stderr.read(1)
        stderr_result = pipe.poll()
        if err == '' and stderr_result is not None:
            break

        if err != '':
            sys.stdout.write(err)
            sys.stdout.flush()


def exec_command(command, cwd=None):
    if cwd is not None:
        print '[' + ' '.join(command) + '] in ' + cwd
    else:
        print '[' + ' '.join(command) + ']'

    p = subprocess.Popen(
        command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd
    )

    out_thread = threading.Thread(name='stdout_thread', target=stdout_thread, args=(p,))
    err_thread = threading.Thread(name='stderr_thread', target=stderr_thread, args=(p,))

    err_thread.start()
    out_thread.start()

    out_thread.join()
    err_thread.join()

    return stdout_result + stderr_result

ваш код может потерять данные, когда подпроцесс завершается, в то время как некоторые данные находятся в буфере. Вместо этого читайте до EOF, см. teed_call ()

jfs 13.07.2015 21:52

Используйте subprocess.call:

from subprocess import call

# Using list
call(["echo", "Hello", "world"])

# Single string argument varies across platforms so better split it
call("echo Hello world".split(" "))

Я обычно использую подпроцесс вместе с шлекс (для обработки экранирования строк в кавычках):

>>> import subprocess, shlex
>>> command = 'ls -l "/your/path/with spaces/"'
>>> call_params = shlex.split(command)
>>> print call_params
["ls", "-l", "/your/path/with spaces/"]
>>> subprocess.call(call_params)

Бесстыдный штекер, я написал для этого библиотеку: P https://github.com/houqp/shell.py

На данный момент это в основном обертка для popen и shlex. Он также поддерживает команды конвейера, поэтому вы можете упростить цепочку команд в Python. Таким образом, вы можете делать такие вещи, как:

ex('echo hello shell.py') | "awk '{print }'"

Простой способ - использовать модуль ОС:

import os
os.system('ls')

В качестве альтернативы вы также можете использовать модуль подпроцесса:

import subprocess
subprocess.check_call('ls')

Если вы хотите, чтобы результат сохранялся в переменной, попробуйте:

import subprocess
r = subprocess.check_output('ls')

Также есть Отвес

>>> from plumbum import local
>>> ls = local["ls"]
>>> ls
LocalCommand(<LocalPath /bin/ls>)
>>> ls()
u'build.py\ndist\ndocs\nLICENSE\nplumbum\nREADME.rst\nsetup.py\ntests\ntodo.txt\n'
>>> notepad = local["c:\windows\notepad.exe"]
>>> notepad()                                   # Notepad window pops up
u''                                             # Notepad window is closed by user, command returns

Использовать:

import os

cmd = 'ls -al'

os.system(cmd)

os - этот модуль обеспечивает переносимый способ использования функций, зависящих от операционной системы.

Для других функций os в документации есть здесь.

он также устарел. использовать подпроцесс

Corey Goldberg 09.12.2015 21:13

Использование функции Popen модуля subprocess Python - самый простой способ запуска команд Linux. В этом случае функция Popen.communicate() выдаст ваши команды. Например

import subprocess

..
process = subprocess.Popen(..)   # Pass command and arguments to the function
stdout, stderr = process.communicate()   # Get command output and error
..

Это уже неверно, и, вероятно, не было, когда был опубликован этот ответ. Вам следует предпочесть subprocess.check_call() и его друзьям, если вам не нужен более низкий уровень управления более сложным Popen(). В последних версиях Python популярной рабочей лошадкой является subprocess.run().

tripleee 03.12.2018 08:30

Вот мои два цента: На мой взгляд, это лучшая практика при работе с внешними командами ...

Это возвращаемые значения из метода execute ...

pass, stdout, stderr = execute(["ls","-la"],"/home/user/desktop")

Это метод выполнения ...

def execute(cmdArray,workingDir):

    stdout = ''
    stderr = ''

    try:
        try:
            process = subprocess.Popen(cmdArray,cwd=workingDir, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=1)
        except OSError:
            return [False, '', 'ERROR : command(' + ' '.join(cmdArray) + ') could not get executed!']

        for line in iter(process.stdout.readline, b''):

            try:
                echoLine = line.decode("utf-8")
            except:
                echoLine = str(line)

            stdout += echoLine

        for line in iter(process.stderr.readline, b''):

            try:
                echoLine = line.decode("utf-8")
            except:
                echoLine = str(line)

            stderr += echoLine

    except (KeyboardInterrupt,SystemExit) as err:
        return [False,'',str(err)]

    process.stdout.close()

    returnCode = process.wait()
    if returnCode != 0 or stderr != '':
        return [False, stdout, stderr]
    else:
        return [True, stdout, stderr]

Потенциал взаимоблокировки: вместо этого используйте метод .communicate

pppery 07.07.2016 05:15

А еще лучше избегать Popen() и использовать API более высокого уровня, который теперь объединен в единую функцию subprocess.run().

tripleee 03.12.2018 08:27

Для Python 3.5+ рекомендуется использовать запустить функцию из модуля подпроцесса. Это возвращает объект CompletedProcess, из которого вы можете легко получить выходные данные, а также код возврата.

from subprocess import PIPE, run

command = ['echo', 'hello']
result = run(command, stdout=PIPE, stderr=PIPE, universal_newlines=True)
print(result.returncode, result.stdout, result.stderr)

ответ с функцией запуска был добавлен в 2015 году. Ты повторил это. Я думаю, это была причина голосования против

Greg Eremeev 11.03.2017 21:27

Я бы порекомендовал следующий метод «запустить», который поможет нам получить STDOUT, STDERR и статус выхода в виде словаря; Вызывающий это может прочитать словарь, возвращаемый методом run, чтобы узнать фактическое состояние процесса.

  def run (cmd):
       print "+ DEBUG exec({0})".format(cmd)
       p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=True)
       (out, err) = p.communicate()
       ret        = p.wait()
       out        = filter(None, out.split('\n'))
       err        = filter(None, err.split('\n'))
       ret        = True if ret == 0 else False
       return dict({'output': out, 'error': err, 'status': ret})
  #end

Это не полностью переопределяет что-то вроде subprocess.run(). Вам особенно следует избегать shell=True, когда это не является строго необходимым.

tripleee 03.12.2018 08:51

В Windows вы можете просто импортировать модуль subprocess и запускать внешние команды, вызывая subprocess.Popen(), subprocess.Popen().communicate() и subprocess.Popen().wait(), как показано ниже:

# Python script to run a command line
import subprocess

def execute(cmd):
    """
        Purpose  : To execute a command and return exit status
        Argument : cmd - command to execute
        Return   : exit_code
    """
    process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    (result, error) = process.communicate()

    rc = process.wait()

    if rc != 0:
        print "Error: failed to execute command:", cmd
        print error
    return result
# def

command = "tasklist | grep python"
print "This process detail: \n", execute(command)

Выход:

This process detail:
python.exe                     604 RDP-Tcp#0                  4      5,660 K

Использовать:

import subprocess

p = subprocess.Popen("df -h", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
print p.split("\n")

Это дает хороший результат, с которым легче работать:

['Filesystem      Size  Used Avail Use% Mounted on',
 '/dev/sda6        32G   21G   11G  67% /',
 'none            4.0K     0  4.0K   0% /sys/fs/cgroup',
 'udev            1.9G  4.0K  1.9G   1% /dev',
 'tmpfs           387M  1.4M  386M   1% /run',
 'none            5.0M     0  5.0M   0% /run/lock',
 'none            1.9G   58M  1.9G   3% /run/shm',
 'none            100M   32K  100M   1% /run/user',
 '/dev/sda5       340G  222G  100G  69% /home',
 '']

Чтобы получить идентификатор сети из OpenStackНейтрон:

#!/usr/bin/python
import os
netid = "nova net-list | awk '/ External / { print  }'"
temp = os.popen(netid).read()  /* Here temp also contains new line (\n) */
networkId = temp.rstrip()
print(networkId)

Выход nova net-list

+--------------------------------------+------------+------+
| ID                                   | Label      | CIDR |
+--------------------------------------+------------+------+
| 431c9014-5b5d-4b51-a357-66020ffbb123 | test1      | None |
| 27a74fcd-37c0-4789-9414-9531b7e3f126 | External   | None |
| 5a2712e9-70dc-4b0e-9281-17e02f4684c9 | management | None |
| 7aa697f5-0e60-4c15-b4cc-9cb659698512 | Internal   | None |
+--------------------------------------+------------+------+

Выход печать (networkId)

27a74fcd-37c0-4789-9414-9531b7e3f126

Не рекомендуется рекомендовать os.popen() в 2016 году. Скрипт Awk можно легко заменить собственным кодом Python.

tripleee 03.12.2018 08:49

Есть много способов вызвать команду.

  • Например:

если and.exe требуется два параметра. В cmd мы можем вызвать sample.exe, используя это: and.exe 2 3, и на экране отображается 5.

Если мы используем сценарий Python для вызова and.exe, мы должны сделать что-то вроде ..

  1. os.system(cmd,...)

    • os.system(("and.exe" + " " + "2" + " " + "3"))
  2. os.popen(cmd,...)

    • os.popen(("and.exe" + " " + "2" + " " + "3"))
  3. subprocess.Popen(cmd,...)
    • subprocess.Popen(("and.exe" + " " + "2" + " " + "3"))

Это слишком сложно, поэтому мы можем объединить cmd с пробелом:

import os
cmd = " ".join(exename,parameters)
os.popen(cmd)

os.popen не следует рекомендовать и, возможно, даже упоминать. В примере subpocess аргументы следует передавать в виде списка, а не объединять их пробелами.

tripleee 03.12.2018 08:25

Вот вызов внешней команды и возврат или печать вывода команды:

Python Подпроцесс check_output подходит для

Run command with arguments and return its output as a byte string.

import subprocess
proc = subprocess.check_output('ipconfig /all')
print proc

Аргумент должен быть правильно токенизирован в список, или вы должны явно передать shell=True. В Python 3.x (где x> 3, я думаю) вы можете получить вывод как правильную строку с universal_newlines=True, и вы, вероятно, захотите переключиться на subproces.run()

tripleee 03.12.2018 08:22

Существует множество различных библиотек, которые позволяют вызывать внешние команды с помощью Python. Для каждой библиотеки я дал описание и показал пример вызова внешней команды. В качестве примера я использовал команду ls -l (перечислить все файлы). Если вы хотите узнать больше о любой из библиотек, я перечислил и связал документацию для каждой из них.

Sources:

These are all the libraries:

Надеюсь, это поможет вам решить, какую библиотеку использовать :)

subprocess

Подпроцесс позволяет вызывать внешние команды и подключать их к их каналам ввода / вывода / ошибок (stdin, stdout и stderr). Подпроцесс - это выбор по умолчанию для выполнения команд, но иногда лучше подходят другие модули.

subprocess.run(["ls", "-l"]) # Run command
subprocess.run(["ls", "-l"], stdout=subprocess.PIPE) # This will run the command and return any output
subprocess.run(shlex.split("ls -l")) # You can also use the shlex library to split the command

os

os используется для «функциональности, зависящей от операционной системы». Его также можно использовать для вызова внешних команд с помощью os.system и os.popen (Примечание: существует также subprocess.popen). os всегда будет запускать оболочку и является простой альтернативой для людей, которым это не нужно или которые не знают, как использовать subprocess.run.

os.system("ls -l") # run command
os.popen("ls -l").read() # This will run the command and return any output

sh

sh - это интерфейс подпроцесса, который позволяет вам вызывать программы, как если бы они были функциями. Это полезно, если вы хотите запускать команду несколько раз.

sh.ls("-l") # Run command normally
ls_cmd = sh.Command("ls") # Save command as a variable
ls_cmd() # Run command as if it were a function

plumbum

plumbum - это библиотека для "скриптовых" программ Python. Вы можете вызывать программы как функции, как в sh. Plumbum полезен, если вы хотите запустить конвейер без оболочки.

ls_cmd = plumbum.local("ls -l") # get command
ls_cmd() # run command

pexpect

pexpect позволяет создавать дочерние приложения, управлять ими и находить закономерности в их выводе. Это лучшая альтернатива подпроцессу для команд, ожидающих tty в Unix.

pexpect.run("ls -l") # Run command as normal
child = pexpect.spawn('scp foo [email protected]:.') # Spawns child application
child.expect('Password:') # When this is the output
child.sendline('mypassword')

fabric

fabric - это библиотека Python 2.5 и 2.7. Он позволяет выполнять локальные и удаленные команды оболочки. Fabric - простая альтернатива для запуска команд в защищенной оболочке (SSH).

fabric.operations.local('ls -l') # Run command as normal
fabric.operations.local('ls -l', capture = True) # Run command and receive output

envoy

envoy известен как «подпроцесс для людей». Он используется как удобная оболочка для модуля subprocess.

r = envoy.run("ls -l") # Run command
r.std_out # get output

commands

commands содержит функции оболочки для os.popen, но он был удален из Python 3, поскольку subprocess - лучшая альтернатива.

Редактирование было основано на комментарии Дж. Ф. Себастьяна.

В Linux, если вы хотите вызвать внешнюю команду, которая будет выполняться независимо (будет продолжать работать после завершения скрипта python), вы можете использовать простую очередь как диспетчер очереди задач или команду в

Пример с диспетчером очереди задач:

import os
os.system('ts <your-command>')

Примечания о диспетчере очереди задач (ts):

  1. Вы можете установить количество одновременно запускаемых процессов ("слотов") с помощью:

    ts -S <number-of-slots>

  2. Для установки ts не требуются права администратора. Вы можете загрузить и скомпилировать его из исходников с помощью простого make, добавить его в свой путь, и все готово.

ts не является стандартом ни в одном известном мне дистрибутиве, хотя указатель на at в некоторой степени полезен. Вы, наверное, также должны упомянуть batch. Как и везде, в рекомендации os.system(), вероятно, следует хотя бы упомянуть, что subprocess является рекомендуемой заменой.

tripleee 03.12.2018 08:43

Calling an external command in Python

Просто используйте subprocess.run, который возвращает объект CompletedProcess:

>>> import subprocess
>>> completed_process = subprocess.run('python --version')
Python 3.6.1 :: Anaconda 4.4.0 (64-bit)
>>> completed_process
CompletedProcess(args='python --version', returncode=0)

Почему?

Начиная с Python 3.5, в документации рекомендуется subprocess.run:

The recommended approach to invoking subprocesses is to use the run() function for all use cases it can handle. For more advanced use cases, the underlying Popen interface can be used directly.

Вот пример простейшего возможного использования - и он работает именно так:

>>> import subprocess
>>> completed_process = subprocess.run('python --version')
Python 3.6.1 :: Anaconda 4.4.0 (64-bit)
>>> completed_process
CompletedProcess(args='python --version', returncode=0)

run ожидает успешного завершения команды, а затем возвращает объект CompletedProcess. Вместо этого он может поднять TimeoutExpired (если вы дадите ему аргумент timeout=) или CalledProcessError (если он не работает и вы передаете check=True).

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

Мы можем проверить возвращенный объект и увидеть заданную команду и код возврата:

>>> completed_process.args
'python --version'
>>> completed_process.returncode
0

Захват вывода

Если вы хотите захватить вывод, вы можете передать subprocess.PIPE соответствующему stderr или stdout:

>>> cp = subprocess.run('python --version', 
                        stderr=subprocess.PIPE, 
                        stdout=subprocess.PIPE)
>>> cp.stderr
b'Python 3.6.1 :: Anaconda 4.4.0 (64-bit)\r\n'
>>> cp.stdout
b''

(Мне кажется интересным и немного противоречащим интуиции, что информация о версии помещается в stderr вместо stdout.)

Передайте список команд

Можно легко перейти от предоставления командной строки вручную (как предполагает вопрос) к предоставлению строки, созданной программно. Не создавайте строки программно. Это потенциальная проблема безопасности. Лучше предположить, что вы не доверяете вводимым данным.

>>> import textwrap
>>> args = ['python', textwrap.__file__]
>>> cp = subprocess.run(args, stdout=subprocess.PIPE)
>>> cp.stdout
b'Hello there.\r\n  This is indented.\r\n'

Обратите внимание: только args следует передавать позиционно.

Полная подпись

Вот фактическая подпись в источнике и как показано help(run):

def run(*popenargs, input=None, timeout=None, check=False, **kwargs):

popenargs и kwargs передаются конструктору Popen. input может быть строкой байтов (или Unicode, если указать кодировку или universal_newlines=True), которые будут переданы на стандартный ввод подпроцесса.

Документация описывает timeout= и check=True лучше, чем я мог бы:

The timeout argument is passed to Popen.communicate(). If the timeout expires, the child process will be killed and waited for. The TimeoutExpired exception will be re-raised after the child process has terminated.

If check is true, and the process exits with a non-zero exit code, a CalledProcessError exception will be raised. Attributes of that exception hold the arguments, the exit code, and stdout and stderr if they were captured.

и этот пример для check=True лучше, чем тот, который я мог придумать:

>>> subprocess.run("exit 1", shell=True, check=True)
Traceback (most recent call last):
  ...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1

Расширенная подпись

Вот расширенная подпись, как указано в документации:

subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, 
shell=False, cwd=None, timeout=None, check=False, encoding=None, 
errors=None)

Обратите внимание, что это означает, что позиционно следует передавать только список аргументов. Поэтому передайте оставшиеся аргументы как аргументы ключевого слова.

Popen

Когда вместо этого использовать Popen? Я бы изо всех сил пытался найти вариант использования, основанный только на аргументах. Однако прямое использование Popen предоставит вам доступ к его методам, включая poll, send_signal, terminate и wait.

Вот подпись Popen, как указано в источник. Я думаю, что это наиболее точная инкапсуляция информации (в отличие от help(Popen)):

def __init__(self, args, bufsize=-1, executable=None,
             stdin=None, stdout=None, stderr=None,
             preexec_fn=None, close_fds=_PLATFORM_DEFAULT_CLOSE_FDS,
             shell=False, cwd=None, env=None, universal_newlines=False,
             startupinfo=None, creationflags=0,
             restore_signals=True, start_new_session=False,
             pass_fds=(), *, encoding=None, errors=None):

Но информативнее документация Popen:

subprocess.Popen(args, bufsize=-1, executable=None, stdin=None,
                 stdout=None, stderr=None, preexec_fn=None, close_fds=True,
                 shell=False, cwd=None, env=None, universal_newlines=False,
                 startupinfo=None, creationflags=0, restore_signals=True,
                 start_new_session=False, pass_fds=(), *, encoding=None, errors=None)

Execute a child program in a new process. On POSIX, the class uses os.execvp()-like behavior to execute the child program. On Windows, the class uses the Windows CreateProcess() function. The arguments to Popen are as follows.

Понимание остальной документации по Popen будет оставлено читателю в качестве упражнения.

Здесь можно найти простой пример двусторонней связи между первичным процессом и подпроцессом: stackoverflow.com/a/52841475/1349673

James Hirschorn 16.10.2018 21:05

В первом примере, вероятно, должен быть shell=True или (что еще лучше) передать команду в виде списка.

tripleee 03.12.2018 08:16

Я написал оболочку для обработки ошибок, перенаправления вывода и прочего.

import shlex
import psutil
import subprocess

def call_cmd(cmd, stdout=sys.stdout, quiet=False, shell=False, raise_exceptions=True, use_shlex=True, timeout=None):
    """Exec command by command line like 'ln -ls "/var/log"'
    """
    if not quiet:
        print("Run %s", str(cmd))
    if use_shlex and isinstance(cmd, (str, unicode)):
        cmd = shlex.split(cmd)
    if timeout is None:
        process = subprocess.Popen(cmd, stdout=stdout, stderr=sys.stderr, shell=shell)
        retcode = process.wait()
    else:
        process = subprocess.Popen(cmd, stdout=stdout, stderr=sys.stderr, shell=shell)
        p = psutil.Process(process.pid)
        finish, alive = psutil.wait_procs([p], timeout)
        if len(alive) > 0:
            ps = p.children()
            ps.insert(0, p)
            print('waiting for timeout again due to child process check')
            finish, alive = psutil.wait_procs(ps, 0)
        if len(alive) > 0:
            print('process {} will be killed'.format([p.pid for p in alive]))
            for p in alive:
                p.kill()
            if raise_exceptions:
                print('External program timeout at {} {}'.format(timeout, cmd))
                raise CalledProcessTimeout(1, cmd)
        retcode = process.wait()
    if retcode and raise_exceptions:
        print("External program failed %s", str(cmd))
        raise subprocess.CalledProcessError(retcode, cmd)

Вы можете назвать это так:

cmd = 'ln -ls "/var/log"'
stdout = 'out.txt'
call_cmd(cmd, stdout)

В качестве примера (в Linux):

import subprocess
subprocess.run('mkdir test.dir', shell=True)

Это создает test.dir в текущем каталоге. Обратите внимание, что это тоже работает:

import subprocess
subprocess.call('mkdir test.dir', shell=True)

Эквивалентный код с использованием os.system:

import os
os.system('mkdir test.dir')

Лучшей практикой было бы использовать subprocess вместо os, при этом .run предпочтительнее .call. Все, что вам нужно знать о подпроцессе, - это здесь. Также обратите внимание, что вся документация Python доступна для загрузки с здесь. Я скачал PDF в формате .zip. Я упоминаю об этом, потому что есть хороший обзор модуля os в tutorial.pdf (стр. 81). Кроме того, это авторитетный ресурс для программистов Python.

Согласно docs.python.org/2/library/…, "shell = True" может вызвать проблемы с безопасностью.

Nick Predey 20.03.2018 21:54

@Nick Predley: отмечено, но "shell = False" не выполняет желаемую функцию. В чем конкретно заключаются проблемы безопасности и какая альтернатива? Пожалуйста, дайте мне знать как можно скорее: я не хочу публиковать что-либо, что может вызвать проблемы у всех, кто это просматривает.

user8468899 21.03.2018 22:49

Основное предупреждение находится в документации, но этот вопрос объясняет его более подробно: stackoverflow.com/questions/3172470/…

tripleee 03.12.2018 08:14

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

Это выходит, если процесс выполняется с использованием poll () в процессе.

import subprocess,sys

def exec_long_running_proc(command, args):
    cmd = "{} {}".format(command, " ".join(str(arg) if ' ' not in arg else arg.replace(' ','\ ') for arg in args))
    print(cmd)
    process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

    # Poll process for new output until finished
    while True:
        nextline = process.stdout.readline().decode('UTF-8')
        if nextline == '' and process.poll() is not None:
            break
        sys.stdout.write(nextline)
        sys.stdout.flush()

    output = process.communicate()[0]
    exitCode = process.returncode

    if (exitCode == 0):
        return output
    else:
        raise Exception(command, exitCode, output)

Вы можете вызвать его так:

exec_long_running_proc(command = "hive", args=["-f", hql_path])

Вы получите неожиданные результаты, передав аргумент с пробелом. Использование repr(arg) вместо str(arg) может помочь по простому совпадению, поскольку python и sh экранируют кавычки одинаково

sbk 17.05.2018 15:08

@sbk repr(arg) действительно не помог, приведенный выше код также обрабатывает пробелы. Сейчас работает следующая exec_long_running_proc(command = "ls", args=["-l", "~/test file*"])

am5 17.11.2018 03:07

Вызов внешней команды в Python

Простой способ вызвать внешнюю команду - использовать os.system(...). И эта функция возвращает значение выхода команды. Но недостаток в том, что мы не получим stdout и stderr.

ret = os.system('some_cmd.sh')
if ret != 0 :
    print 'some_cmd.sh execution returned failure'

Вызов внешней команды в Python в фоновом режиме

subprocess.Popen обеспечивает большую гибкость для запуска внешней команды, чем использование os.system. Мы можем запустить команду в фоновом режиме и дождаться ее завершения. И после этого мы можем получить stdout и stderr.

proc = subprocess.Popen(["./some_cmd.sh"], stdout=subprocess.PIPE)
print 'waiting for ' + str(proc.pid)
proc.wait()
print 'some_cmd.sh execution finished'
(out, err) = proc.communicate()
print 'some_cmd.sh output : ' + out

Вызов длительной внешней команды в Python в фоновом режиме и остановка через некоторое время

Мы даже можем запустить длительный процесс в фоновом режиме с помощью subprocess.Popen и убить его через некоторое время, как только его задача будет выполнена.

proc = subprocess.Popen(["./some_long_run_cmd.sh"], stdout=subprocess.PIPE)
# Do something else
# Now some_long_run_cmd.sh exeuction is no longer needed, so kill it
os.system('kill -15 ' + str(proc.pid))
print 'Output : ' proc.communicate()[0]

Это может быть так просто:

import os
cmd = "your command"
os.system(cmd)

Это не указывает на недостатки, которые более подробно объясняются в PEP-324. Документация для os.system явно рекомендует избегать этого в пользу subprocess.

tripleee 03.12.2018 08:02

Если вам нужно вызвать команду оболочки из записной книжки Python (например, Юпитер, Zeppelin, Databricks или Google Cloud Datalab), вы можете просто использовать префикс !.

Например,

!ls -ilF

Вызвать - это инструмент и библиотека для выполнения задач Python (2.7 и 3.4+). Он предоставляет чистый высокоуровневый API для запуска команд оболочки.

>>> from invoke import run
>>> cmd = "pip install -r requirements.txt"
>>> result = run(cmd, hide=True, warn=True)
>>> print(result.ok)
True
>>> print(result.stdout.splitlines()[-1])
Successfully installed invocations-0.13.0 pep8-1.5.7 spec-1.3.1

Это отличная библиотека. На днях я пытался объяснить это коллеге, и я описал это так: invoke соответствует subprocess, как requests соответствует urllib3.

user9074332 12.03.2019 05:00

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

https://pypi.org/project/citizenshell/

Его можно установить с помощью

pip install citizenshell

А потом использовали так:

from citizenshell import sh
assert sh("echo Hello World") == "Hello World"

Вы можете отделить stdout от stderr и извлечь код выхода следующим образом:

result = sh(">&2 echo error && echo output && exit 13")
assert result.stdout() == ["output"]
assert result.stderr() == ["error"]
assert result.exit_code() == 13

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

for line in sh("for i in 1 2 3 4; do echo -n 'It is '; date +%H:%M:%S; sleep 1; done", wait=False)
    print ">>>", line + "!"

напечатает строки, поскольку они доступны благодаря wait = False

>>> It is 14:24:52!
>>> It is 14:24:53!
>>> It is 14:24:54!
>>> It is 14:24:55!

Больше примеров можно найти на https://github.com/meuter/citizenshell

Поскольку некоторые ответы были связаны с предыдущими версиями Python или использовали модуль os.system, я публикую этот ответ для таких людей, как я, которые намереваются использовать subprocess в Python 3.5 +. Следующее помогло мне в Linux:

import subprocess

# subprocess.run() returns a completed process object that can be inspected
c = subprocess.run(["ls", "-ltrh"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
print(c.stdout.decode('utf-8'))

Как упомянуто в документация, значения PIPE представляют собой байтовые последовательности, и для их правильного отображения следует рассмотреть возможность декодирования. Для более поздних версий Python text=True и encoding='utf-8' добавлены в kwargs subprocess.run().

Результатом вышеупомянутого кода является:

total 113M
-rwxr-xr-x  1 farzad farzad  307 Jan 15  2018 vpnscript
-rwxrwxr-x  1 farzad farzad  204 Jan 15  2018 ex
drwxrwxr-x  4 farzad farzad 4.0K Jan 22  2018 scripts
.... # Some other lines

Если вы нет и используете пользовательский ввод в командах, вы можете использовать это:

from os import getcwd
from subprocess import check_output
from shlex import quote

def sh(command):
    return check_output(quote(command), shell=True, cwd=getcwd(), universal_newlines=True).strip()

И использовать его как

branch = sh('git rev-parse --abbrev-ref HEAD')

shell=True создаст оболочку, поэтому вы можете использовать pipe и подобные оболочки sh('ps aux | grep python'). Это очень удобно для выполнения жестко запрограммированных команд и обработки их вывода. universal_lines=True гарантирует, что выходные данные возвращаются в виде строки, а не в двоичном формате.

cwd=getcwd() будет следить за тем, чтобы команда запускалась в том же рабочем каталоге, что и интерпретатор. Это удобно для работы команд Git, как в приведенном выше примере имени ветки Git.

Некоторые рецепты

  • свободная память в мегабайтах: sh('free -m').split('\n')[1].split()[1]
  • свободное место на / в процентах sh('df -m /').split('\n')[1].split()[4][0:-1]
  • Загрузка процессора sum(map(float, sh('ps -ef -o pcpu').split('\n')[1:])

Но это небезопасно для ввода пользователем, из документации:

Security Considerations

Unlike some other popen functions, this implementation will never implicitly call a system shell. This means that all characters, including shell metacharacters, can safely be passed to child processes. If the shell is invoked explicitly, via shell=True, it is the application’s responsibility to ensure that all whitespace and metacharacters are quoted appropriately to avoid shell injection vulnerabilities.

When using shell=True, the shlex.quote() function can be used to properly escape whitespace and shell metacharacters in strings that are going to be used to construct shell commands.

Даже при использовании shlex.quote() полезно сохранять небольшую паранойю при использовании пользовательского ввода в командах оболочки. Один из вариантов - использовать жестко запрограммированную команду для получения общего вывода и фильтрации по вводу пользователя. В любом случае использование shell=False гарантирует, что будет выполнен только тот процесс, который вы хотите выполнить, иначе вы получите ошибку No such file or directory.

Также есть некоторое влияние на производительность shell=True, из моих тестов кажется, что он примерно на 20% медленнее, чем shell=False (по умолчанию).

In [50]: timeit("check_output('ls -l'.split(), universal_newlines=True)", number=1000, globals=globals())
Out[50]: 2.6801227919995654

In [51]: timeit("check_output('ls -l', universal_newlines=True, shell=True)", number=1000, globals=globals())
Out[51]: 3.243950183999914

Султан - это недавний пакет, предназначенный для этой цели. Предоставляет некоторые тонкости управления привилегиями пользователей и добавление полезных сообщений об ошибках.

from sultan.api import Sultan

with Sultan.load(sudo=True, hostname = "myserver.com") as sultan:
  sultan.yum("install -y tree").run()

Re "Обеспечивает некоторые тонкости": Вы можете уточнить?

Peter Mortensen 30.11.2019 01:16

Если вы пишете сценарий оболочки Python и в вашей системе установлен IPython, вы можете использовать префикс bang для запуска команды оболочки внутри IPython:

!ls
filelist = !ls

@PeterMortensen Я не думаю, что это работает в DOS, но должно работать в Cygwin.

noɥʇʎԀʎzɐɹƆ 30.11.2019 04:39

Python 3.5+

import subprocess

p = subprocess.run(["ls", "-ltr"], capture_output=True)
print(p.stdout.decode(), p.stderr.decode())

Попробуйте онлайн

import subprocess

p = subprocess.run(["ls", "-ltr"], capture_output=True)
print(p.stdout.decode(), p.stderr.decode())

Попробуйте онлайн

os.popen() - самый простой и безопасный способ выполнить команду. Вы можете выполнить любую команду, которую запускаете в командной строке. Кроме того, вы также сможете захватить вывод команды с помощью os.popen().read().

Сделать это можно так:

import os
output = os.popen('Your Command Here').read()
print (output)

Пример, в котором вы перечисляете все файлы в текущем каталоге:

import os
output = os.popen('ls').read()
print (output)
# Outputs list of files in the directory

БОЛЬШИНСТВО СЛУЧАЕВ:

В большинстве случаев вам понадобится короткий фрагмент кода, подобный этому.:

import subprocess
import shlex

source = "test.txt"
destination = "test_copy.txt"

base = "cp {source} {destination}'"
cmd = base.format(source=source, destination=destination)
subprocess.check_call(shlex.split(cmd))

Это чисто и просто.

subprocess.check_call run command with arguments and wait for command to complete.

shlex.split split the string cmd using shell-like syntax

ОТДЫХ ДЕЛ:

Если это не работает для какой-то конкретной команды, скорее всего, у вас проблема с интерпретаторы командной строки. Операционная система выбрала программу по умолчанию, которая не подходит для вашего типа программы или не смогла найти подходящую в системном пути к исполняемому файлу.

Пример:

Использование оператора перенаправления в системе Unix

input_1 = "input_1.txt"
input_2 = "input_2.txt"
output = "merged.txt"
base_command = "/bin/bash -c 'cat {input} >> {output}'"

base_command.format(input_1, output=output)
subprocess.check_call(shlex.split(base_command))

base_command.format(input_2, output=output)
subprocess.check_call(shlex.split(base_command))

As it is stated in The Zen of Python: Explicit is better than implicit

Итак, если использовать функцию Python> = 3.6, это будет выглядеть примерно так:

import subprocess
import shlex

def run_command(cmd_interpreter: str, command: str) -> None:
    base_command = f"{cmd_interpreter} -c '{command}'"
    subprocess.check_call(shlex.split(base_command)

Существует несколько способов вызова внешней команды из Python. Есть несколько функций и модулей с хорошими вспомогательными функциями, которые могут сделать это действительно легко. Но среди всех рекомендуется модуль Subprocess.

import subprocess as s
s.call(["command.exe","..."])

Функция вызова запустит внешний процесс, передаст некоторые аргументы командной строки и дождется его завершения. Когда он закончится, вы продолжите выполнение. Аргументы в функции Call передаются по списку. Первым аргументом в списке является команда, обычно в форме исполняемого файла, а последующие аргументы в списке - все, что вы хотите передать.

Если вы вызывали процессы из командной строки в окнах, прежде чем вы узнаете, что вам часто нужно заключать аргументы в кавычки. Вам нужно поставить кавычки вокруг него, если есть пробел, тогда есть обратная косая черта и есть некоторые сложные правила, но вы можете избежать всего этого в python, используя модуль subprocess, потому что это список, и каждый элемент известен как отдельный и питон может правильно цитировать для вас.

В конце концов, после списка есть ряд необязательных параметров, один из которых - это оболочка, и если вы установите для оболочки значение true, ваша команда будет запущена, как если бы вы ввели ее в командной строке.

s.call(["command.exe","..."], shell=True)

Это дает вам доступ к таким функциям, как конвейер, вы можете перенаправлять на файлы, вы можете одновременно вызывать несколько команд.

Еще одна вещь, если ваш сценарий полагается на успешное выполнение процесса, тогда вы хотите проверить результат, и результат можно проверить с помощью вспомогательной функции вызова проверки.

s.check_call(...)

Это точно так же, как функция вызова, она принимает те же аргументы, принимает тот же список, вы можете передать любой из дополнительных аргументов, но она будет ждать завершения функций. И если код выхода функции отличен от нуля, это произойдет через исключение в скрипте python.

Наконец, если вам нужен более жесткий контроль, конструктор Popen, который также принадлежит модулю subprocess. Он также принимает те же аргументы, что и функция incall и check_call, но возвращает объект, представляющий запущенный процесс.

p=s.Popen("...")

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

я использую это для 3.6+

import subprocess
def execute(cmd):
    """
        Purpose  : To execute a command and return exit status
        Argument : cmd - command to execute
        Return   : result, exit_code
    """
    process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    (result, error) = process.communicate()
    rc = process.wait()
    if rc != 0:
        print ("Error: failed to execute command: ", cmd)
        print (error.rstrip().decode("utf-8"))
    return result.rstrip().decode("utf-8"), serror.rstrip().decode("utf-8")
# def

Не используйте набор shell=True для запуска команд, он открывает программу для уязвимостей внедрения команд. Вы должны передать команду в виде списка с аргументами cmd=["/bin/echo", "hello word"]. docs.python.org/3/library/…

user5994461 19.04.2020 19:52

Начиная с Python 3.7.0 выпущен 27 июня 2018 г. (https://docs.python.org/3/whatsnew/3.7.html), вы можете достичь желаемого результата самым мощным и в то же время простым способом. Этот ответ призван вкратце показать вам основное резюме различных вариантов. Подробные ответы см. В других.


TL; DR в 2021 году

Большим преимуществом os.system(...) была его простота. subprocess лучше и по-прежнему прост в использовании, особенно с Python 3.5.

import subprocess
subprocess.run("ls -a", shell=True)

Примечание: Это точный ответ на ваш вопрос - выполнение команды

like in a shell


Предпочтительный способ

Если возможно, удалите служебные данные оболочки и запустите команду напрямую (требуется список).

import subprocess
subprocess.run(["help"])
subprocess.run(["ls", "-a"])

Передайте аргументы программы в виде списка. Не включайте экранирование \" для аргументов, содержащих пробелы.


Расширенные варианты использования

Проверка вывода

Следующий код говорит сам за себя:

import subprocess
result = subprocess.run(["ls", "-a"], capture_output=True, text=True)
if "stackoverflow-logo.png" in result.stdout:
    print("You're a fan!")
else:
    print("You're not a fan?")

result.stdout - это обычный программный выход исключая ошибки. Прочтите result.stderr, чтобы получить их.

capture_output=True - включает захват. В противном случае result.stderr и result.stdout будут None. Доступно с Python 3.7.

text=True - удобный аргумент, добавленный в Python 3.7, который преобразует полученные двоичные данные в строки Python, с которыми вы можете легко работать.

Проверка кода возврата

Делать

if result.returncode == 127: print("The program failed for some weird reason")
elif result.returncode == 0: print("The program succeeded")
else: print("The program failed unexpectedly")

Если вы просто хотите проверить, удалось ли выполнить программу (код возврата == 0), а в противном случае выбросить исключение, есть более удобная функция:

result.check_returncode()

Но это Python, поэтому есть еще более удобный аргумент check, который автоматически делает то же самое за вас:

result = subprocess.run(..., check=True)

stderr должен быть внутри stdout

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

result = subprocess.run(..., stderr=subprocess.STDOUT)

Тогда result.stderr будет None, а result.stdout будет содержать все.

используя shell = False со строкой аргумента

shell=False ожидает список аргументов. Однако вы можете самостоятельно разделить строку аргумента с помощью shlex.

import subprocess
import shlex
subprocess.run(shlex.split("ls -a"))

Вот и все.

Общие проблемы

Скорее всего, вы только что начали использовать Python, когда столкнетесь с этим вопросом. Давайте посмотрим на некоторые общие проблемы.

FileNotFoundError: [Errno 2] No such file or directory: 'ls -a': 'ls -a'

Вы запускаете подпроцесс без shell=True. Либо используйте список (["ls", "-a"]), либо установите shell=True.

TypeError: [...] NoneType [...]

Убедитесь, что вы установили capture_output=True.

TypeError: a bytes-like object is required, not [...]

Вы всегда получаете результат в байтах от вашей программы. Если вы хотите работать с ним как с обычной строкой, установите text=True.

subprocess.CalledProcessError: Command '[...]' returned non-zero exit status 1.

Ваша команда не была успешно выполнена. Вы можете отключить проверку кода возврата или проверить действительность вашей программы.

TypeError: init() got an unexpected keyword argument [...]

Скорее всего, вы используете версию Python старше 3.7.0; обновите его до самого последнего доступного. В противном случае в этом сообщении StackOverflow есть другие ответы, показывающие вам более старые альтернативные решения.

Другие вопросы по теме