Вопрос: Вызов внешней команды в Python


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


3552


источник


Ответы:


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

from subprocess import call
call(["ls", "-l"])

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

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

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

" Замена старых функций модулем подпроцесса раздел в подпроцесс у документации могут быть некоторые полезные рецепты.

Официальная документация по подпроцесс модуль:


3417



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

  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. 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. Видеть документация ,

  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 /».


2432



Обычно я использую:

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


251



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

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


155



I'd recommend using the subprocess module instead of os.system because it does shell escaping for you and is therefore much safer: http://docs.python.org/library/subprocess.html

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

92



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

If you want to return the results of the command, you can use os.popen. However, this is deprecated since version 2.6 in favor of the subprocess module, which other answers have covered well.


87



import os
os.system("your command")

Note that this is dangerous, since the command isn't cleaned. I leave it up to you to google for the relevant documentation on the 'os' and 'sys' modules. There are a bunch of functions (exec* and spawn*) that will do similar things.


76



Check the "pexpect" Python library, too.

It allows for interactive controlling of external programs/commands, even ssh, ftp, telnet, etc. You can just type something like:

child = pexpect.spawn('ftp 192.168.0.24')

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

child.sendline('anonymous')

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

51



I always use fabric for this things like:

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

But this seem to be a good tool: sh (Python subprocess interface).

Look an example:

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

50



There are lots of different libraries which allow you to call external commands with Python. For each library I've given a description and shown an example of calling an external command. The command I used as the example is ls -l (list all files). If you want to find out more about any of the libraries I've listed and linked the documentation for each of them.

Sources:

These are all the libraries:

Hopefully this will help you make a decision on which library to use :)

subprocess

Subprocess allows you to call external commands and connect them to their input/output/error pipes (stdin, stdout, and stderr). Subprocess is the default choice for running commands, but sometimes other modules are better.

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 is used for "operating system dependent functionality". It can also be used to call external commands with os.system and os.popen (Note: There is also a subprocess.popen). os will always run the shell and is a simple alternative for people who don't need to, or don't know how to use subprocess.run.

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

sh

sh is a subprocess interface which lets you call programs as if they were functions. This is useful if you want to run a command multiple times.

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 is a library for "script-like" Python programs. You can call programs like functions as in sh. Plumbum is useful if you want to run a pipeline without the shell.

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

pexpect

pexpect lets you spawn child applications, control them and find patterns in their output. This is a better alternative to subprocess for commands that expect a tty on 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')

fabric

fabric is a Python 2.5 and 2.7 library. It allows you to execute local and remote shell commands. Fabric is simple alternative for running commands in a secure shell (SSH)

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

envoy

envoy is known as "subprocess for humans". It is used as a convenience wrapper around the subprocess module.

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

commands

commands contains wrapper functions for os.popen, but it has been removed from Python 3 since subprocess is a better alternative.

The edit was based on J.F. Sebastian's comment.


46