Як ви викликаєте зовнішню команду (як би я набрав її в оболонці Unix або командному рядку Windows) із сценарію Python?
Як ви викликаєте зовнішню команду (як би я набрав її в оболонці Unix або командному рядку Windows) із сценарію Python?
Відповіді:
Подивіться на підпроцесорний модуль у стандартній бібліотеці:
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"])
shell=True
це.
shell=True
, для цього Python постачається з os.path.expandvars . У вашому випадку ви можете написати: os.path.expandvars("$PATH")
. @SethMMorton, будь ласка, перегляньте свій коментар -> Чому б не скористатися shell = True
for
циклі, як це зробити, не блокуючи мій скрипт python? Мене не хвилює вихід команди, я просто хочу запустити їх багато.
subprocess
коли shell=False
, тоді скористайтеся shlex.split
простим способом зробити це docs.python.org/2/library/shlex.html#shlex.split
Ось підсумок способів виклику зовнішніх програм та переваг та недоліків кожної з них:
os.system("some_command with args")
передає команду та аргументи в оболонку вашої системи. Це добре, тому що ви можете реально запускати декілька команд одночасно таким чином і налаштовувати труби та перенаправлення вводу / виводу. Наприклад:
os.system("some_command < input_file | another_command > output_file")
Однак, хоча це зручно, вам доведеться вручну обробляти вхідні символи оболонки, такі як пробіли тощо. З іншого боку, це також дозволяє запускати команди, які є просто командними оболонками, а насправді не зовнішніми програмами. Дивіться документацію .
stream = os.popen("some_command with args")
зробить те саме, що, os.system
за винятком того, що він дає вам файл-подібний об'єкт, який ви можете використовувати для доступу до стандартного вводу / виводу для цього процесу. Існують 3 інші варіанти popen, які всі обробляють введення / виведення трохи по-різному. Якщо ви передаєте все як рядок, то ваша команда передається оболонці; якщо ви передаєте їх як список, то вам не потрібно турбуватися про те, щоб уникнути нічого. Дивіться документацію .
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-х різних функцій. Дивіться документацію .
call
Функція від subprocess
модуля. Це в основному так само, як і Popen
клас, і приймає всі ті ж аргументи, але він просто чекає, поки команда завершиться і надасть вам код повернення. Наприклад:
return_code = subprocess.call("echo Hello World", shell=True)
Дивіться документацію .
Якщо ви перебуваєте на Python 3.5 або пізнішої версії, ви можете використовувати нову subprocess.run
функцію, яка дуже схожа на вищезазначені, але ще більш гнучку і повертає CompletedProcess
об’єкт, коли команда закінчить виконання.
Модуль os також має всі функції fork / exec / spawn, які ви мали б у програмі C, але я не рекомендую використовувати їх безпосередньо.
Можливо, subprocess
модуль повинен бути тим, що ви використовуєте.
Нарешті, врахуйте, що для всіх методів, коли ви передаєте остаточну команду для виконання оболонкою у вигляді рядка, і ви несете відповідальність за її уникнення. Є серйозні наслідки для безпеки, якщо будь-якій частині рядка, яку ви пройшли, не можна повністю довіряти. Наприклад, якщо користувач вводить частину / будь-яку частину рядка. Якщо ви не впевнені, використовуйте ці методи лише з константами. Щоб підказати про наслідки, розгляньте цей код:
print subprocess.Popen("echo %s " % user_input, stdout=PIPE).stdout.read()
і уявіть, що користувач вводить щось "моя мама не любила мене && rm -rf /", що могло б стерти всю файлову систему.
open
.
subprocess.run()
. docs.python.org/3.5/library/subprocess.html#subprocess.run
subprocess.run(..)
що саме означає "Це не зафіксує stdout або stderr за замовчуванням." мати на увазі? А як щодо subprocess.check_output(..)
STDERR?
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()
.
.readlines()
зчитує відразу всі рядки, тобто блокує, поки підпроцес не вийде (закриє його кінець труби). Щоб читати в режимі реального часу (якщо проблем із буферизацією немає), ви можете:for line in iter(p.stdout.readline, ''): print line,
p.stdout.readline()
(зверніть увагу: ні s
в кінці) не буде бачити даних, поки дитина не заповнить свій буфер. Якщо дитина не видає багато даних, то результат не буде в режимі реального часу. Дивіться другу причину в питанні: Чому б не просто використовувати трубу (popen ())? . У цій відповіді містяться деякі обхідні варіанти (pexpect, pty, stdbuf)
Popen
для простих завдань. Це також непотрібно вказувати shell=True
. Спробуйте одну з subprocess.run()
відповідей.
Деякі натяки на відмежування процесу дитини від виклику (запуск дочірнього процесу у фоновому режимі).
Припустимо, ви хочете почати довге завдання зі сценарію CGI. Тобто, дочірній процес повинен жити довше, ніж процес виконання сценарію CGI.
Класичний приклад документації підпроцесорного модуля:
import subprocess
import sys
# Some code here
pid = subprocess.Popen([sys.executable, "longtask.py"]) # Call subprocess
# Some more code here
Ідея тут полягає в тому, що ви не хочете чекати в рядку "виклик підпроцесу" до завершення longtask.py. Але незрозуміло, що станеться після рядка "ще якийсь код тут" із прикладу.
Моєю цільовою платформою був FreeBSD, але розробка була в Windows, тому я спочатку зіткнувся з проблемою в Windows.
У Windows (Windows XP) батьківський процес не закінчиться, поки longtask.py не закінчить свою роботу. Це не те, що потрібно в сценарії CGI. Проблема не є специфічною для Python; у спільноті PHP проблеми однакові.
Рішення полягає в тому, щоб передати DETACHED_PROCESS прапор створення процесу основній функції CreateProcess в API Windows. Якщо у вас інстальований 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. Якщо хтось знає, будь ласка, поділіться своїми ідеями. Гуглінг при запуску фонових процесів у Python поки не проливає жодного світла.
DETACHED_PROCESS
в creationflags
уникаєш цього шляху запобігання дитини від успадкування або створення консолі. Якщо ви хочете отримати нову консоль, використовуйте CREATE_NEW_CONSOLE
(0x00000010).
os.devnull
тому, що деякі консольні програми виходять із помилкою в іншому випадку. Створіть нову консоль, коли ви хочете, щоб дочірній процес взаємодів із користувачем одночасно з батьківським процесом. Було б заплутано намагатися робити обидва в одному вікні.
import os
os.system("your command")
Зауважте, що це небезпечно, оскільки команда не очищена. Я залишаю вам google для отримання відповідної документації на модулі 'os' та 'sys'. Є купа функцій (exec * та spawn *), які дозволять робити подібні дії.
subprocess
як на дещо більш універсальне та портативне рішення. Запуск зовнішніх команд, звичайно, неприйнятний (ви повинні переконатися, що команда доступна в будь-якій архітектурі, яку вам потрібно підтримувати), а передача даних користувача як зовнішньої команди по своїй суті небезпечна.
Я рекомендую використовувати підпроцесорний модуль замість os.system, тому що він робить для вас оболонку і тому набагато безпечніший.
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
cmd = 'ls -al'
os.system(cmd)
Якщо ви хочете повернути результати команди, ви можете використовувати os.popen
. Однак це застаріло з версії 2.6 на користь модуля підпроцесу , який інші відповіді добре висвітлювали.
Існує безліч різних бібліотек, які дозволяють викликати зовнішні команди з Python. Для кожної бібліотеки я описав і показав приклад виклику зовнішньої команди. Команда, яку я використала як приклад, є ls -l
(перерахуйте всі файли). Якщо ви хочете дізнатися більше про будь-яку бібліотеку, яку я перераховував, та зв'язали документацію для кожної з них.
Джерела:
Це всі бібліотеки:
Сподіваємось, це допоможе вам прийняти рішення, якою бібліотекою користуватися :)
підпроцес
Підпроцес дозволяє викликати зовнішні команди та підключити їх до їх вхідних / вихідних / помилкових труб (stdin, stdout та stderr). Підпроцес - вибір за замовчуванням для запуску команд, але іноді інші модулі є кращими.
subprocess.run(["ls", "-l"]) # Run command
subprocess.run(["ls", "-l"], stdout=subprocess.PIPE) # This will run the command and return any output
subprocess.run(shlex.split("ls -l")) # You can also use the shlex library to split the command
ос
os використовується для "функціональності, залежної від операційної системи". Його також можна використовувати для виклику зовнішніх команд за допомогою os.system
та os.popen
(Примітка. Існує також підпроцес.popen). os завжди буде запускати оболонку і є простою альтернативою для людей, яким не потрібно або не знають, як їх використовувати subprocess.run
.
os.system("ls -l") # run command
os.popen("ls -l").read() # This will run the command and return any output
ш
sh - інтерфейс підпроцесу, який дозволяє викликати програми так, ніби вони були функціями. Це корисно, якщо ви хочете виконати команду кілька разів.
sh.ls("-l") # Run command normally
ls_cmd = sh.Command("ls") # Save command as a variable
ls_cmd() # Run command as if it were a function
плюмбум
plumbum - це бібліотека програм "Python", подібних до сценарію. Ви можете викликати такі програми, як функції sh
. Плумбум корисний, якщо ви хочете провести трубопровід без оболонки.
ls_cmd = plumbum.local("ls -l") # get command
ls_cmd() # run command
pexpect
pexpect дозволяє нерестувати додатки, керувати ними та знаходити шаблони у їх результатах. Це краща альтернатива підпроцесу для команд, які очікують tty на Unix.
pexpect.run("ls -l") # Run command as normal
child = pexpect.spawn('scp foo user@example.com:.') # Spawns child application
child.expect('Password:') # When this is the output
child.sendline('mypassword')
тканина
тканина - бібліотека Python 2.5 та 2.7. Це дозволяє виконувати локальні та віддалені команди оболонки. Тканина - це проста альтернатива запуску команд у захищеній оболонці (SSH)
fabric.operations.local('ls -l') # Run command as normal
fabric.operations.local('ls -l', capture = True) # Run command and receive output
посланник
Посланець відомий як "підпроцес для людини". Він використовується як зручна обгортка навколо subprocess
модуля.
r = envoy.run("ls -l") # Run command
r.std_out # get output
команди
commands
містить функції обгортки для os.popen
, але він був видалений з Python 3, оскільки subprocess
є кращою альтернативою.
Редагування було засноване на коментарі Дж. Ф. Себастьяна.
Я завжди використовую 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)
Перевірте також "pexpect" бібліотеку Python.
Це дозволяє інтерактивне управління зовнішніми програмами / командами, навіть ssh, ftp, telnet тощо. Ви можете просто ввести щось на зразок:
child = pexpect.spawn('ftp 192.168.0.24')
child.expect('(?i)name .*: ')
child.sendline('anonymous')
child.expect('(?i)password')
Використовуйте модуль підпроцесу (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'))
Якщо ви не проти зовнішніх залежностей, використовуйте плюмбум :
from plumbum.cmd import ifconfig
print(ifconfig['wlan0']())
Це найкраща subprocess
обгортка. Це крос-платформа, тобто працює як в Windows, так і в Unix-подібних системах. Встановити pip install plumbum
.
Інша популярна бібліотека ш :
from sh import ifconfig
print(ifconfig('wlan0'))
Однак sh
підтримка Windows відмовилася, тож це не так приголомшливо, як раніше. Встановити pip install sh
.
Якщо вам потрібен вихід з команди, яку ви викликаєте, ви можете використовувати 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'
Також зверніть увагу на параметр оболонки .
Якщо оболонка є
True
, то вказана команда буде виконуватися через оболонку. Це може бути корисно, якщо ви використовуєте Python в першу чергу для покращеного потоку управління, який він пропонує в більшості системних оболонок, і все ще хочете зручного доступу до інших функцій оболонки, таких як труби оболонки, подстановочні імена файлів, розширення змінної середовища та розширення ~ до будинку користувача каталог. Тим НЕ менше, зверніть увагу , що сам Python пропонує реалізацію багатьох оболочечной подібні функції (зокрема,glob
,fnmatch
,os.walk()
,os.path.expandvars()
,os.path.expanduser()
, іshutil
).
check_output
потрібен список, а не рядок. Якщо ви не покладаєтесь на процитовані пробіли, щоб зробити ваш дзвінок дійсним, найпростіший, найчитабельніший спосіб зробити це subprocess.check_output("ls -l /dev/null".split())
.
Ось так я виконую свої команди. У цьому коді є все, що вам дуже потрібно
from subprocess import Popen, PIPE
cmd = "ls -l ~/"
p = Popen(cmd , shell=True, stdout=PIPE, stderr=PIPE)
out, err = p.communicate()
print "Return code: ", p.returncode
print out.rstrip(), err.rstrip()
subprocess.run
- це рекомендований підхід для Python 3.5, якщо ваш код не потребує підтримки сумісності з більш ранніми версіями Python. Він більш послідовний і пропонує подібну простоту використання, як і 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
Простий у використанні 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 () для всіх випадків використання, з якими вона може працювати. Для більш розширених випадків використання інтерфейс Popen можна використовувати безпосередньо.
Ось приклад найпростішого можливого використання - і він робить саме так, як було запропоновано:
>>> 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
Якщо ви хочете отримати результат, ви можете перейти 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
краще, ніж я міг:
Аргумент часу очікування передається 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
Однак, безпосередньо використання дасть вам доступ до його методів, у тому числі 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
залишатиметься вправою для читача.
shell=True
або (ще краще) передавати команду як список.
os.system
гаразд, але вид датований. Це також не дуже безпечно. Натомість спробуйте subprocess
. subprocess
не викликає sh безпосередньо і тому є більш безпечним, ніж os.system
.
Дізнайтеся більше тут .
subprocess
вона не усуває всіх проблем із безпекою і має деякі набридливі проблеми.
Також є 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
функцій, ось документація.
Це може бути так просто:
import os
cmd = "your command"
os.system(cmd)
Мені дуже подобається 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
Тут є ще одна відмінність, про яку раніше не говорилося.
subprocess.Popen
виконує <command> як підпроцес. У моєму випадку мені потрібно виконати файл <a>, який потребує зв’язку з іншою програмою <b>.
Я спробував підпроцес, і виконання було успішним. Однак <b> не міг спілкуватися з <a>. Все нормально, коли я запускаю обоє з терміналу.
Ще одне: (ПРИМІТКА: kwrite поводиться відрізняється від інших програм. Якщо ви спробуєте нижче з Firefox, результати не будуть однаковими.)
Якщо ви спробуєте os.system("kwrite")
, потік програми заморожується, поки користувач не закриє kwrite. Щоб подолати це, я намагався замість цього os.system(konsole -e kwrite)
. Цього разу програма продовжувала текти, але kwrite став підпроцесом консолі.
Будь-який запуск kwrite не є підпроцесом (тобто на системному моніторі він повинен з’являтися в крайньому лівому краю дерева).
os.system
не дозволяє зберігати результати, тому якщо ви хочете зберегти результати в якомусь списку чи щось подібне, це subprocess.call
працює.
Я схильний використовувати підпроцес разом із 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}'"
У 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
Під Linux, у випадку, якщо ви хочете викликати зовнішню команду, яка буде виконуватися незалежно (продовжуватиметься після закінчення сценарію python), ви можете використовувати просту чергу в якості спілера задач або в команді at
Приклад із спілером завдань:
import os
os.system('ts <your-command>')
Примітки про спілера завдань ( ts
):
Ви можете встановити кількість одночасних процесів, які слід запустити ("слоти") за допомогою:
ts -S <number-of-slots>
Встановлення ts
не вимагає прав адміністратора. Ви можете завантажити і компілювати його з джерела просто make
, додати його у свій шлях і все закінчено.
ts
не є стандартним для будь-якого дистрибутива, про який я знаю, хоча вказівник на at
це корисно. Напевно, ви також повинні згадати batch
. Як і в інших місцях, os.system()
рекомендація, мабуть, повинна принаймні згадувати, що subprocess
це її рекомендована заміна.
Ви можете використовувати Popen, а потім можете перевірити стан процедури:
from subprocess import Popen
proc = Popen(['ls', '-l'])
if proc.poll() is None:
proc.kill()
Перевірте підпроцес . Відкрийте .
Щоб отримати мережевий ідентифікатор з нейтрона 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)
Вихід нового 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
os.popen()
в 2016 році. Сценарій Awk можна було легко замінити нативним кодом Python.
echo $PATH
, використовуючиcall(["echo", "$PATH"])
, але це просто перегукується з буквальним рядком$PATH
замість того, щоб робити будь-яку заміну. Я знаю, що міг би отримати змінну середовища PATH, але мені цікаво, чи існує простий спосіб змусити команду вести себе точно так, як ніби я її виконав у bash.