python استدعاء أمر خارجي في بايثون





15 Answers

فيما يلي ملخص لطرق استدعاء البرامج الخارجية ومزايا وعيوب كل منها:

  1. os.system("some_command with args") بتمرير الأوامر os.system("some_command with args") إلى shell الخاص بالنظام. هذا أمر جيد لأنه يمكنك بالفعل تشغيل أوامر متعددة في وقت واحد بهذه الطريقة وإعداد الأنابيب وإعادة توجيه الإدخال / الإخراج. فمثلا:

    os.system("some_command < input_file | another_command > output_file")  
    

    ومع ذلك ، في حين أن هذا مناسب ، عليك أن تتعامل يدويًا مع أحرف shell من الفواصل ، مثل المساحات ، إلخ. ومن ناحية أخرى ، يتيح لك هذا أيضًا تشغيل الأوامر التي هي ببساطة أوامر shell وليس في الواقع برامج خارجية. انظر الوثائق .

  2. stream = os.popen("some_command with args") سوف يفعل نفس الشيء مثل os.system إلا أنه يعطيك كائن يشبه الملف الذي يمكنك استخدامه للوصول إلى الإدخال / الإخراج القياسي لهذه العملية. هناك 3 أنواع أخرى من popen التي تعالج جميع i / o بشكل مختلف قليلاً. إذا قمت بتمرير كل شيء كسلسلة ، فسيتم تمرير الأمر إلى shell ؛ إذا قمت بتمريرها كقائمة ، فلا داعي للقلق بشأن الهروب من أي شيء. انظر الوثائق .

  3. فئة Popen من الوحدة النمطية Popen . هذا هو المقصود كبديل لـ os.popen ولكن له جانب سلبي من كونه أكثر تعقيدًا بقليل بسبب كونه شاملاً للغاية. على سبيل المثال ، يمكنك قول:

    print subprocess.Popen("echo Hello World", shell=True, stdout=subprocess.PIPE).stdout.read()
    

    بدلا من:

    print os.popen("echo Hello World").read()
    

    ولكن من الجيد أن يكون لديك جميع الخيارات في صف واحد موحّد بدلاً من 4 وظائف بوبينية مختلفة. انظر الوثائق .

  4. وظيفة call من الوحدة subprocess . هذا في الأساس تمامًا مثل فئة Popen ويأخذ كل الوسيطات نفسها ، ولكنه ببساطة ينتظر حتى يكمل الأمر ويعطيك رمز الإرجاع. فمثلا:

    return_code = subprocess.call("echo Hello World", shell=True)  
    

    انظر الوثائق .

  5. إذا كنت تستخدم Python 3.5 أو ما بعده ، فيمكنك استخدام الدالة subprocess.run الجديدة ، والتي تشبه إلى حد كبير ما ورد أعلاه ولكنها أكثر مرونة CompletedProcess كائن CompletedProcess عند انتهاء الأمر.

  6. تشتمل وحدة نظام التشغيل أيضًا على جميع وظائف fork / exec / spawn التي لديك في برنامج C ، ولكن لا أنصح باستخدامها بشكل مباشر.

ربما يجب أن تكون وحدة العمليات subprocess هي ما تستخدمه.

وأخيرًا ، يُرجى الانتباه إلى أنه بالنسبة إلى جميع الطرق التي يتم فيها تمرير الأمر النهائي ليتم تنفيذه بواسطة shell كسلسلة ، فأنت مسؤول عن الفرار منه. هناك تداعيات أمنية خطيرة إذا كان أي جزء من السلسلة التي تمررها لا يمكن الوثوق به تمامًا. على سبيل المثال ، إذا كان المستخدم يدخل بعض / أي جزء من السلسلة. إذا كنت غير متأكد ، استخدم هذه الطرق فقط مع الثوابت. لإعطائك تلميحًا للآثار المترتبة على هذا الرمز:

print subprocess.Popen("echo %s " % user_input, stdout=PIPE).stdout.read()

وتخيل أن المستخدم يدخل "ماما لم تحبني && rm -rf /".

python shell command subprocess external

كيف يمكنني الاتصال بأمر خارجي (كما لو كنت اكتبه في shell Unix أو موجه أوامر Windows) من خلال نص برمجي Python؟




بعض التلميحات حول فصل عملية الطفل عن الاتصال (بدء عملية الطفل في الخلفية).

لنفترض أنك تريد بدء مهمة طويلة من نص CGI ، أي أن عملية الطفل يجب أن تعيش لفترة أطول من عملية تنفيذ CGI - script.

المثال الكلاسيكي من مستندات وحدة المعالجة الفرعية هو:

import subprocess
import sys

# some code here

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

# some more code here

الفكرة هنا هي أنك لا تريد الانتظار في السطر "استدعاء subprocess" حتى تنتهي longtask.py. ولكن ليس من الواضح ما الذي يحدث بعد السطر "المزيد من الشفرات هنا" من المثال.

كان النظام الأساسي المستهدف هو freebsd ، ولكن كان التطوير على النوافذ ، لذلك واجهت المشكلة على النوافذ أولاً.

على النوافذ (win xp) ، لن تنتهي العملية الأصل حتى تنتهي longtask.py من عملها. ليس ما تريد في السيناريو CGI. المشكلة ليست خاصة بيثون ، في مجتمع 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.27eryksun في تعليق أدناه ملاحظات ، أن العلامة الصحيحة لغويًا هي CREATE_NEW_CONSOLE (0x00000010) * /

على freebsd لدينا مشكلة أخرى: عند الانتهاء من العملية الأم ، فإنه ينتهي من عمليات الطفل كذلك. وهذا ليس ما تريد في السيناريو CGI أما. أظهرت بعض التجارب أن المشكلة كانت في مشاركة sys.stdout. وكان حل العمل هو التالي:

pid = subprocess.Popen([sys.executable, "longtask.py"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)

لم تتحقق من الشفرة على منصات أخرى ولا أعرف أسباب السلوك على فري بي. إذا كان أي شخص يعرف ، يرجى مشاركة أفكارك. غوغلينغ على بدء عمليات الخلفية في بايثون لا يلقي أي ضوء حتى الآن.




أنصحك باستخدام وحدة المعالجة الفرعية بدلاً من os.system لأنها لا تفلت من قوتك وبالتالي فهي أكثر أمانًا: http://docs.python.org/library/subprocess.html

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



أستخدم دائمًا fabric لهذه الأشياء مثل:

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

ولكن يبدو أن هذا هو أداة جيدة: sh (واجهة بايثون subprocess) .

انظر على سبيل المثال:

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



هناك الكثير من المكتبات المختلفة التي تسمح لك باستدعاء الأوامر الخارجية مع بايثون. لكل مكتبة قدمت وصفًا وعرضت مثالًا للاتصال بأمر خارجي. الأمر الذي استخدمته كمثال هو ls -l (سرد كافة الملفات). إذا كنت ترغب في معرفة المزيد عن أي من المكتبات التي قمت بإدراجها وقمت بربط الوثائق الخاصة بكل منها.

مصادر:

هذه كلها مكتبات:

نأمل أن يساعدك هذا في اتخاذ قرار بشأن المكتبة التي تستخدمها :)

فرعي أو جانبي

Subprocess يسمح لك باستدعاء الأوامر الخارجية وتوصيلها إلى أنابيب الإدخال / الإخراج / الخطأ (stdin و stdout و stderr). Subprocess هو الخيار الافتراضي لتشغيل الأوامر ، لكن أحيانًا تكون الوحدات النمطية الأخرى أفضل.

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 (ملاحظة: هناك أيضا subprocess.popen). سيعمل نظام التشغيل دائمًا مع shell وهو بديل بسيط للأشخاص الذين لا يحتاجون إلى ذلك ، أو لا يعرفون كيفية استخدام 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

plumbum هي مكتبة لبرامج Python "مثل البرامج النصية". يمكنك استدعاء برامج مثل وظائف كما هو الحال في sh . Plumbum مفيد إذا كنت ترغب في تشغيل خط أنابيب دون قذيفة.

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

pexpect

يتيح لك pexpect إنتاج تطبيقات الطفل والتحكم فيها والبحث عن أنماط في إنتاجها. هذا هو بديل أفضل للعملية الفرعية للأوامر التي تتوقع tty على يونكس.

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. يسمح لك بتنفيذ أوامر shell المحلية والبعيدة. النسيج هو بديل بسيط لتشغيل الأوامر في قشرة آمنة (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 نظرًا لأن os.popen هي بديل أفضل.

اعتمد التعديل على تعليق JF Sebastian.




هذه هي الطريقة التي أدير بها الأوامر. يحتوي هذا الرمز على كل ما تحتاج إليه كثيرًا

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 السابقة. إنها أكثر اتساقًا وتوفر سهولة استخدام مماثلة للمبعوث. (لا يعد وضع الأنابيب أمرًا بسيطًا على الرغم من ذلك. انظر هذا السؤال لمعرفة كيفية القيام بذلك ).

إليك بعض الأمثلة من المستندات .

قم بتشغيل عملية:

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

الجواب الأصلي:

أوصي المحاولة https://github.com/kennethreitz/envoy . وهو عبارة عن غلاف للمعالجة الثانوية ، والذي يهدف بدوره إلى استبدال الوحدات والوظائف القديمة. المبعوث هو عملية فرعية للبشر.

استخدام مثال من الملف التمهيدي :

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






هناك أيضا 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 = "your command"
os.system(cmd)



subprocess.check_callمناسب إذا كنت لا تريد اختبار قيم الإرجاع. يلقي استثناء على أي خطأ.




os.systemلا يسمح لك بتخزين النتائج ، لذلك إذا كنت تريد تخزين النتائج في بعض القوائم أو أي شيء subprocess.callيعمل.




قابس خزي ، كتبت مكتبة لهذا: P https://github.com/houqp/shell.py

انها في الاساس مجمع ل popen و shlex في الوقت الحالي. كما أنه يدعم أوامر الأنابيب حتى تتمكن من سلسلة الأوامر أسهل في بايثون. حتى تتمكن من القيام بأشياء مثل:

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



أنا أحب تماما 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



في نظام التشغيل Windows يمكنك فقط استيراد subprocessوحدة وتشغيل الأوامر الخارجية من خلال الدعوة subprocess.Popen()، subprocess.Popen().communicate()و subprocess.Popen().wait()على النحو التالي:

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

انتاج:

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



Related