параметрами спрограммы запуск Вызов внешней команды в Python




15 Answers

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

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

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

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

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

  3. Класс subprocess модуля 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. См. Документацию .

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

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

    См. Документацию .

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

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

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

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

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

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

python запуск exe с параметрами

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




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

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

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

import subprocess
import sys

# some code here

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

# some more code here

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

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

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

Решение состоит в том, чтобы передать флаг создания процесса DETACHED_PROCESS в базовую функцию CreateProcess в win 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. Если кто-нибудь знает, пожалуйста, поделитесь своими идеями. Googling при запуске фоновых процессов в Python еще не проливает свет.




Я бы рекомендовал использовать модуль подпроцесса вместо os.system, потому что он отключается для вас и, следовательно, намного безопаснее: http://docs.python.org/library/subprocess.html

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



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



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

Источники:

Это все библиотеки:

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

подпроцесс

Подпроцесс позволяет вам вызывать внешние команды и подключать их к их каналам ввода / вывода / ошибок (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.system и os.popen (Примечание. Существует также подпроцесс.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.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 - это библиотека для «скриптовых» программ 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 user@example.com:.') # Spawns child application
child.expect('Password:') # When this is the output
child.sendline('mypassword')

ткань

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

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

эмиссар

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

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

команды

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

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




Вот как я запускаю свои команды. Этот код содержит все необходимое

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



Обновить:

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

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

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

>>> 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')

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

Я рекомендую попробовать https://github.com/kennethreitz/envoy . Это оболочка для подпроцесса, которая, в свою очередь, предназначена для замены старых модулей и функций. Посланник является подпроцессом для людей.

Пример использования из файла 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'>]






Существует также Plumbum

>>> 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 = "your command"
os.system(cmd)



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




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




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

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

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



Мне очень нравится 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



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

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

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

Заметки о диспетчере очереди задач ( ts):

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

    ts -S <number-of-slots>

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




Related