Команды Popen для ОС и подпроцессов Python

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

Вступление

Python предлагает несколько вариантов запуска внешних процессов и взаимодействия с операционной системой. Однако методы отличаются для Python 2 и 3. Python 2 имеет несколько методов в os , которые теперь устарели и заменены subprocess , который является предпочтительным вариантом в Python 3.

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

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

Прежде всего, это старые методы os.popen*

Методы os.popen *

Модуль os предлагает четыре различных метода, которые позволяют нам взаимодействовать с операционной системой (как и с командной строкой) и создавать канал для других команд. Я имею в виду следующие методы: popen , popen2 , popen3 и popen4 , все из которых описаны в следующих разделах.

Цель каждого из этих методов - иметь возможность вызывать другие программы из вашего кода Python. Это может быть вызов другого исполняемого файла, например вашей собственной скомпилированной программы на C ++, или команды оболочки, например ls или mkdir .

os.popen

Метод os.popen открывает канал из команды. Этот канал позволяет команде отправлять свои выходные данные другой команде. Результатом является открытый файл, к которому могут получить доступ другие программы.

Синтаксис следующий:

 os.popen(command[, mode[, bufsize]]) 

Здесь command - это то, что вы будете выполнять, и его вывод будет доступен через открытый файл. Аргумент mode определяет , является ли считываемый этого выходного файла ( «г») или перезаписываемый ( «W»). Добавление «b» к mode откроет файл в двоичном режиме. Таким образом, например, «rb» создаст читаемый объект двоичного файла.

Чтобы получить код выхода выполненной команды, вы должны использовать метод close() файлового объекта.

Параметр bufsize сообщает popen сколько данных следует буферизовать, и может принимать одно из следующих значений:

  • 0 = без буферизации (значение по умолчанию)
  • 1 = строчная буферизация
  • N = приблизительный размер буфера, когда N> 0; и значение по умолчанию, когда N <0

Этот метод доступен для платформ Unix и Windows и устарел, начиная с версии Python 2.6. Если вы в настоящее время используете этот метод и хотите переключиться на версию Python 3, вот эквивалентная subprocess для Python 3:

Методика Заменен на


труба = os.popen ('cmd', 'r', bufsize) pipe = Popen ('cmd', shell = True, bufsize = bufsize, stdout = PIPE) .stdout. труба = os.popen ('cmd', 'w', bufsize) pipe = Popen ('cmd', shell = True, bufsize = bufsize, stdin = PIPE) .stdin.

В приведенном ниже коде показан пример использования метода os.popen

 import os 
 
 p = os.popen('ls -la') 
 print(p.read()) 

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

 $ python popen_test.py 
 total 32 
 drwxr-xr-x 7 scott staff 238 Nov 9 09:13 . 
 drwxr-xr-x 29 scott staff 986 Nov 9 09:08 .. 
 -rw-r--r-- 1 scott staff 52 Nov 9 09:13 popen2_test.py 
 -rw-r--r-- 1 scott staff 55 Nov 9 09:14 popen3_test.py 
 -rw-r--r-- 1 scott staff 53 Nov 9 09:14 popen4_test.py 
 -rw-r--r-- 1 scott staff 49 Nov 9 09:13 popen_test.py 
 -rw-r--r-- 1 scott staff 0 Nov 9 09:13 subprocess_popen_test.py 

os.popen2

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

Синтаксис следующий:

 popen2(cmd[, mode[, bufsize]]) 

Эти аргументы имеют то же значение, что и в предыдущем методе os.popen .

Метод popen2 доступен как для платформ Unix, так и для Windows. Однако он присутствует только в Python 2. Опять же, если вы хотите использовать subprocess (более подробно показанную ниже), используйте вместо этого следующее:


Методика Заменен на


(child_stdin, child_stdout) = p = Popen ('cmd', shell = True, os.popen2 ('cmd', mode, bufsize) bufsize = bufsize, stdin = PIPE, stdout = PIPE, close_fds = True)
(child_stdin, child_stdout) = (p.stdin, p.stdout)


В приведенном ниже коде показан пример использования этого метода:

 import os 
 
 in, out = os.popen2('ls -la') 
 print(out.read()) 

Этот код даст те же результаты, что и в первом выводе кода выше. Разница здесь в том, что вывод popen2 состоит из двух файлов. Таким образом, вторая строка кода определяет две переменные: in и out . В последней строке, мы читаем выходной файл out и распечатать его на консоль.

os.popen3

Этот метод очень похож на предыдущие. Однако разница в том, что вывод команды представляет собой набор из трех файлов: stdin, stdout и stderr .

Синтаксис:

 os.popen3(cmd[, mode[, bufsize]]) 

где аргументы cmd , mode и bufsize имеют те же характеристики, что и в предыдущих методах. Метод доступен для платформ Unix и Windows.

Обратите внимание, что этот метод устарел, и документация Python рекомендует нам заменить popen3 следующим образом:


Методика Заменен на


(child_stdin,\ p = Popen ('cmd', shell = True, child_stdout,\ bufsize = bufsize,
child_stderr) = os.popen3 ('cmd', stdin = PIPE, stdout = PIPE, stderr mode, bufsize) = PIPE, close_fds = True)
(child_stdin,
child_stdout,
child_stderr) = (p.stdin, p.stdout, p.stderr)


Как и в предыдущих примерах, приведенный ниже код даст тот же результат, что и в нашем первом примере.

 import os 
 
 in, out, err = os.popen3('ls -la') 
 print(out.read()) 

Однако в этом случае мы должны определить три файла: stdin, stdout и stderr. Список файлов из нашей команды ls -la сохраняется в файле out

os.popen4

Как вы, наверное, догадались, os.popen4 похож на предыдущие методы. Однако в этом случае он возвращает только два файла: один для стандартного ввода, а другой - для стандартного вывода и стандартного вывода.

Этот метод доступен для платформ Unix и Windows и ( сюрприз! ) Также устарел, начиная с версии 2.6. Чтобы заменить его соответствующим Popen subprocess , сделайте следующее:


Методика Заменен на


(child_stdin, p = Popen ('cmd', shell = True, child_stdout_and_stderr) = bufsize = bufsize,
os.popen4 ('cmd', mode, bufsize) stdin = PIPE, stdout = PIPE, stderr = STDOUT, close_fds = True)
(child_stdin, child_stdout_and_stderr) = (p.stdin, p.stdout)


Следующий код даст тот же результат, что и в предыдущих примерах, который показан в первом выводе кода выше.

 import os 
 
 in, out = os.popen4('ls -la') 
 print(we.read()) 

Как видно из приведенного выше кода, метод очень похож на popen2 . Однако out файл в программе покажет объединенные результаты потоков stdout и stderr.

Резюме различий

Все различия между различными popen* связаны с их выводом, который кратко изложен в таблице ниже:

Методика Аргументы


открывать стандартный вывод popen2 стандартный ввод, стандартный вывод popen3 стандартный ввод, стандартный вывод, стандартный поток popen4 stdin, stdout и stderr

Кроме того, popen2 , popen3 и popen4 доступны только в Python 2, но не в Python 3. В Python 3 доступен popen , но вместо него рекомендуется использовать subprocess , который мы опишем более подробно в следующий раздел.

Метод susbprocess.Popen

Модуль subprocess был создан с намерением заменить несколько методов, доступных в os , которые не считались очень эффективными. В этом модуле мы находим новый класс Popen

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

Доступны следующие параметры:

 subprocess.Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0) 

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

В конструкторе довольно много аргументов. Самым важным для понимания является args , который содержит команду для процесса, который мы хотим запустить. Его можно указать как последовательность параметров (через массив) или как одну командную строку.

Второй аргумент, который важно понять, - это shell , значение которой по умолчанию равно False . В Unix, когда нам нужно запустить команду, принадлежащую оболочке, например ls -la , нам нужно установить shell=True .

Например, следующий код вызовет команду Unix ls -la через оболочку.

 import subprocess 
 subprocess.Popen('ls -la', shell=True) 

Результаты можно увидеть в выводе ниже:

 $ python subprocess_popen_test.py 
 total 40 
 drwxr-xr-x 7 scott staff 238 Nov 9 09:13 . 
 drwxr-xr-x 29 scott staff 986 Nov 9 09:08 .. 
 -rw-r--r-- 1 scott staff 52 Nov 9 09:13 popen2_test.py 
 -rw-r--r-- 1 scott staff 55 Nov 9 09:14 popen3_test.py 
 -rw-r--r-- 1 scott staff 53 Nov 9 09:14 popen4_test.py 
 -rw-r--r-- 1 scott staff 49 Nov 9 09:13 popen_test.py 
 -rw-r--r-- 1 scott staff 56 Nov 9 09:16 subprocess_popen_test.py 

Используя следующий пример на компьютере с Windows, мы можем легче shell Здесь мы открываем Microsoft Excel из оболочки или как исполняемую программу. Из оболочки это похоже на то, как если бы мы открывали Excel из командного окна.

Следующий код откроет Excel из оболочки (обратите внимание, что мы должны указать shell=True ):

 import subprocess 
 subprocess.Popen("start excel", shell=True) 

Однако мы можем получить те же результаты, вызвав исполняемый файл Excel. В этом случае мы не используем оболочку, поэтому оставляем ее со значением по умолчанию ( False ); но мы должны указать полный путь к исполняемому файлу.

 import subprocess 
 subprocess.Popen("C:\Program Files (x86)\Microsoft Office\Office15\excel.exe") 

Кроме того, когда мы создаем экземпляр Popen , у нас есть доступ к нескольким полезным методам:

Методика Описание


Popen.poll() Проверяет, завершен ли дочерний процесс. Popen.wait() Подождите, пока дочерний процесс завершится. Popen.communicate() Позволяет взаимодействовать с процессом. Popen.send_signal() Посылает сигнал дочернему процессу. Popen.terminate() Останавливает дочерний процесс. Popen.kill() Убивает дочерний процесс.

Полный список можно найти в документации подпроцесса . Наиболее часто используемый метод - это communicate .

Метод communicate позволяет нам считывать данные со стандартного ввода, а также позволяет отправлять данные на стандартный вывод. Он возвращает кортеж, определенный как (stdoutdata, stderrdata) .

Например, следующий код объединяет команды Windows dir и sort .

 import subprocess 
 
 p1 = subprocess.Popen('dir', shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 
 p2 = subprocess.Popen('sort /R', shell=True, stdin=p1.stdout) 
 
 p1.stdout.close() 
 out, err = p2.communicate() 

Чтобы объединить обе команды, мы создаем два подпроцесса: один для команды dir а другой - для команды sort . Поскольку мы хотим выполнить сортировку в обратном порядке, мы добавляем параметр /R к вызову sort

Мы определяем стандартный вывод процесса 1 как PIPE, что позволяет нам использовать вывод процесса 1 в качестве ввода для процесса 2. Затем нам нужно закрыть стандартный вывод процесса 1, чтобы его можно было использовать в качестве ввода для процесса 2. связь между процессами достигается с помощью метода communicate

Запуск этого из командной оболочки Windows дает следующее:

 > python subprocess_pipe_test.py 
 11/09/2017 08:52 PM 234 subprocess_pipe_test.py 
 11/09/2017 07:13 PM 99 subprocess_pipe_test2.py 
 11/09/2017 07:08 PM 66 subprocess_pipe_test3.py 
 11/09/2017 07:01 PM 56 subprocess_pipe_test4.py 
 11/09/2017 06:48 PM <DIR> .. 
 11/09/2017 06:48 PM <DIR> . 
 Volume Serial Number is 2E4E-56A3 
 Volume in drive D is ECA 
 Directory of D:\MyPopen 
 4 File(s) 455 bytes 
 2 Dir(s) 18,634,326,016 bytes free 

Подведение итогов

В os представляли собой хороший вариант, однако в настоящее время в subprocess есть несколько методов, которые являются более мощными и эффективными в использовании. Среди доступных инструментов есть Popen , который можно использовать в более сложных случаях. Этот класс также содержит communicate , который помогает нам объединять различные команды для более сложных функций.

Для чего вы используете popen* и какие предпочитаете? Дайте нам знать об этом в комментариях!

comments powered by Disqus