python выполняет команды терминала без echo [duplicate]

Давайте начнем с начала и исследователя немного глубже:

Итак, у вас есть два списка:

list_1=['01','98']
list_2=[['01','98']]

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

Итак, сначала попробуем общий метод копирования:

copy=list_1

Теперь, если вы думаете, что копия скопировала список_1, вы можете Неправильно, давайте проверим:

The id() function shows us that both variables point to the same list object, i.e. they share this object.
print(id(copy))
print(id(list_1))

output:

4329485320
4329485320

Удивлен? Итак, давайте рассмотрим это:

Итак, поскольку мы знаем, что python ничего не хранит в переменной, переменные просто ссылаются на объект и объект хранят значение. Здесь object list, но мы создали две ссылки на тот же объект двумя разными именами переменных. Таким образом, обе переменные указывают на один и тот же объект:

, поэтому, когда вы делаете copy=list_1, что на самом деле его делает:

Здесь в изображении list_1 и copy находятся два имени переменной, но объект одинаковый для обеих переменных, который является list

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

copy[0]="modify"

print(copy)
print(list_1)

output:

['modify', '98']
['modify', '98']

Так что он изменил Исходный список:

Что такое решение?

Решение:

Теперь перейдем ко второму питоническому методу копирования списка :

copy_1=list_1[:]

Теперь этот метод исправить то, с чем мы столкнулись в первом выпуске, давайте проверим его:

print(id(copy_1))
print(id(list_1))

4338792136
4338791432

Итак, мы можем видеть, что оба наших списка имеют разные id и это означает, что обе переменные указывают на разные объекты, так что здесь происходит следующее:

N ow давайте попробуем изменить список и посмотрим, остаемся ли мы перед предыдущей проблемой:

copy_1[0]="modify"

print(list_1)
print(copy_1)

Выход:

['01', '98']
['modify', '98']

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

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

copy_2=list_2[:]

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

print(id((list_2)),id(copy_2))

получаем результат:

4330403592 4330403528

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

Поэтому, когда мы пытаемся:

copy_2[0][1]="modify"

print(list_2,copy_2)

, он дает нам вывод:

[['01', 'modify']] [['01', 'modify']]

Теперь, это немного запутывает, мы использовали питоновский путь, и все же мы сталкиваемся с той же проблемой .

давайте поймем это:

Итак, когда мы делаем:

copy_2=list_2[:]

, мы фактически копируем только внешний список, а не вложенный список, поэтому вложенный list - тот же объект для обоих списков, давайте проверим:

print(id(copy_2[0]))
print(id(list_2[0]))

output:

4329485832
4329485832

Так что, фактически, когда мы делаем copy_2=list_2[:], это происходит:

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

Итак, каково решение?

Решение - deep copy

from copy import deepcopy
deep=deepcopy(list_2)

Итак, теперь давайте проверим:

print(id((list_2)),id(deep))

вывод:

4322146056 4322148040

оба идентификатора разные, теперь давайте проверим идентификатор вложенного списка:

print(id(deep[0]))
print(id(list_2[0]))

output:

4322145992
4322145800

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

So когда вы делаете deep=deepcopy(list_2), что на самом деле происходит:

Таким образом, оба вложенных списка указывают на другой объект, и теперь они имеют отдельную копию вложенного списка.

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

, так что если мы это сделаем:

deep[0][1]="modify"
print(list_2,deep)

вывод:

[['01', '98']] [['01', 'modify']]

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

Если вам понравился мой подробный ответ, сообщите мне об этом, если вы сомневаетесь в этом ответе, прокомментируйте:)

3810
задан igaurav 22 September 2014 в 13:40
поделиться

26 ответов

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

from subprocess import Popen

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

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

3531
ответ дан Peter Mortensen 19 August 2018 в 15:00
поделиться
  • 1
    Есть ли способ использовать замену переменных? IE Я пытался сделать echo $PATH с помощью call(["echo", "$PATH"]), но он просто повторил буквенную строку $PATH вместо любой подстановки. Я знаю, что могу получить переменную среды PATH, но мне интересно, есть ли простой способ заставить команду вести себя так, как если бы я выполнил ее в bash. – Kevin Wheeler 1 September 2015 в 23:17
  • 2
    @KevinWheeler Вам нужно будет использовать shell=True для этого. – SethMMorton 2 September 2015 в 20:38
  • 3
    @KevinWheeler Вы НЕ должны использовать shell=True, для этого Python поставляется с os.path.expandvars . В вашем случае вы можете написать: os.path.expandvars("$PATH"). @SethMMorton, пожалуйста, пересмотреть свой комментарий - & gt; Почему бы не использовать shell = True – Murmel 11 November 2015 в 21:24
  • 4
    он также устарел. использовать подпроцесс – Corey Goldberg 9 December 2015 в 19:13
  • 5
    С Python 3.5 предлагается использовать subprocess.run вместо subprocess.call. docs.python.org/3/library/subprocess.html – Hannes Karppila 4 July 2016 в 19:31
  • 6
    Пример вызывает ls -l, но не дает доступа к его выводу (stdout недоступен). Я нахожу это запутанным - вместо этого вы можете использовать команду без stdout, например touch. – florisla 12 July 2017 в 10:02
  • 7
    Обратите внимание, что для check_output требуется список, а не строка. Если вы не полагаетесь на цитируемые пробелы, чтобы сделать ваш звонок действительным, самым простым и удобным для чтения способом является subprocess.check_output("ls -l /dev/null".split()). – Bruno Bronosky 30 January 2018 в 19:18
  • 8
    Что вы подразумеваете под & quot; команда не очищается & quot; ? – Peter Mortensen 3 June 2018 в 17:10
  • 9
    Что вы подразумеваете под & quot; Кто-нибудь запускает kwrite, не являющийся подпроцессом & quot; ? – Peter Mortensen 3 June 2018 в 20:14
  • 10
    Не знаю, что я имел в виду почти десять лет назад (проверьте дату!), Но если бы я должен был догадаться, это было бы так, что проверки не было. – nimish 6 June 2018 в 16:01

Здесь есть другая разница, которая не упоминается ранее.

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

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

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

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

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

3531
ответ дан Peter Mortensen 19 August 2018 в 15:00
поделиться
  • 1
    Есть ли способ использовать замену переменных? IE Я пытался сделать echo $PATH с помощью call(["echo", "$PATH"]), но он просто повторил буквенную строку $PATH вместо любой подстановки. Я знаю, что могу получить переменную среды PATH, но мне интересно, есть ли простой способ заставить команду вести себя так, как если бы я выполнил ее в bash. – Kevin Wheeler 1 September 2015 в 23:17
  • 2
    @KevinWheeler Вам нужно будет использовать shell=True для этого. – SethMMorton 2 September 2015 в 20:38
  • 3
    @KevinWheeler Вы НЕ должны использовать shell=True, для этого Python поставляется с os.path.expandvars . В вашем случае вы можете написать: os.path.expandvars("$PATH"). @SethMMorton, пожалуйста, пересмотреть свой комментарий - & gt; Почему бы не использовать shell = True – Murmel 11 November 2015 в 21:24
  • 4
    он также устарел. использовать подпроцесс – Corey Goldberg 9 December 2015 в 19:13
  • 5
    С Python 3.5 предлагается использовать subprocess.run вместо subprocess.call. docs.python.org/3/library/subprocess.html – Hannes Karppila 4 July 2016 в 19:31
  • 6
    Пример вызывает ls -l, но не дает доступа к его выводу (stdout недоступен). Я нахожу это запутанным - вместо этого вы можете использовать команду без stdout, например touch. – florisla 12 July 2017 в 10:02
  • 7
    Обратите внимание, что для check_output требуется список, а не строка. Если вы не полагаетесь на цитируемые пробелы, чтобы сделать ваш звонок действительным, самым простым и удобным для чтения способом является subprocess.check_output("ls -l /dev/null".split()). – Bruno Bronosky 30 January 2018 в 19:18
  • 8
    Что вы подразумеваете под & quot; команда не очищается & quot; ? – Peter Mortensen 3 June 2018 в 17:10
  • 9
    Что вы подразумеваете под & quot; Кто-нибудь запускает kwrite, не являющийся подпроцессом & quot; ? – Peter Mortensen 3 June 2018 в 20:14
  • 10
    Не знаю, что я имел в виду почти десять лет назад (проверьте дату!), Но если бы я должен был догадаться, это было бы так, что проверки не было. – nimish 6 June 2018 в 16:01
3653
ответ дан Sani Kamal 31 October 2018 в 02:22
поделиться

Вызов внешней команды в 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 :

. Рекомендуемым подходом к вызову подпроцессов является использование функции run () для всех случаев использования, которые он может обрабатывать.

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

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

Захват output

Если вы хотите захватить вывод, вы можете передать 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), которые будут переданы по каналу в stdin подпроцесса.

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

Аргумент timeout передается Popen.communicate (). Если истечет время ожидания, дочерний процесс будет убит и будет ждать. Исключение TimeoutExpired будет повторно поднято после завершения дочернего процесса.

Если проверка верна, и процесс завершается с ненулевым кодом выхода, будет вызвано исключение CalledProcessError. Атрибуты этого исключения содержат аргументы, код выхода и stdout и stderr, если они были захвачены.

, и этот пример для 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)

Выполнить дочернюю программу в новом процессе. В POSIX класс использует os.execvp () - подобное поведение для выполнения дочерней программы. В Windows класс использует функцию Windows CreateProcess (). Аргументы для Popen следующие.

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

17
ответ дан Aaron Hall 19 August 2018 в 15:00
поделиться

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

16
ответ дан cdunn2001 19 August 2018 в 15:00
поделиться

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

subprocess.call(['ping', 'localhost'])
98
ответ дан cincodenada 19 August 2018 в 15:00
поделиться

Обновление:

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

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

Я рекомендую попробовать 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'>]
35
ответ дан Community 19 August 2018 в 15:00
поделиться

Я склонен использовать подпроцесс вместе с 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)
15
ответ дан Emil Stenström 19 August 2018 в 15:00
поделиться

Я всегда использую 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)
52
ответ дан Eric 19 August 2018 в 15:00
поделиться

С помощью стандартной библиотеки

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

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

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

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

import shlex
from subprocess import call
call(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.

36
ответ дан Honza Javorek 19 August 2018 в 15:00
поделиться

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

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

ex('echo hello shell.py') | "awk '{print $2}'"
13
ответ дан houqp 19 August 2018 в 15:00
поделиться

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

#!/usr/bin/python
import os
netid= "nova net-list | awk '/ External / { print $2 }'"
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
12
ответ дан IRSHAD 19 August 2018 в 15:00
поделиться

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

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

260
ответ дан Jim Fasarakis Hilliard 19 August 2018 в 15:00
поделиться
  • 1
    .readlines() считывает строки all сразу, т. е. блокирует до выхода подпроцесса (закрывает его конец). Чтобы читать в режиме реального времени (если нет проблем с буферизацией), вы можете: for line in iter(p.stdout.readline, ''): print line, – jfs 16 November 2012 в 16:12
  • 2
    Не могли бы вы рассказать о том, что вы подразумеваете под «, если нет проблем с буферизацией»? Если процесс блокируется определенно, вызов подпроцесса также блокируется. То же самое может произойти и с моим оригинальным примером. Что еще может произойти в отношении буферизации? – EmmEff 17 November 2012 в 15:25
  • 3
    дочерний процесс может использовать блочную буферизацию в неинтерактивном режиме вместо буферизации строк, поэтому p.stdout.readline() (примечание: no s в конце) не будет видеть никаких данных, пока ребенок не заполнит свой буфер. Если ребенок не производит много данных, тогда выход не будет в режиме реального времени. См. Вторую причину в Q: Почему бы просто не использовать трубу (popen ())? . В этом ответе приведены некоторые обходные пути (pexpect, pty, stdbuf) – jfs 17 November 2012 в 15:51
  • 4
    проблема буферизации имеет значение только в том случае, если вы хотите выводить в реальном времени и не относится к вашему коду, который ничего не печатает до тех пор, пока не будут получены данные all – jfs 17 November 2012 в 15:53

https://docs.python.org/2/library/subprocess.html

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

import os
os.system('cat testfile')
23
ответ дан Jonathan Callen 19 August 2018 в 15:00
поделиться

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

15
ответ дан Mariusz Jamro 19 August 2018 в 15:00
поделиться

Мне очень нравится 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
13
ответ дан mdwhatcott 19 August 2018 в 15:00
поделиться
import os
cmd = 'ls -al'
os.system(cmd)

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

96
ответ дан Patrick M 19 August 2018 в 15:00
поделиться
  • 1
    popen устарел в пользу подпроцесса . – Fox Wilson 8 August 2014 в 01:22
  • 2
    Вы также можете сохранить результат с помощью вызова os.system, так как он работает, как и сама оболочка UNIX, например, os.system ('ls -l & gt; test2.txt'). – Stefan Gruenwald 8 November 2017 в 00:19

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

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

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

import subprocess
import sys

# some code here

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

# some more code here

Идея здесь заключается в том, что вы не хотите ждать в line 'call subprocess', пока не будет закончен 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 in комментарий ниже отмечает, что семантически правильный флаг 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 еще не проливает свет.

158
ответ дан rstackhouse 19 August 2018 в 15:00
поделиться
  • 1
    я заметил возможную "quirk" с разработкой приложений py2exe в pydev + eclipse. я смог сказать, что основной скрипт не был отсоединен, поскольку выходное окно eclipse не заканчивалось; даже если скрипт завершит выполнение, он все еще ждет возврата. но, когда я попытался скомпилировать исполняемый файл py2exe, ожидается ожидаемое поведение (запускает процессы как отсоединенные, а затем завершает работу). я не уверен, но исполняемое имя больше не входит в список процессов. это работает для всех подходов (os.system («start *»), os.spawnl с os.P_DETACH, подпрограммы и т. д.), – maranas 9 April 2010 в 09:09
  • 2
    Windows gotcha: несмотря на то, что я породил процесс с DETACHED_PROCESS, когда я убил своего демона Python, все открытые им порты не будут освобождены, пока все порожденные процессы не прекратятся. WScript.Shell решил все мои проблемы. Пример здесь: pastebin.com/xGmuvwSx – Alexey Lebedev 16 April 2012 в 11:04
  • 3
  • 4
    Неправильно следующее: «[o] n windows (win xp), родительский процесс не завершится до тех пор, пока longtask.py не завершит свою работу». Родитель завершит работу нормально, но консольное окно (экземпляр conhost.exe) закрывается только при завершении последнего присоединенного процесса, и ребенок может унаследовать консоль родителя. Установка DETACHED_PROCESS в creationflags позволяет избежать этого, не позволяя ребенку наследовать или создавать консоль. Если вы хотите использовать новую консоль, используйте CREATE_NEW_CONSOLE (0x00000010). – eryksun 27 October 2015 в 01:27
  • 5
    Я не имел в виду, что выполнение отдельного процесса неверно. Тем не менее, вам может потребоваться установить стандартные дескрипторы файлов, труб или os.devnull, потому что в некоторых консольных программах с ошибкой выйдет ошибка. Создайте новую консоль, если вы хотите, чтобы дочерний процесс взаимодействовал с пользователем одновременно с родительским процессом. Было бы странно пытаться сделать это как в одном окне. – eryksun 27 October 2015 в 18:37

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

import os
cmd = "your command"
os.system(cmd)
16
ответ дан Samadi Salahedine 19 August 2018 в 15:00
поделиться

Существует также 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
22
ответ дан stuckintheshuck 19 August 2018 в 15:00
поделиться

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

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

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

2478
ответ дан the Tin Man 19 August 2018 в 15:00
поделиться
  • 1
    Хороший ответ / объяснение. Как этот ответ оправдывает девиз Python, как описано в этой статье? fastcompany.com/3026446/… "Стилистически, Perl и Python имеют разные философии. Наиболее известные девизы Perl являются " Есть больше, чем один способ сделать это ». Python разработан, чтобы иметь один очевидный способ сделать это & ​​quot; Похоже, это должно быть наоборот! В Perl я знаю только два способа выполнения команды - использование back-tick или open. – Jean 26 May 2015 в 21:16
  • 2
    Если вы используете Python 3.5+, используйте subprocess.run(). docs.python.org/3.5/library/subprocess.html#subprocess.run – phoenix 7 October 2015 в 16:37
  • 3
    То, что обычно нужно знать, - это то, что делается с STDOUT и STDERR дочернего процесса, потому что, если они игнорируются, в некоторых (довольно распространенных) условиях, в конечном итоге дочерний процесс выдаст системный вызов для записи в STDOUT (тоже STDERR?) что превысит выходной буфер, предоставленный для ОС ОС, и ОС заставит его блокировать, пока какой-либо процесс не будет прочитан из этого буфера. Итак, с рекомендуемыми в настоящее время способами, subprocess.run(..), что именно делает & quot; Это не фиксирует stdout или stderr по умолчанию. & Quot; подразумевает? Как насчет subprocess.check_output(..) и STDERR? – Evgeni Sergeev 1 June 2016 в 10:44
  • 4
    какую из команд вы рекомендуете блокировать мой сценарий? то есть, если я хочу запустить несколько команд в цикле for, как это сделать, не блокируя мой скрипт python? Я не забочусь о выходе команды, я просто хочу запустить много из них. – Charlie Parker 24 October 2017 в 19:08
  • 5
    @phoenix Я не согласен. Ничто не мешает вам использовать os.system в python3 docs.python.org/3/library/os.html#os.system – Qback 8 December 2017 в 10:27

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

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()
41
ответ дан Usman Khan 19 August 2018 в 15:00
поделиться
  • 1
    Передача команд как строк обычно является плохой идеей – Eric 23 July 2013 в 19:29
  • 2
    Я думаю, что это приемлемо для жестко закодированных команд, если оно повышает читаемость. – Adam Matan 2 April 2014 в 14:07

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

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

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

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

  1. Вы можете установить количество одновременных процессов для запуска («слоты») с помощью: ts -S <number-of-slots>
  2. Установка ts не требует прав администратора. Вы можете загрузить и скомпилировать его из источника с помощью простого make, добавить его в свой путь, и все готово.
12
ответ дан yuval 19 August 2018 в 15: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().

260
ответ дан Jim Fasarakis Hilliard 19 August 2018 в 15:00
поделиться
  • 1
    .readlines() считывает строки all сразу, т. е. блокирует до выхода подпроцесса (закрывает его конец). Чтобы читать в режиме реального времени (если нет проблем с буферизацией), вы можете: for line in iter(p.stdout.readline, ''): print line, – jfs 16 November 2012 в 16:12
  • 2
    Не могли бы вы рассказать о том, что вы подразумеваете под «, если нет проблем с буферизацией»? Если процесс блокируется определенно, вызов подпроцесса также блокируется. То же самое может произойти и с моим оригинальным примером. Что еще может произойти в отношении буферизации? – EmmEff 17 November 2012 в 15:25
  • 3
    дочерний процесс может использовать блочную буферизацию в неинтерактивном режиме вместо буферизации строк, поэтому p.stdout.readline() (примечание: no s в конце) не будет видеть никаких данных, пока ребенок не заполнит свой буфер. Если ребенок не производит много данных, тогда выход не будет в режиме реального времени. См. Вторую причину в Q: Почему бы просто не использовать трубу (popen ())? . В этом ответе приведены некоторые обходные пути (pexpect, pty, stdbuf) – jfs 17 November 2012 в 15:51
  • 4
    проблема буферизации имеет значение только в том случае, если вы хотите выводить в реальном времени и не относится к вашему коду, который ничего не печатает до тех пор, пока не будут получены данные all – jfs 17 November 2012 в 15:53
92
ответ дан Peter Mortensen 31 October 2018 в 02:22
поделиться
92
ответ дан Peter Mortensen 31 October 2018 в 02:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: