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

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

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

Показать лучший ответ

Прежде чем опубликовать новый ответ, учтите, что на этот вопрос уже есть более 60 ответов. Пожалуйста, убедитесь, что ваш ответ содержит информацию, которой нет среди существующих ответов.

Прежде чем использовать подпроцесс или os.system, подумайте о поиске пакета python, который делает то же самое. Обычно есть надстройки над часто используемыми утилитами bash, которые вы можете использовать.

 import os
os.system("your command")
  

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

Понятия не имею, что я имел в виду почти десять лет назад (проверь дату!), Но если бы мне пришлось угадывать, было бы, что проверка не была сделана.

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

Обратите внимание на отметку времени этого парня: «правильный» ответ имеет 40х голосов и является ответом № 1.

Единственное решение, которое сработало для меня для запуска NodeJS.

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

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

Вы также можете сохранить свой результат с помощью вызова os.system, поскольку он работает как сама оболочка UNIX, например, os.system ('ls -l> test2.txt')

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

 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"])
  

Есть ли способ использовать подстановку переменных? То есть я пытался сделать echo $PATH с помощью call(["echo", "$PATH"]) , но он просто повторил буквальную строку $PATH вместо какой-либо замены. Я знаю, что могу получить переменную среды PATH, но мне интересно, есть ли простой способ заставить команду вести себя точно так же, как если бы я выполнял ее в bash.

@KevinWheeler Вы должны будете использовать shell=True , чтобы это работало.

@KevinWheeler Вы НЕ должны использовать shell=True , для этого Python поставляется с os.path.expandvars . В вашем случае вы можете написать: os.path.expandvars("$PATH") . @SethMMorton, пожалуйста, пересмотрите свой комментарий -> Почему бы не использовать shell = Правда

В примере вызывается ls -l , но не предоставляется доступ к его выводу (stdout недоступен). Я нахожу это странным - вы можете вместо этого использовать команду без stdout, например touch .

Кажется, довольно неуклюже в Python3 + Windows . Если я введу имя файла со специальными символами, такими как & , оно выдаст FileNotFoundError . Хотя файл находится в рабочем каталоге, где я выполнил python, и, очевидно, существует.

вызывает блок? то есть, если я хочу запустить несколько команд в цикле for , как я могу это сделать без блокировки моего скрипта Python? Меня не волнует вывод команды, я просто хочу запустить их много.

Я понимаю использование call для более продвинутых функций, но я не вижу ничего плохого в использовании system , если он делает то, что вам нужно.

Чтобы хотя бы концептуально упростить: \ n вызов ("ls -l" .split ())

Если вы хотите создать список из команды с параметрами , список, который можно использовать с subprocess при shell=False , тогда используйте shlex.split для простого способа сделать это docs.python.org/ 2 / библиотека / shlex.html # shlex.split

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

@CharlieParker: блоки call , check_call , check_output и run . Если вы хотите неблокировать, используйте subprocess.Popen .

@sudo: ты получил это наоборот. system() является более продвинутым, чем Popen , он добавляет чертову оболочку, которая готова перевернуть вас, когда вы меньше всего этого ожидаете. Какая оболочка? Зависит от того, что пользователь имеет в качестве окружения SHELL, что означает, что точный синтаксис, который он вам испортит, часто находится вне вашего контроля. Popen - более низкий уровень, он ближе к тому, как выглядит базовый OS API, и имеет гораздо менее удивительное поведение.

@LieRyan Я бы использовал Popen , если бы беспокоился о точном синтаксисе, но если вы просто запускаете какую-то программу (возможно, с несколькими постоянными аргументами), system не так вопрос. Кроме того, иногда я хочу оболочку.

Вы забыли сказать, что для этого нужен Python 3.5. Например, он не работает на Python 3.4.3, который по умолчанию для Ubuntu 14.04 LTS

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

Исходный ответ содержал subprocess.call() , поэтому лицо, обновившее ответ (а не первоначальный ответчик!), Также должно объяснить это изменение более подробно.

Вы также можете передать в виде строки вместо списка строк: subprocess.run("ls -l")

Если они хотят назвать его run вместо call , почему бы просто не сделать его псевдонимом? Некоторые типы обратной совместимости являются сложными и позволяют продолжить работу с склонными к ошибкам шаблонами, но создание run == call легко, просто и практически бесплатно. Почему call для версий Python до 3.5 вместо новых и старых версий?

@SamuelMuldoon Проблема в том, что у subprocess.call семантика полностью отличается от subprocess.run . subprocess.call все еще существует в Python 3.5–3.8 (для обратной совместимости), просто если он у вас есть, subprocess.run намного лучше .

Вы также можете использовать os.popen . stackoverflow.com/a/59050139/9789097

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

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

Если вы хотите создать список из команды с параметрами , список, который можно использовать с subprocess при shell=False , тогда используйте shlex.split для простого способа сделать это docs.python.org/ 2 / library / shlex.html # shlex.split (это рекомендуемый путь в соответствии с документацией docs.python.org/2/library/subprocess.html#popen-constructor )

Это неверно: " он делает экранирование для вас и поэтому намного безопаснее ". подпроцесс не выполняет экранирование оболочки, субпроцесс не передает вашу команду через оболочку, поэтому нет необходимости в экранировании оболочки.

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

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

 import os
os.system('cat testfile')
  

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

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

Хотя я согласен с общей рекомендацией, subprocess не устраняет все проблемы с безопасностью и имеет некоторые собственные неприятные проблемы.

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

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

Если вы используете Python 3.5+, используйте subprocess.run() . docs.python.org/3.5/library/subprocess.html#subprocess. запустить

Обычно нужно знать, что делается с STDOUT и STDERR дочернего процесса, потому что, если они игнорируются, при некоторых (довольно распространенных) условиях, в конечном итоге дочерний процесс выдаст системный вызов для записи в STDOUT (тоже STDERR?) это превысило бы выходной буфер, предоставленный для процесса ОС, и ОС заставит его заблокировать, пока какой-либо процесс не прочитает из этого буфера. Итак, с помощью рекомендуемых в настоящее время способов, subprocess.run(..) , что именно означает «Это не захватывает stdout или stderr по умолчанию». подразумевает? А как насчет subprocess.check_output(..) и STDERR?

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

@ Phoenix Я не согласен. Ничто не мешает вам использовать os.system в python3 docs.python. орг / 3 / библиотека / os.html # os.system

моя мама не любила меня && rm -rf / ничего не будет делать: D Вероятно, моя мама не любила меня || rm -rf / будет опаснее :)

@ Да, но это не то, что исполняется на примере. Обратите внимание на echo перед строкой, переданной в Popen ? Таким образом, полная команда будет echo my mama didnt love me && rm -rf / .

Это возможно неправильный путь назад. Большинству людей нужен только subprocess.run() или его старшие братья и сестры subprocess.check_call() и другие. Для случаев, когда их недостаточно, см. subprocess.Popen() . os.popen() , возможно, вообще не следует упоминать или даже после «взломать свой собственный код fork / exec / spawn».

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

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

Аватар jfs

.readlines() считывает все строки одновременно, то есть блокируется до выхода из подпроцесса (закрывает свой конец канала). Чтобы читать в режиме реального времени (если нет проблем с буферизацией), вы можете: for line in iter(p.stdout.readline, ''): print line,

Не могли бы вы уточнить, что вы подразумеваете под «если нет проблем с буферизацией»? Если процесс блокируется определенным образом, вызов подпроцесса также блокируется. То же самое может случиться и с моим оригинальным примером. Что еще может произойти в отношении буферизации?

Аватар jfs

дочерний процесс может использовать буферизацию блоков в неинтерактивном режиме вместо буферизации строк, поэтому p.stdout.readline() (примечание: нет s в конце) не увидит никаких данных, пока дочерний заполняет свой буфер. Если ребенок не производит много данных, то вывод не будет в реальном времени. Вторую причину смотрите в Q: Почему бы просто не использовать канал? (POPEN (?)) . Некоторые обходные пути предоставлены в этом ответе (pexpect, pty, stdbuf)

Аватар jfs

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

Этот ответ был хорош для своего времени, но мы больше не должны рекомендовать Popen для простых задач. Это также излишне указывает shell=True . Попробуйте один из subprocess.run() ответов.

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

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

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

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

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

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

Что вы подразумеваете под «Кто-нибудь запускает kwrite, не будучи подпроцессом» ?

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

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

я заметил возможную «причуду» разработки приложений py2exe в pydev + eclipse. я был в состоянии сказать, что основной сценарий не был отсоединен, потому что окно вывода eclipse не заканчивалось; даже если скрипт выполняется до конца, он все еще ожидает возврата. но, когда я попытался скомпилировать в исполняемый файл py2exe, происходит ожидаемое поведение (запускает процессы как отдельные, а затем выходит). я не уверен, но имя исполняемого файла больше нет в списке процессов. это работает для всех подходов (os.system ("start *"), os.spawnl с os.P_DETACH, подпрограммы и т. д.)

Понятно, что Windows: несмотря на то, что я порождал процесс с помощью DETACHED_PROCESS, когда я убивал моего демона Python, все открытые им порты не освобождались до тех пор, пока все порожденные процессы не завершатся. WScript.Shell решил все мои проблемы. Пример здесь: pastebin.com/xGmuvwSx

Я вижу, что import subprocess as sp;sp.Popen('calc') не ждет завершения подпроцесса. Кажется, флаги создания не нужны. Что мне не хватает?

@ubershmekel, я не уверен, что ты имеешь в виду, и у меня нет установки Windows. Если я правильно помню, без флагов вы не сможете закрыть экземпляр cmd , из которого вы запустили calc .

Я нахожусь на Windows 8.1 и calc , кажется, переживает закрытие python .

Есть ли какое-либо значение для использования «0x00000008»? Это конкретное значение, которое нужно использовать, или один из нескольких вариантов?

Неправильно указано следующее: «[o] n windows (win xp), родительский процесс не завершится, пока longtask.py не завершит свою работу». Родитель будет нормально завершать работу, но окно консоли (экземпляр conhost.exe) закрывается только при выходе из последнего подключенного процесса, и дочерний объект может наследовать консоль родителя. Настройка DETACHED_PROCESS в creationflags позволяет избежать этого, не давая ребенку наследовать или создавать консоль. Если вместо этого вы хотите новую консоль, используйте CREATE_NEW_CONSOLE (0x00000010).

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

stdout=subprocess.PIPE заставит ваш код зависать, если у вас длинный вывод от ребенка. Для получения дополнительной информации см. thraxil .org / пользователи / Anders / сообщений / 2008/03/13 / ...

не существует ли независимого от ОС способа запуска процесса в фоновом режиме?

Ваш ответ кажется мне странным. Я просто открыл subprocess.Popen и ничего плохого не произошло (ждать не пришлось). Почему именно нам нужно беспокоиться о сценарии, на который вы указываете? Я скептически

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

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

 child = pexpect.spawn('ftp 192.168.0.24')

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

child.sendline('anonymous')

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

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

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

Также обратите внимание на параметр shell . р>

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

Обратите внимание, что check_output требует список, а не строку. Если вы не используете пробелы в кавычках, чтобы сделать ваш вызов действительным, самый простой и читаемый способ сделать это - subprocess.check_output("ls -l /dev/null".split()) .

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

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

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

 from subprocess import Popen

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

Ознакомьтесь с subprocess.Popen .

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

 from commands import getstatusoutput

try:
    return getstatusoutput("ls -ltr")
except Exception, e:
    return None
  

Это будет устаревшим в Python 3.0?

Действительно, в commands документации из Python 2.7 об этом говорится устарел в 2.6 и будет удален в 3.0.

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

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

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

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

Аватар Joe

Update:

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

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

Используйте модуль подпроцесса (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 .

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

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

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

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

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

Обновление

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

Без вывода результата:

 import os
os.system("your command here")
  

С выводом результата:

 import commands
commands.getoutput("your command here")
or
commands.getstatusoutput("your command here")
  

commands больше не доступен в Python 3. Вы должны предпочесть subprocess перед os.system()

модуль подпроцесса , описанный выше 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.6: модуль команд был удален в Python 3. Вместо этого используйте модуль подпроцесса».

Это не опасно! Разработчики Python стараются разбивать функции только между основными выпусками (то есть между 2.x и 3.x). Я использую модуль команд с 2004 года Python 2.4. Он работает так же сегодня в Python 2.7.

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

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

Например:

 In [9]: mylist = !ls

In [10]: mylist
Out[10]:
['file1',
 'file2',
 'file3',]
  

После некоторых исследований у меня есть следующий код, который очень хорошо работает для меня. Он в основном печатает как 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
  

Аватар jfs

Ваш код может потерять данные при выходе из подпроцесса, когда некоторые данные буферизируются. Вместо этого читайте до EOF, см. teed_call ()

Используйте 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(" "))
  

Я склонен использовать подпроцесс вместе с 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)
  

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

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

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

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

 import os
os.system('ls')
  

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

 import subprocess
subprocess.check_call('ls')
  

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

 import subprocess
r = subprocess.check_output('ls')
  

Существует также 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 = 'ls -al'

os.system(cmd)
  

os - этот модуль предоставляет переносимый способ использования функций, зависящих от операционной системы.

Для других функций os здесь документация.

это также устарело. использовать подпроцесс

Использование функции Popen модуля Python subprocess - самый простой способ запуска команд Linux. При этом функция Popen.communicate() выдаст ваши команды. Например,

 import subprocess

..
process = subprocess.Popen(..)   # Pass command and arguments to the function
stdout, stderr = process.communicate()   # Get command output and error
..
  

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

Вот мои два цента: на мой взгляд, это лучшая практика при работе с внешними командами ...

Это возвращаемые значения из метода execute ...

 pass, stdout, stderr = execute(["ls","-la"],"/home/user/desktop")
  

Это метод execute ...

 def execute(cmdArray,workingDir):

    stdout = ''
    stderr = ''

    try:
        try:
            process = subprocess.Popen(cmdArray,cwd=workingDir, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=1)
        except OSError:
            return [False, '', 'ERROR : command(' + ' '.join(cmdArray) + ') could not get executed!']

        for line in iter(process.stdout.readline, b''):

            try:
                echoLine = line.decode("utf-8")
            except:
                echoLine = str(line)

            stdout += echoLine

        for line in iter(process.stderr.readline, b''):

            try:
                echoLine = line.decode("utf-8")
            except:
                echoLine = str(line)

            stderr += echoLine

    except (KeyboardInterrupt,SystemExit) as err:
        return [False,'',str(err)]

    process.stdout.close()

    returnCode = process.wait()
    if returnCode != 0 or stderr != '':
        return [False, stdout, stderr]
    else:
        return [True, stdout, stderr]
  

Потенциал тупика: используйте метод .communicate

А еще лучше избегайте Popen() и используйте API более высокого уровня, который теперь собран в единую функцию subprocess.run()

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

 from subprocess import PIPE, run

command = ['echo', 'hello']
result = run(command, stdout=PIPE, stderr=PIPE, universal_newlines=True)
print(result.returncode, result.stdout, result.stderr)
  

Ответ с функцией запуска был добавлен в 2015 году. Вы повторили это. Я думаю, что это было причиной отрицательного голосования

Я бы порекомендовал следующий метод 'run', и он поможет нам получить STDOUT, STDERR и статус выхода в качестве словаря; Вызывающий объект может прочитать словарь, возвращаемый методом run, чтобы узнать фактическое состояние процесса.

   def run (cmd):
       print "+ DEBUG exec({0})".format(cmd)
       p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=True)
       (out, err) = p.communicate()
       ret        = p.wait()
       out        = filter(None, out.split('\n'))
       err        = filter(None, err.split('\n'))
       ret        = True if ret == 0 else False
       return dict({'output': out, 'error': err, 'status': ret})
  #end
  

Это не полностью переопределяет что-то вроде subprocess.run() . Особенно следует избегать shell=True , когда это не является строго необходимым.

В Windows вы можете просто импортировать модуль subprocess и запускать внешние команды, вызывая subprocess.Popen() , subprocess.Popen().communicate() и subprocess.Popen().wait() , как показано ниже:

 # Python script to run a command line
import subprocess

def execute(cmd):
    """
        Purpose  : To execute a command and return exit status
        Argument : cmd - command to execute
        Return   : exit_code
    """
    process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    (result, error) = process.communicate()

    rc = process.wait()

    if rc != 0:
        print "Error: failed to execute command:", cmd
        print error
    return result
# def

command = "tasklist | grep python"
print "This process detail: \n", execute(command)
  

Вывод:

 This process detail:
python.exe                     604 RDP-Tcp#0                  4      5,660 K
  

Использование:

 import subprocess

p = subprocess.Popen("df -h", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
print p.split("\n")
  

Это дает хороший вывод, с которым легче работать:

 ['Filesystem      Size  Used Avail Use% Mounted on',
 '/dev/sda6        32G   21G   11G  67% /',
 'none            4.0K     0  4.0K   0% /sys/fs/cgroup',
 'udev            1.9G  4.0K  1.9G   1% /dev',
 'tmpfs           387M  1.4M  386M   1% /run',
 'none            5.0M     0  5.0M   0% /run/lock',
 'none            1.9G   58M  1.9G   3% /run/shm',
 'none            100M   32K  100M   1% /run/user',
 '/dev/sda5       340G  222G  100G  69% /home',
 '']
  

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

 #!/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

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

Вывод print (networkId)

 27a74fcd-37c0-4789-9414-9531b7e3f126
  

Вы не должны рекомендовать os.popen() в 2016 году. Сценарий Awk можно легко заменить на собственный код Python.

Есть много способов вызвать команду.

  • Например:

если and.exe нужны два параметра. В cmd мы можем вызвать sample.exe и использовать это: and.exe 2 3 и на экране отображается 5 .

Если мы используем сценарий Python для вызова and.exe , мы должны делать то же самое ..

  1. os.system(cmd,...)

    • os.system(("and.exe" + " " + "2" + " " + "3"))
  2. os.popen(cmd,...)

    • os.popen(("and.exe" + " " + "2" + " " + "3"))
  3. subprocess.Popen(cmd,...)
    • subprocess.Popen(("and.exe" + " " + "2" + " " + "3"))

Это слишком сложно, поэтому мы можем объединить cmd с пробелом:

 import os
cmd = " ".join(exename,parameters)
os.popen(cmd)
  

os.popen не рекомендуется и, возможно, даже не упоминается. Пример subpocess должен передавать аргументы в виде списка, а не соединять их пробелами.

Здесь вызывается внешняя команда и возвращается или выводится вывод команды:

Python Подпроцесс check_output подходит для

Запустите команду с аргументами и верните ее вывод в виде байтовой строки.

 import subprocess
proc = subprocess.check_output('ipconfig /all')
print proc
  

Аргумент должен быть правильно разбит на токены в список, или вы должны явно передать shell=True . В Python 3.x (где, я думаю, x> 3) вы можете получить вывод в виде правильной строки с помощью universal_newlines=True , и вы, вероятно, захотите переключиться на subproces.run()

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

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

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

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

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

    ts -S <number-of-slots>

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

ts не является стандартным в любом известном мне дистрибутиве, хотя указатель на at слегка полезен. Вы должны также упомянуть batch . Как и везде, рекомендация os.system() должна, по крайней мере, упоминать, что subprocess является рекомендуемой заменой.

Простой пример двусторонней связи между основным процессом и подпроцессом можно найти здесь: stackoverflow.com/a/52841475/1349673

Первый пример, вероятно, должен иметь shell=True или (еще лучше) передать команду в виде списка.

Я написал оболочку для обработки ошибок и перенаправления вывода и прочего.

 import shlex
import psutil
import subprocess

def call_cmd(cmd, stdout=sys.stdout, quiet=False, shell=False, raise_exceptions=True, use_shlex=True, timeout=None):
    """Exec command by command line like 'ln -ls "/var/log"'
    """
    if not quiet:
        print("Run %s", str(cmd))
    if use_shlex and isinstance(cmd, (str, unicode)):
        cmd = shlex.split(cmd)
    if timeout is None:
        process = subprocess.Popen(cmd, stdout=stdout, stderr=sys.stderr, shell=shell)
        retcode = process.wait()
    else:
        process = subprocess.Popen(cmd, stdout=stdout, stderr=sys.stderr, shell=shell)
        p = psutil.Process(process.pid)
        finish, alive = psutil.wait_procs([p], timeout)
        if len(alive) > 0:
            ps = p.children()
            ps.insert(0, p)
            print('waiting for timeout again due to child process check')
            finish, alive = psutil.wait_procs(ps, 0)
        if len(alive) > 0:
            print('process {} will be killed'.format([p.pid for p in alive]))
            for p in alive:
                p.kill()
            if raise_exceptions:
                print('External program timeout at {} {}'.format(timeout, cmd))
                raise CalledProcessTimeout(1, cmd)
        retcode = process.wait()
    if retcode and raise_exceptions:
        print("External program failed %s", str(cmd))
        raise subprocess.CalledProcessError(retcode, cmd)
  

Вы можете назвать это так:

 cmd = 'ln -ls "/var/log"'
stdout = 'out.txt'
call_cmd(cmd, stdout)
  

Как пример (в Linux):

 import subprocess
subprocess.run('mkdir test.dir', shell=True)
  

Это создает test.dir в текущем каталоге. Обратите внимание, что это также работает:

 import subprocess
subprocess.call('mkdir test.dir', shell=True)
  

Эквивалентный код, использующий os.system:

 import os
os.system('mkdir test.dir')
  

Лучшей практикой будет использование подпроцесса вместо os, при этом .run предпочтительнее, чем .call. Все, что вам нужно знать о подпроцессе, это здесь . Также обратите внимание, что всю документацию по Python можно загрузить с здесь . Я скачал PDF, упакованный как .zip. Я упоминаю об этом, потому что есть хороший обзор модуля os в tutorial.pdf (страница 81). Кроме того, это авторитетный ресурс для программистов Python.

@ Ник Предли: замечено, но «shell = False» не выполняет нужную функцию. Каковы конкретно проблемы безопасности и какова альтернатива? Пожалуйста, дайте мне знать как можно скорее: я не хочу публиковать что-либо, что может вызвать проблемы у любого, кто просматривает это.

Основное предупреждение содержится в документации, но этот вопрос объясняет его более подробно: stackoverflow.com/questions/3172470/…

Аватар am5

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

Он появляется, если процесс выполняется с использованием метода poll () для процесса .

 import subprocess,sys

def exec_long_running_proc(command, args):
    cmd = "{} {}".format(command, " ".join(str(arg) if ' ' not in arg else arg.replace(' ','\ ') for arg in args))
    print(cmd)
    process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

    # Poll process for new output until finished
    while True:
        nextline = process.stdout.readline().decode('UTF-8')
        if nextline == '' and process.poll() is not None:
            break
        sys.stdout.write(nextline)
        sys.stdout.flush()

    output = process.communicate()[0]
    exitCode = process.returncode

    if (exitCode == 0):
        return output
    else:
        raise Exception(command, exitCode, output)
  

Вы можете вызвать его так:

 exec_long_running_proc(command = "hive", args=["-f", hql_path])
  

Аватар sbk

Вы получите неожиданные результаты, передав аргумент с пробелом. Использование repr(arg) вместо str(arg) может помочь простым совпадением того, что python и sh экранируют одинаковые кавычки

Аватар am5

@sbk repr(arg) не очень помог, вышеприведенный код также обрабатывает пробелы. Теперь работает следующее exec_long_running_proc(command = "ls", args=["-l", "~/test file*"])

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

Простой способ вызова внешней команды - использовать os.system(...) . И эта функция возвращает значение выхода команды. Но недостаток в том, что мы не получим stdout и stderr.

 ret = os.system('some_cmd.sh')
if ret != 0 :
    print 'some_cmd.sh execution returned failure'
  

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

subprocess.Popen обеспечивает большую гибкость для запуска внешней команды, чем использование os.system . Мы можем запустить команду в фоновом режиме и дождаться ее завершения. И после этого мы можем получить stdout и stderr.

 proc = subprocess.Popen(["./some_cmd.sh"], stdout=subprocess.PIPE)
print 'waiting for ' + str(proc.pid)
proc.wait()
print 'some_cmd.sh execution finished'
(out, err) = proc.communicate()
print 'some_cmd.sh output : ' + out
  

Вызов долгосрочной внешней команды в Python в фоновом режиме и остановка через некоторое время

Мы даже можем запустить длительный процесс в фоновом режиме, используя subprocess.Popen , и убить его через какое-то время после выполнения задачи.

 proc = subprocess.Popen(["./some_long_run_cmd.sh"], stdout=subprocess.PIPE)
# Do something else
# Now some_long_run_cmd.sh exeuction is no longer needed, so kill it
os.system('kill -15 ' + str(proc.pid))
print 'Output : ' proc.communicate()[0]
  

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

 import os
cmd = "your command"
os.system(cmd)
  

Это не указывает на недостатки, которые более подробно объясняются в PEP-324. . Документация для os.system явно рекомендует избегать его в пользу subprocess .

Если вам нужно вызвать команду оболочки из записной книжки Python (например, Jupyter , Zeppelin, Databricks или Google Cloud Datalab) вы можете просто использовать префикс ! .

Например,

 !ls -ilF
  

Используйте модуль os :

 import os
os.system("your command")
  

Например,

 import os
os.system("ifconfig")
  

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

Invoke - инструмент для выполнения задач Python (2.7 и 3.4+) и библиотека. Он предоставляет чистый API высокого уровня для запуска команд оболочки

 >>> from invoke import run
>>> cmd = "pip install -r requirements.txt"
>>> result = run(cmd, hide=True, warn=True)
>>> print(result.ok)
True
>>> print(result.stdout.splitlines()[-1])
Successfully installed invocations-0.13.0 pep8-1.5.7 spec-1.3.1
  

Это отличная библиотека. Я пытался объяснить это коллеге на днях, и adn описал это так: invoke для subprocess как requests для urllib3 .

Я написал небольшую библиотеку, чтобы помочь с этим вариантом использования:

https://pypi.org/project/citizenshell/

Его можно установить с помощью

 pip install citizenshell
  

А затем используется следующим образом:

 from citizenshell import sh
assert sh("echo Hello World") == "Hello World"
  

Вы можете отделить stdout от stderr и извлечь код завершения следующим образом:

 result = sh(">&2 echo error && echo output && exit 13")
assert result.stdout() == ["output"]
assert result.stderr() == ["error"]
assert result.exit_code() == 13
  

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

 for line in sh("for i in 1 2 3 4; do echo -n 'It is '; date +%H:%M:%S; sleep 1; done", wait=False)
    print ">>>", line + "!"
  

напечатает строки, как они доступны, благодаря wait = False

 >>> It is 14:24:52!
>>> It is 14:24:53!
>>> It is 14:24:54!
>>> It is 14:24:55!
  

Другие примеры можно найти по адресу https://github.com/meuter/citizenshell

Поскольку некоторые ответы были связаны с предыдущими версиями Python или использовали модуль os.system , я публикую этот ответ для таких людей, как я, которые намерены использовать subprocess в Python 3.5. +. Следующее помогло мне в Linux:

 import subprocess

# subprocess.run() returns a completed process object that can be inspected
c = subprocess.run(["ls", "-ltrh"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
print(c.stdout.decode('utf-8'))
  

Как упоминалось в документации , PIPE Значения являются байтовыми последовательностями, и для правильного их отображения необходимо учитывать декодирование. Для более поздних версий Python text=True и encoding='utf-8' добавляются в kwargs из subprocess.run() .

Вывод вышеупомянутого кода:

 total 113M
-rwxr-xr-x  1 farzad farzad  307 Jan 15  2018 vpnscript
-rwxrwxr-x  1 farzad farzad  204 Jan 15  2018 ex
drwxrwxr-x  4 farzad farzad 4.0K Jan 22  2018 scripts
.... # Some other lines
  

Существует два основных способа выполнения команд оболочки с использованием Python. Оба приведенных ниже примера показывают, как можно получить имя текущего рабочего каталога (pwd ), используя Python. Вы можете использовать любую другую команду Unix вместо pwd .

1.> 1-й метод: можно использовать модуль os из Python и system () <Оттуда / a> функция для выполнения команд оболочки в Python.

 import os
os.system('pwd')
  

Вывод:

 /Users/siddharth
  

1.> 2-й метод: Другой способ - использовать модуль подпроцесса и вызов () . р>

 import subprocess
subprocess.call('pwd')
  

Вывод:

 /Users/siddharth
  

Если вы не используете пользовательский ввод в командах, вы можете использовать это:

 from os import getcwd
from subprocess import check_output
from shlex import quote

def sh(command):
    return check_output(quote(command), shell=True, cwd=getcwd(), universal_newlines=True).strip()
  

И используйте его как

 branch = sh('git rev-parse --abbrev-ref HEAD')
  

shell=True порождает оболочку, поэтому вы можете использовать pipe и такие вещи оболочки sh('ps aux | grep python') . Это очень удобно для запуска жестко закодированных команд и обработки их вывода. universal_lines=True убедитесь, что выходные данные возвращаются в виде строки, а не двоичного кода.

cwd=getcwd() убедится, что команда запускается с тем же рабочим каталогом, что и интерпретатор. Это удобно для команд Git, работающих как пример с именем ветви Git выше.

Некоторые рецепты

  • свободная память в мегабайтах: sh('free -m').split('\n')[1].split()[1]
  • свободное место в / в процентах sh('df -m /').split('\n')[1].split()[4][0:-1]
  • загрузка процессора sum(map(float, sh('ps -ef -o pcpu').split('\n')[1:])

Но это не безопасно для пользовательского ввода из документации:

Вопросы безопасности

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

При использовании shell = True функция shlex.quote () может использоваться для правильно экранировать пробелы и метасимволы оболочки в строках, которые будут использоваться для создания команд оболочки.

Даже используя shlex.quote() , неплохо быть немного параноиком при использовании пользовательских вводов для команд оболочки. Одним из вариантов является использование жестко запрограммированной команды для получения общего вывода и фильтрации по вводу пользователя. В любом случае использование shell=False обеспечит выполнение только того процесса, который вы хотите выполнить, или вы получите ошибку No such file or directory .

Кроме того, на shell=True также наблюдается некоторое снижение производительности. По моим тестам оно примерно на 20% медленнее, чем shell=False (по умолчанию).

 In [50]: timeit("check_output('ls -l'.split(), universal_newlines=True)", number=1000, globals=globals())
Out[50]: 2.6801227919995654

In [51]: timeit("check_output('ls -l', universal_newlines=True, shell=True)", number=1000, globals=globals())
Out[51]: 3.243950183999914
  

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

 from sultan.api import Sultan

with Sultan.load(sudo=True, hostname="myserver.com") as sultan:
  sultan.yum("install -y tree").run()
  

Re "Предоставляет некоторые тонкости" : Можете ли вы уточнить?

Вы также можете использовать subprocess.getoutput() и subprocess.getstatusutput() , которые являются Унаследованные функции вызова оболочки из устаревшего модуля commands , т.е.

subprocess.getstatusoutput(cmd)

Возврат (exitcode , output ) выполнения cmd в оболочке.

<Ч>

subprocess.getoutput(cmd)

Вернуть вывод (stdout и stderr ) выполнения cmd в оболочке.

Если вы пишете сценарий оболочки Python и в вашей системе установлен IPython , Вы можете использовать магию взрыва для запуска команды внутри IPython:

 !ls
filelist = !ls
  

@PeterMortensen Я не думаю, что это работает в DOS, но оно должно работать в Cygwin.

Python 3.5 +

 import subprocess

p = subprocess.run(["ls", "-ltr"], capture_output=True)
print(p.stdout.decode(), p.stderr.decode())
  

Попробуйте в Интернете

 import subprocess

p = subprocess.run(["ls", "-ltr"], capture_output=True)
print(p.stdout.decode(), p.stderr.decode())
  

Попробуйте в Интернете

os.popen() - это самый простой и безопасный способ выполнения команды. Вы можете выполнить любую команду, запущенную в командной строке. Кроме того, вы также сможете захватить вывод команды, используя os.popen().read()

Вы можете сделать это так:

 import os
output = os.popen('Your Command Here').read()
print (output)
  

Пример, в котором вы перечисляете все файлы в текущем каталоге:

 import os
output = os.popen('ls').read()
print (output)
# Outputs list of files in the directory
  

БОЛЬШИНСТВО СЛУЧАЙ:

В большинстве случаев вам понадобится короткий фрагмент кода, подобный этому :

 import subprocess
import shlex

source = "test.txt"
destination = "test_copy.txt"

base = "cp {source} {destination}'"
cmd = base.format(source=source, destination=destination)
subprocess.check_call(shlex.split(cmd))
  

Это чисто и просто .

subprocess.check_call выполните команду с аргументами и дождитесь Команда для завершения.

shlex.split разделяет строку cmd с использованием подобного оболочке синтаксиса

ОТДЫХ ОТ ДЕЛА:

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

<сильный> Пример:

Использование оператора перенаправления в системе Unix

 input_1 = "input_1.txt"
input_2 = "input_2.txt"
output = "merged.txt"
base_command = "/bin/bash -c 'cat {input} > {output}'"

base_command.format(input_1, output=output_1)
subprocess.check_call(shlex.split(base_command))

base_command.format(input_1, output=output_2)
subprocess.check_call(shlex.split(base_command))
  

Как указано в Дзен Python : Явное лучше, чем неявный

Так что, если использовать функцию Python> = 3.6, она будет выглядеть примерно так:

 import subprocess
import shlex

def run_command(cmd_interpreter: str, command: str) -> None:
    base_command = f"{cmd_interpreter} -c '{command}'"
    subprocess.check_call(shlex.split(base_command)

  

 import os
os.system('testing')
  

os - это библиотека python, поэтому очень важно импортировать ее при выполнении любого теста.