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

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

18.09.2008 01:35:30
30 ОТВЕТОВ
РЕШЕНИЕ

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

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

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

Официальная документация рекомендует subprocessмодуль над альтернативой os.system():

subprocessМодуль предоставляет более мощные средства для порождения новых процессов и получения их результатов; использование этого модуля предпочтительнее, чем использование этой функции [ os.system()].

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

Для версий Python до 3.5 используйте call:

import subprocess
subprocess.call(["ls", "-l"])
4622
31.08.2019 03:17:55
Есть ли способ использовать подстановку переменных? IE я пытался сделать echo $PATHс помощью call(["echo", "$PATH"]), но он просто повторил буквальную строку $PATHвместо какой-либо замены. Я знаю, что могу получить переменную среды PATH, но мне интересно, есть ли простой способ заставить команду вести себя точно так же, как если бы я выполнял ее в bash.
Kevin Wheeler 1.09.2015 23:17:07
@KevinWheeler Вы должны использовать shell=Trueэто для работы.
SethMMorton 2.09.2015 20:38:24
@KevinWheeler Вы НЕ должны использовать shell=True, для этого Python поставляется с os.path.expandvars . В вашем случае вы можете написать: os.path.expandvars("$PATH"). @SethMMorton, пожалуйста, пересмотрите свой комментарий -> Почему бы не использовать shell = True
Murmel 11.11.2015 20:24:27
вызывает блок? то есть, если я хочу запустить несколько команд в forцикле, как мне сделать это без блокировки моего скрипта Python? Меня не волнует вывод команды, я просто хочу запустить их много.
Charlie Parker 24.10.2017 19:07:55
Если вы хотите создать список из команды с параметрами , список, который можно использовать с subprocessкогда shell=False, а затем используйте shlex.splitдля простого способа сделать это docs.python.org/2/library/shlex.html#shlex.split
Daniel F 20.09.2018 18:05:59
import os
os.system("your command")

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

148
3.06.2018 17:10:00
Понятия не имею, что я имел в виду почти десять лет назад (проверь дату!), Но если бы мне пришлось угадывать, было бы, что проверка не была сделана.
nimish 6.06.2018 16:01:34
Теперь это должно subprocessбыть несколько более универсальным и портативным решением. Выполнение внешних команд, конечно, по своей природе непереносимо (вы должны убедиться, что команда доступна в каждой архитектуре, которую вам необходимо поддерживать), а передача пользовательского ввода в качестве внешней команды небезопасна.
tripleee 3.12.2018 05:11:39
Обратите внимание на отметку времени этого парня: «правильный» ответ имеет 40х голосов и является ответом № 1.
nimish 3.12.2018 18:41:52
Единственное решение, которое помогло мне запустить NodeJS.
Nikolay Shindarov 29.10.2019 20:49:50
import os
cmd = 'ls -al'
os.system(cmd)

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

141
26.01.2016 16:53:05
popen устарела в пользу подпроцесса .
Fox Wilson 8.08.2014 00:22:35
Вы также можете сохранить свой результат с помощью вызова os.system, поскольку он работает как сама оболочка UNIX, например, os.system ('ls -l> test2.txt')
Stefan Gruenwald 7.11.2017 23:19:20

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

subprocess.call(['ping', 'localhost'])
144
24.02.2020 01:01:46
Если вы хотите создать список из команды с параметрами , список, который можно использовать с 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 18:07:21
Это неверно: « он спасается от оболочки и поэтому намного безопаснее ». подпроцесс не выполняет экранирование оболочки, субпроцесс не передает вашу команду через оболочку, поэтому нет необходимости в экранировании оболочки.
Lie Ryan 4.12.2018 08:36:35

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

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

import os
os.system('cat testfile')
40
29.11.2019 21:39:08

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

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

34
10.12.2016 13:25:05
Хотя я согласен с общей рекомендацией, subprocessон не устраняет все проблемы с безопасностью и имеет некоторые неприятные проблемы.
tripleee 3.12.2018 05:36:59

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

  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 /", что может стереть всю файловую систему.

2963
4.10.2019 02:34:49
Хороший ответ / объяснение. Как этот ответ оправдывает девиз Python, описанный в этой статье? fastcompany.com/3026446/… «Стилистически, Perl и Python имеют разные философии. Самый известный девиз Perl:« Существует больше, чем один способ сделать это ». Python разработан, чтобы иметь один очевидный способ сделать это» Кажется, так и должно быть другой способ! В Perl я знаю только два способа выполнить команду - используя back-tick или open.
Jean 26.05.2015 21:16:27
Если вы используете Python 3.5+, используйте subprocess.run(). docs.python.org/3.5/library/subprocess.html#subprocess.run
phoenix 7.10.2015 16:37:18
Обычно нужно знать, что делается с STDOUT и STDERR дочернего процесса, потому что, если они игнорируются, при некоторых (довольно распространенных) условиях, в конечном итоге дочерний процесс выдаст системный вызов для записи в STDOUT (тоже STDERR?) это превысило бы выходной буфер, предоставленный для процесса ОС, и ОС заставит его заблокировать, пока какой-либо процесс не прочитает из этого буфера. Итак, с помощью рекомендуемых в настоящее время способов, subprocess.run(..)что именно означает «Это не захватывает stdout или stderr по умолчанию». означают? А как насчет subprocess.check_output(..)STDERR?
Evgeni Sergeev 1.06.2016 10:44:53
@ Да, но это не то, что исполняется на примере. Заметьте, что echoперед строкой передано Popen? Так что полная команда будет echo my mama didnt love me && rm -rf /.
Chris Arndt 10.09.2018 16:38:25
Это возможно неправильный путь назад. Большинству людей нужны только subprocess.run()его старшие братья subprocess.check_call()и сестры и соавт. Для случаев, когда этого недостаточно, см subprocess.Popen(). os.popen()возможно, вообще не следует упоминать или даже после "взломать свой собственный код fork / exec / spawn".
tripleee 3.12.2018 06:00:46

Типичная реализация:

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().

349
4.10.2019 02:33:47
.readlines()читает все строки одновременно, т. е. блокируется до выхода из подпроцесса (закрывает свой конец канала). Чтобы читать в режиме реального времени (если нет проблем с буферизацией), вы можете:for line in iter(p.stdout.readline, ''): print line,
jfs 16.11.2012 14:12:18
Не могли бы вы уточнить, что вы подразумеваете под «если нет проблем с буферизацией»? Если процесс блокируется определенным образом, вызов подпроцесса также блокируется. То же самое может случиться и с моим оригинальным примером. Что еще может произойти в отношении буферизации?
EmmEff 17.11.2012 13:25:15
дочерний процесс может использовать буферизацию блоков в неинтерактивном режиме вместо буферизации строк, поэтому p.stdout.readline()(примечание: нет sв конце) не увидит никаких данных, пока дочерний процесс не заполнит свой буфер. Если ребенок не производит много данных, то вывод не будет в реальном времени. Смотрите вторую причину в вопросе: почему бы просто не использовать канал (popen ())? , В этом ответе приведены некоторые обходные пути (pexpect, pty, stdbuf)
jfs 17.11.2012 13:51:25
проблема с буферизацией имеет значение только в том случае, если вы хотите выводить данные в реальном времени и не применяется к коду, который ничего не печатает, пока не будут получены все данные
jfs 17.11.2012 13:53:26
Этот ответ был хорош для своего времени, но мы больше не должны рекомендовать Popenдля простых задач. Это также излишне указывает shell=True. Попробуйте один из subprocess.run()ответов.
tripleee 3.12.2018 05:39:55

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

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

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

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

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

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

23
3.06.2018 20:14:32
Что вы подразумеваете под "Кто-нибудь запускает kwrite, не будучи подпроцессом" ?
Peter Mortensen 3.06.2018 20:14:54

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

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

226
29.11.2019 21:46:11
я заметил возможную «причуду» разработки приложений py2exe в pydev + eclipse. я был в состоянии сказать, что основной сценарий не был отсоединен, потому что окно вывода eclipse не заканчивалось; даже если скрипт выполняется до конца, он все еще ожидает возврата. но, когда я попытался скомпилировать в исполняемый файл py2exe, происходит ожидаемое поведение (запускает процессы как отдельные, а затем завершает работу). Я не уверен, но имя исполняемого файла больше нет в списке процессов. это работает для всех подходов (os.system ("start *"), os.spawnl с os.P_DETACH, подпрограммы и т. д.)
maranas 9.04.2010 08:09:26
jfs 16.11.2012 14:16:42
Неправильно указано следующее: «[o] n windows (win xp), родительский процесс не завершится, пока longtask.py не завершит свою работу». Родитель будет нормально завершать работу, но окно консоли (экземпляр conhost.exe) закрывается только при выходе из последнего присоединенного процесса, и дочерний объект может наследовать консоль родителя. Установка DETACHED_PROCESSв creationflagsизбегаешь этого пути предотвращения ребенка от наследования или создания консоли. Если вы вместо этого хотите новую консоль, используйте CREATE_NEW_CONSOLE(0x00000010).
Eryk Sun 27.10.2015 00:27:30
Я не имел в виду, что выполнение как отдельный процесс некорректно. Тем не менее, вам может потребоваться установить стандартные дескрипторы для файлов, каналов или os.devnullпотому , что некоторые консольные программы выходят с ошибкой в ​​противном случае. Создайте новую консоль, когда вы хотите, чтобы дочерний процесс взаимодействовал с пользователем одновременно с родительским процессом. Было бы странно пытаться сделать оба в одном окне.
Eryk Sun 27.10.2015 17:37:15
не существует ли независимого от ОС способа запуска процесса в фоновом режиме?
Charlie Parker 24.02.2019 19:05:29

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

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

child = pexpect.spawn('ftp 192.168.0.24')

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

child.sendline('anonymous')

child.expect('(?i)password')
72
28.05.2017 23:02:27

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

21
18.01.2011 19:21:44

Если вам нужен вывод команды, которую вы вызываете, вы можете использовать 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'

Также обратите внимание на параметр оболочки .

Если оболочка есть True, указанная команда будет выполнена через оболочку. Это может быть полезно, если вы используете Python в первую очередь для расширенного потока управления, который он предлагает для большинства системных оболочек, и все еще хотите удобный доступ к другим функциям оболочки, таким как каналы оболочки, подстановочные знаки имени файла, расширение переменных среды и расширение ~ до дома пользователя. каталог. Тем не менее, обратите внимание , что сам Python предлагает реализацию многих оболочечной подобные функции (в частности, glob, fnmatch, os.walk(), os.path.expandvars(), os.path.expanduser(), и shutil).

68
3.06.2018 20:18:34
Обратите внимание, что check_outputтребуется список, а не строка. Если вы не полагаетесь на пробелы в кавычках, чтобы сделать ваш вызов действительным, самый простой и читаемый способ сделать это subprocess.check_output("ls -l /dev/null".split()).
Bruno Bronosky 30.01.2018 18:18:54

Я всегда использую 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)
72
29.11.2019 21:47:58

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

21
29.11.2019 21:48:26

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

from subprocess import Popen

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

Проверьте подпроцесс . Открыть .

15
28.05.2017 23:01:49

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

from commands import getstatusoutput

try:
    return getstatusoutput("ls -ltr")
except Exception, e:
    return None
14
3.06.2018 20:25:28
Это будет устаревшим в Python 3.0?
719016 4.03.2014 14:16:18
Действительно, в commandsдокументации Python 2.7 говорится, что она устарела в 2.6 и будет удалена в 3.0.
tripleee 3.12.2018 05:06:54

Мне очень нравится 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
23
29.11.2019 21:49:06

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

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()
55
28.10.2012 05:44:05
Я думаю, что это приемлемо для жестко запрограммированных команд, если это повышает удобочитаемость.
Adam Matan 2.04.2014 13:07:44

Обновить:

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'>]
52
29.11.2019 21:52:33

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

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

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

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

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

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

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

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

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

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

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

Другая популярная библиотека - это sh :

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

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

68
29.11.2019 21:54:25

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

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

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

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

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

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

7
13.12.2019 09:31:51

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

Самый простой способ сделать системный вызов - воспользоваться модулем команд (только для 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 «устарели» как модуль команд, но это не значит, что вы не должны его использовать. Только то, что они его больше не развивают, и это нормально, потому что он уже совершенен (при его небольшой, но важной функции).

2
18.04.2013 17:39:50
Устаревшее означает не только «больше не разрабатывается», но и «вам не рекомендуется использовать это». Устаревшие функции могут быть повреждены в любое время, могут быть удалены в любое время или могут быть опасными. Вы никогда не должны использовать это в важном коде. Устаревание - это просто лучший способ, чем немедленное удаление функции, поскольку она дает программистам время для адаптации и замены устаревших функций.
Misch 19.04.2013 08:07:01
Просто чтобы доказать мою точку зрения: «устарело с версии 2.6: модуль команд был удален в Python 3. Вместо этого используйте модуль подпроцесса».
Misch 19.04.2013 08:14:32
Это не опасно! Разработчики Python стараются разбивать функции только между основными выпусками (то есть между 2.x и 3.x). Я использую модуль команд с 2004 года Python 2.4. Он работает так же сегодня в Python 2.7.
Colonel Panic 23.04.2013 16:09:04
С опасным я не имел в виду, что он может быть удален в любое время (это другая проблема), и при этом я не сказал, что использовать этот конкретный модуль опасно. Однако это может стать опасным, если обнаружена уязвимость системы безопасности, но модуль не разрабатывается и не поддерживается. (Я не хочу сказать, что этот модуль уязвим или не подвержен проблемам с безопасностью, просто говорю о устаревших вещах в целом)
Misch 23.04.2013 16:23:36

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

Например:

In [9]: mylist = !ls

In [10]: mylist
Out[10]:
['file1',
 'file2',
 'file3',]
9
28.05.2017 23:03:57

После некоторых исследований у меня есть следующий код, который очень хорошо работает для меня. Он в основном печатает как 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
5
29.11.2019 21:55:54
Ваш код может потерять данные при выходе из подпроцесса, когда некоторые данные буферизируются. Вместо этого читайте до EOF, смотрите teed_call ()
jfs 13.07.2015 18:52:13

Используйте 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(" "))
6
29.11.2019 21:56:58

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

>>> 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)
21
30.04.2014 14:37:04

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

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

ex('echo hello shell.py') | "awk '{print $2}'"
16
1.05.2014 20:49:01

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

import os
os.system('ls')

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

import subprocess
subprocess.check_call('ls')

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

import subprocess
r = subprocess.check_output('ls')
9
29.11.2019 21:58:36

Есть также Пламбум

>>> 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
32
10.10.2014 17:41:13