تحتاج أحيانًا إلى أن يشغّل برنامج بايثون أمرًا من أوامر النظام، أو يفتح برنامجًا خارجيًا، أو ينفذ أداة مثل git أو ffmpeg ثم يقرأ النتيجة ويتعامل مع نجاح الأمر أو فشله. الطريقة الحديثة والمباشرة لهذه المهمة هي مكتبة subprocess المدمجة مع بايثون، وبالأخص الدالة subprocess.run().
في هذا الدرس سنبدأ بأبسط مثال يعمل على Windows وLinux وmacOS، ثم ننتقل إلى التقاط stdout وstderr، واستخدام check=True وtimeout، وتشغيل CMD وPowerShell وأوامر Linux، ثم نختم بالفرق بين shell=False وshell=True ولماذا يؤثر ذلك في الأمان.
الخلاصة السريعة: إذا أردت تشغيل برنامج خارجي وانتظار انتهائه، فابدأ عادةً بـ subprocess.run() ومرّر الأمر كقائمة مثل ["program", "arg"]. استخدم capture_output=True لقراءة المخرجات، وtext=True للحصول عليها كنص، وcheck=True لتحويل فشل الأمر إلى Exception واضحة.
حمّل كود المشروع الكامل، وملفات runner.py وapp.py، والاختبارات التلقائية؛ وجرّب أمثلة subprocess.run() وstdout وstderr وtimeout بنفسك.
هذا الدرس مناسب لسلسلة بايثون بعد الأساسيات. إذا كان هدفك مختلفًا وتريد تشغيل ملف .py يدويًا من CMD أو PowerShell، فراجع دليل تشغيل ملف Python من CMD وTerminal وVS Code. هنا سنفعل العكس: برنامج Python هو الذي سيشغّل أمرًا أو برنامجًا خارجيًا.
ما هي مكتبة subprocess في بايثون؟
مكتبة subprocess جزء من المكتبة القياسية في بايثون، لذلك لا تحتاج إلى تثبيتها عبر pip. وظيفتها إنشاء Processes جديدة، والاتصال بمدخلاتها ومخرجاتها وأخطاءها، والحصول على رمز الخروج return code.
توصي وثائق Python الحالية باستخدام subprocess.run() للحالات التي تستطيع التعامل معها، والانتقال إلى Popen عندما تحتاج تحكمًا أكثر تقدمًا في Process طويلة التشغيل أو تدفق المخرجات أثناء التنفيذ.
المرجع الرسمي: Python Documentation — subprocess.
ملاحظة مهمة: subprocess تعتمد على تشغيل Processes حقيقية في نظام التشغيل. وفق توثيق Python فهي غير مدعومة على Android وiOS وWASI، ولذلك لا تتوقع أن تعمل بالطريقة نفسها داخل بعض بيئات Python التي تعمل في المتصفح أو WebAssembly. إذا كنت تجرب أمثلة بسيطة أونلاين، راجع تشغيل بايثون أونلاين بدون تثبيت لمعرفة حدود بيئات المتصفح.
أول مثال: تشغيل أمر من بايثون باستخدام subprocess.run
بدل الاعتماد على أمر يختلف بين Windows وLinux، سنستخدم مفسر Python الحالي نفسه. يوفر sys.executable مسار المفسر الذي يشغل السكربت الآن:
import subprocess
import sys
result = subprocess.run(
[sys.executable, "--version"]
)
print("Return code:", result.returncode)
قد ترى الناتج هكذا:
Python 3.15.2
Return code: 0
رقم 0 يعني عادةً أن البرنامج الخارجي انتهى بنجاح. أما الرقم غير الصفري فيشير عادةً إلى أن الأمر فشل أو انتهى بحالة خطأ يحددها البرنامج الذي شغلته.
لماذا نمرر الأمر كقائمة بدل String؟
الأسلوب المفضل في الحالات العادية هو تمرير اسم البرنامج وكل Argument كعنصر منفصل:
subprocess.run(
[sys.executable, "-c", "print('Hello from child process')"]
)
هنا العناصر الثلاثة واضحة:
sys.executable: البرنامج الذي سنشغله.-c: خيار يطلب من Python تنفيذ نص كود.print(...): القيمة التي سيستقبلها الخيار.
هذا الأسلوب يقلل الحاجة إلى تفسير Shell للنص، ويجعل التعامل مع Arguments التي تحتوي مسافات أكثر وضوحًا. توصي وثائق Popen بتمرير args كسلسلة من القيم ما لم تكن لديك حاجة محددة إلى String.
ما الذي تعيده subprocess.run؟ شرح CompletedProcess
لا تعيد run() مجرد True أو False. إنها تعيد كائنًا من النوع CompletedProcess يحتوي معلومات عن الأمر بعد انتهائه.
import subprocess
import sys
result = subprocess.run(
[sys.executable, "-c", "print('done')"]
)
print(type(result).__name__)
print(result.args)
print(result.returncode)
أهم الخصائص التي سنستخدمها في المقال:
| الخاصية | ماذا تحتوي؟ |
|---|---|
args | الأمر وArguments التي شُغلت. |
returncode | رمز خروج العملية. |
stdout | الناتج القياسي إذا طلبت التقاطه. |
stderr | رسائل الخطأ القياسية إذا طلبت التقاطها. |
التقاط مخرجات الأمر باستخدام capture_output=True
في الأمثلة السابقة خرجت النتيجة مباشرة إلى Terminal. إذا أردت أن يستخدم برنامجك الناتج، أضف capture_output=True:
import subprocess
import sys
result = subprocess.run(
[
sys.executable,
"-c",
"print('Arab Python')",
],
capture_output=True,
)
print(result.stdout)
print(result.stderr)
بدون text=True ستكون البيانات الملتقطة عادةً من نوع bytes:
b'Arab Python\n'
b''
استخدام text=True للحصول على String بدل bytes
في معظم البرامج التعليمية والتطبيقات النصية تريد التعامل مع الناتج كسلسلة نصية عادية. أضف text=True:
import subprocess
import sys
result = subprocess.run(
[
sys.executable,
"-c",
"print('Arab Python')",
],
capture_output=True,
text=True,
)
print(result.stdout)
print(type(result.stdout).__name__)
الناتج:
Arab Python
str
الخيار text=True هو الاسم الأكثر وضوحًا للخيار القديم universal_newlines=True. وإذا كنت تحتاج ترميزًا محددًا تستطيع استخدام encoding=... أيضًا.
الفرق بين stdout وstderr
البرنامج الخارجي قد يكتب النتيجة الطبيعية في stdout، ويكتب التشخيص أو الخطأ في stderr. يمكن التقاط الاثنين معًا ثم اتخاذ قرار داخل Python.
import subprocess
import sys
code = (
"import sys; "
"print('normal output'); "
"print('error output', file=sys.stderr)"
)
result = subprocess.run(
[sys.executable, "-c", code],
capture_output=True,
text=True,
)
print("STDOUT:", result.stdout.strip())
print("STDERR:", result.stderr.strip())
الناتج:
STDOUT: normal output
STDERR: error output
هذه النقطة مهمة عند تشغيل أدوات حقيقية: لا تفترض أن كل ما يظهر في Terminal موجود داخل stdout.
فحص returncode بدل افتراض نجاح الأمر
إذا كان check=False — وهو الافتراضي — فلن ترفع run() استثناء لمجرد أن البرنامج أعاد رمزًا غير صفري. لذلك تستطيع فحص returncode بنفسك:
import subprocess
import sys
result = subprocess.run(
[
sys.executable,
"-c",
"raise SystemExit(3)",
]
)
if result.returncode == 0:
print("نجح الأمر")
else:
print("فشل الأمر:", result.returncode)
الناتج:
فشل الأمر: 3
استخدام check=True وCalledProcessError
في كثير من البرامج لا تريد متابعة التنفيذ وكأن كل شيء نجح. عند استخدام check=True ترفع subprocess.run() الخطأ CalledProcessError إذا انتهت العملية برمز غير صفري.
import subprocess
import sys
try:
subprocess.run(
[
sys.executable,
"-c",
"raise SystemExit(3)",
],
check=True,
)
except subprocess.CalledProcessError as error:
print("فشل الأمر")
print("Return code:", error.returncode)
إذا كنت تحتاج مراجعة أساس التعامل مع الاستثناءات، راجع شرح try وexcept والتعامل مع الأخطاء في بايثون.
الحصول على stdout وstderr عند الفشل
ادمج check=True مع capture_output=True وtext=True:
import subprocess
import sys
code = (
"import sys; "
"print('details', file=sys.stderr); "
"raise SystemExit(2)"
)
try:
subprocess.run(
[sys.executable, "-c", code],
capture_output=True,
text=True,
check=True,
)
except subprocess.CalledProcessError as error:
print("code:", error.returncode)
print("stderr:", error.stderr.strip())
منع الأمر من التعليق باستخدام timeout
قد يتوقف برنامج خارجي أو ينتظر موردًا وقتًا طويلًا. ضع حدًا زمنيًا باستخدام timeout:
import subprocess
import sys
try:
subprocess.run(
[
sys.executable,
"-c",
"import time; time.sleep(5)",
],
timeout=1,
)
except subprocess.TimeoutExpired:
print("انتهت المهلة قبل اكتمال الأمر")
عند انتهاء المهلة ترفع الدالة TimeoutExpired. ووفق التوثيق، في run() يتم قتل العملية ثم انتظارها قبل إعادة رفع الاستثناء، مع ملاحظة أن إنشاء Process نفسها قد لا يكون قابلًا للمقاطعة فورًا على بعض منصات النظام.
تشغيل الأمر داخل مجلد معين باستخدام cwd
الخيار cwd يحدد Current Working Directory للعملية الجديدة. المثال التالي يجعل Process الطفل تطبع المجلد الذي تعمل بداخله:
from pathlib import Path
import subprocess
import sys
project_dir = Path.cwd()
result = subprocess.run(
[
sys.executable,
"-c",
"import os; print(os.getcwd())",
],
cwd=project_dir,
capture_output=True,
text=True,
check=True,
)
print(result.stdout.strip())
هذا مفيد عندما تشغل أداة تتوقع ملفات إعداد أو مسارات نسبية داخل مجلد مشروع محدد.
تمرير Environment Variables باستخدام env
إذا مررت env فإنك تحدد بيئة العملية الجديدة بدل الاعتماد مباشرة على الوراثة الافتراضية. في التطبيقات المعتادة، خذ نسخة من os.environ ثم عدّل ما تحتاجه:
import os
import subprocess
import sys
child_env = os.environ.copy()
child_env["APP_MODE"] = "demo"
result = subprocess.run(
[
sys.executable,
"-c",
"import os; print(os.getenv('APP_MODE'))",
],
env=child_env,
capture_output=True,
text=True,
check=True,
)
print(result.stdout.strip())
الناتج:
demo
إذا كانت إعداداتك محفوظة في ملف .env، راجع أيضًا حفظ مفاتيح API باستخدام .env وpython-dotenv. تذكر أن env في subprocess لا يقرأ ملف .env بنفسه؛ أنت تمرر له Mapping للمتغيرات.
إرسال نص إلى stdin باستخدام input
يمكنك تمرير قيمة إلى المدخل القياسي للعملية الجديدة عبر input=.... مع text=True تستطيع إرسال String مباشرة:
import subprocess
import sys
child_code = (
"name = input(); "
"print(name.upper())"
)
result = subprocess.run(
[sys.executable, "-c", child_code],
input="arab python\n",
capture_output=True,
text=True,
check=True,
)
print(result.stdout.strip())
الناتج:
ARAB PYTHON
تشغيل برنامج خارجي من بايثون
الفكرة نفسها لا تقتصر على أوامر النظام. تستطيع تشغيل أي Executable متاح على الجهاز. مثلًا، إذا كان Git مثبتًا:
import subprocess
result = subprocess.run(
["git", "--version"],
capture_output=True,
text=True,
check=True,
)
print(result.stdout.strip())
إذا لم يكن البرنامج موجودًا أو لا يستطيع النظام العثور عليه، فقد تحصل على FileNotFoundError. للتشخيص يمكنك استخدام shutil.which():
from shutil import which
git_path = which("git")
if git_path is None:
print("Git غير موجود في PATH")
else:
print(git_path)
عند تشغيل مفسر Python نفسه من داخل سكربت Python، استخدم sys.executable بدل كتابة python أو python3 عشوائيًا. توثيق subprocess يوصي بهذه الطريقة لأنها تشير إلى المفسر الحالي فعليًا.
تشغيل أوامر CMD من بايثون على Windows
بعض أوامر CMD مثل dir هي أوامر داخلية في Shell وليست ملفات تنفيذية مستقلة. تستطيع تشغيلها بصورة صريحة عبر cmd /c:
import subprocess
result = subprocess.run(
["cmd", "/c", "dir"],
capture_output=True,
text=True,
check=True,
)
print(result.stdout)
هذا المثال مخصص لـWindows. الخيار /c يعني تنفيذ الأمر ثم إنهاء CMD.
تشغيل PowerShell من بايثون
على Windows تستطيع استدعاء Windows PowerShell هكذا:
import subprocess
result = subprocess.run(
[
"powershell",
"-NoProfile",
"-Command",
"Get-Date",
],
capture_output=True,
text=True,
check=True,
)
print(result.stdout.strip())
إذا كنت تستخدم PowerShell 7 فقد يكون اسم البرنامج pwsh بدل powershell. تحقق أولًا من البرنامج المثبت على جهازك.
تشغيل أوامر Linux وmacOS من بايثون
على أنظمة Unix-like تستطيع تشغيل برنامج مستقل مثل uname مباشرة:
import subprocess
result = subprocess.run(
["uname", "-a"],
capture_output=True,
text=True,
check=True,
)
print(result.stdout.strip())
ويمكن تشغيل ls مثلًا:
subprocess.run(
["ls", "-la"],
check=True,
)
هذه الأمثلة ليست متطابقة مع Windows لأن أسماء البرامج والـShell built-ins تختلف حسب النظام.
shell=False مقابل shell=True
القيمة الافتراضية هي shell=False، وهذا يعني أن Python لا يختار Shell تلقائيًا لتفسير النص. في معظم الحالات هذا هو الخيار الذي تبدأ به.
| الحالة | الاختيار الأنسب غالبًا |
|---|---|
| تشغيل برنامج مع Arguments | shell=False وتمرير قائمة. |
| تشغيل Python أو Git أو ffmpeg | shell=False. |
| تحتاج ميزة خاصة بالـShell مثل Pipeline أو Redirection | قد تحتاج shell=True أو بناء Pipeline باستخدام Processes منفصلة. |
| الأمر يحتوي مدخلًا غير موثوق من المستخدم | تجنب تركيب String وتشغيلها بـshell=True. |
مثال shell=True لأمر ثابت وموثوق
import subprocess
subprocess.run(
"echo Hello",
shell=True,
check=True,
)
هذا المثال بسيط، لكن لا تجعل shell=True الخيار الافتراضي لمجرد أنه يسمح بكتابة الأمر كسطر واحد.
لماذا قد يكون shell=True خطرًا؟
عندما تطلب من Shell تفسير نص، تصبح الرموز الخاصة بالـShell ذات معنى. إذا ركبت النص من إدخال غير موثوق فقد يتحول جزء من البيانات إلى Command إضافية.
هذا مثال يجب تجنبه عندما تأتي القيمة من مستخدم:
import subprocess
user_value = input("اكتب اسمًا: ")
subprocess.run(
f"echo {user_value}",
shell=True,
)
الأفضل عندما لا تحتاج ميزات الـShell أن تمرر كل Argument كعنصر مستقل:
import subprocess
user_value = input("اكتب اسمًا: ")
subprocess.run(
["echo", user_value],
check=True,
)
تقول وثائق Python إن subprocess لا تستدعي System Shell ضمنيًا. لكن إذا فعّلت shell=True تصبح مسؤولًا عن التعامل الصحيح مع المسافات والرموز الخاصة لتجنب Shell Injection. توجد تفاصيل إضافية خاصة بملفات .bat و.cmd على Windows، لذلك ارجع إلى قسم Security Considerations في التوثيق عند بناء برنامج يستقبل مدخلات غير موثوقة.
مرجع رسمي: Security Considerations — subprocess.
subprocess.run أم os.system؟
يمكنك رؤية كود قديم أو أمثلة قصيرة تستخدم:
import os
os.system("python --version")
os.system() تشغّل String داخل subshell، وقيمة الإرجاع ذات معنى يعتمد على النظام، كما أن التقاط الناتج والتعامل المنظم مع stdout وstderr وTimeouts أصعب.
في المقابل توفر subprocess.run() واجهة أوضح:
import subprocess
import sys
result = subprocess.run(
[sys.executable, "--version"],
capture_output=True,
text=True,
check=True,
)
print(result.stdout or result.stderr)
ولهذا توضح وثائق Python أن subprocess صممت لاستبدال عدد من الواجهات الأقدم مثل os.system. راجع أيضًا توثيق os.system الرسمي.
subprocess.run أم Popen؟
ابدأ بـrun() عندما تريد تشغيل أمر وانتظار نهايته. انتقل إلى Popen عندما تحتاج إدارة Process بصورة أكثر تقدمًا، مثل قراءة المخرجات أثناء استمرار البرنامج أو التحكم في Process طويلة التشغيل.
| الحاجة | run() | Popen |
|---|---|---|
| تشغيل أمر وانتظار انتهائه | مناسب جدًا | ممكن لكن أكثر تعقيدًا |
| التقاط الناتج بعد النهاية | مباشر | ممكن |
| Timeout بسيط | مباشر | ممكن |
| قراءة Streaming أثناء التشغيل | ليس الاستخدام الأساسي | أنسب |
| تحكم تفصيلي في Process | محدود | أنسب |
مشروع عملي: Safe Command Runner
سنحوّل الأفكار السابقة إلى دالة صغيرة تشغّل Arguments بدون Shell، وتلتقط المخرجات، وتحدد Timeout، وتسمح بتمرير متغيرات بيئة إضافية.
from dataclasses import dataclass
from pathlib import Path
from collections.abc import Mapping, Sequence
import os
import subprocess
@dataclass(slots=True)
class CommandResult:
args: tuple[str, ...]
returncode: int
stdout: str
stderr: str
def run_command(
args: Sequence[str],
*,
timeout: float = 10,
cwd: str | Path | None = None,
env: Mapping[str, str] | None = None,
check: bool = False,
) -> CommandResult:
if isinstance(args, (str, bytes)):
raise TypeError("مرر الأمر كقائمة أو Sequence من النصوص")
child_env = os.environ.copy()
if env:
child_env.update(env)
completed = subprocess.run(
list(args),
capture_output=True,
text=True,
shell=False,
timeout=timeout,
cwd=cwd,
env=child_env,
check=check,
)
return CommandResult(
args=tuple(str(item) for item in completed.args),
returncode=completed.returncode,
stdout=completed.stdout,
stderr=completed.stderr,
)
ثم استخدمها هكذا:
import sys
result = run_command(
[
sys.executable,
"-c",
"print('Hello from subprocess')",
],
check=True,
)
print(result.stdout.strip())
هذه الدالة لا تحاول دعم shell=True أصلًا؛ هدفها أن تكون Wrapper بسيطة للحالات المعتادة والآمنة افتراضيًا. ستجد المشروع الكامل والاختبارات داخل ملف ZIP المرفق مع الدرس.
أخطاء شائعة عند استخدام subprocess
1. كتابة أمر كامل كسلسلة ثم توقع أن يعمل بدون shell=True
الكود التالي لا يعني دائمًا ما تتوقعه:
subprocess.run(
"python --version"
)
عند shell=False الأفضل تمرير Arguments منفصلة:
subprocess.run(
["python", "--version"]
)
ولتشغيل نفس المفسر الحالي بصورة أكثر موثوقية استخدم sys.executable.
2. نسيان capture_output ثم محاولة قراءة stdout
إذا لم تطلب التقاط الناتج، فقد تكون result.stdout تساوي None.
3. استخدام capture_output=True مع stdout أو stderr يدويًا
capture_output=True يضبط stdout وstderr إلى Pipes داخليًا؛ لا تجمعه مع قيم stdout=... أو stderr=... في الاستدعاء نفسه.
4. الاعتماد على returncode بدون فحصه
الأمر قد يفشل بينما يستمر برنامجك إذا بقي check=False. افحص returncode أو استخدم check=True عندما تريد اعتبار الفشل Exception.
5. عدم وضع timeout لأداة قد تعلق
إذا كنت تشغل برنامجًا خارجيًا يمكن أن ينتظر شبكة أو ملفًا أو Input، ضع Timeout مناسبًا وتوقع TimeoutExpired.
6. استخدام shell=True مع مدخل المستخدم
هذه من أهم الأخطاء. إذا لم تكن بحاجة فعلية إلى Shell فلا تستخدمها. وإذا احتجتها، لا تركّب Command من بيانات غير موثوقة دون قواعد escaping مناسبة للنظام.
7. افتراض أن أسماء الأوامر واحدة على كل الأنظمة
dir وcmd مرتبطة بـWindows، بينما ls وuname شائعة في Linux/macOS. اختر أمثلة تناسب النظام أو استخدم برنامجًا مشتركًا مثل sys.executable.
متى تستخدم subprocess في مشروع حقيقي؟
- تشغيل أدوات خارجية مثل Git أو ffmpeg أو أدوات البناء.
- تنفيذ سكربت أو برنامج آخر كجزء من Automation.
- قراءة stdout لاستخراج نتيجة من أداة CLI.
- تشغيل أوامر صيانة أو Build داخل مشروع تطوير.
- دمج برنامج Python مع أدوات نظام موجودة أصلًا.
أما إذا كنت تريد بناء برنامج CLI يستقبل Arguments من المستخدم، فهذا موضوع مختلف؛ راجع بناء برنامج سطر أوامر CLI باستخدام argparse.
ملخص سريع لأهم خيارات subprocess.run
| الخيار | استخدامه |
|---|---|
capture_output=True | التقاط stdout وstderr. |
text=True | التعامل مع Streams كنصوص بدل bytes. |
check=True | رفع CalledProcessError عند رمز خروج غير صفري. |
timeout=... | منع الانتظار غير المحدود. |
cwd=... | تغيير مجلد العمل للعملية الجديدة. |
env=... | تحديد Environment للعملية الجديدة. |
input=... | إرسال بيانات إلى stdin. |
shell=True | تشغيل الأمر عبر Shell عندما تحتاج ميزاتها، مع اعتبارات أمان إضافية. |
مصادر رسمية وروابط مكملة
- Python 3.15 — subprocess documentation
- Python — subprocess Security Considerations
- Python — os.system documentation
- PEP 324 — subprocess
- بايثون العرب — try وexcept والتعامل مع الأخطاء
- بايثون العرب — بناء برنامج CLI باستخدام argparse
- بايثون العرب — .env وEnvironment Variables
الأسئلة الشائعة عن تشغيل أوامر النظام من بايثون
كيف أشغّل أمر نظام من بايثون؟
استخدم subprocess.run() ومرر اسم البرنامج وArguments في قائمة، مثل subprocess.run(["git", "--version"]). للحالات التي تريد فيها نفس مفسر Python الحالي استخدم sys.executable.
كيف أقرأ ناتج الأمر داخل بايثون؟
استخدم capture_output=True لالتقاط stdout وstderr، وأضف text=True إذا أردت Strings بدل bytes.
ما فائدة check=True في subprocess.run؟
تجعل run() ترفع CalledProcessError عندما ينتهي الأمر برمز غير صفري، بدل أن تحتاج إلى فحص returncode يدويًا في كل مرة.
كيف أحدد وقتًا أقصى لتنفيذ الأمر؟
استخدم timeout مثل timeout=5. إذا تجاوزت العملية المهلة ترفع بايثون TimeoutExpired.
ما الفرق بين subprocess.run وos.system؟
subprocess.run() توفر تحكمًا أوضح في Arguments والمخرجات والأخطاء والمهلة والبيئة، بينما os.system() تشغّل String داخل subshell وتملك واجهة أقدم وأقل مرونة لهذه الحالات.
ما الفرق بين subprocess.run وPopen؟
استخدم run() عندما تريد تشغيل أمر وانتظار انتهائه. استخدم Popen عندما تحتاج إدارة Process أثناء استمرارها أو Streaming للمخرجات أو تحكمًا أكثر تقدمًا.
هل shell=True ضروري لتشغيل الأوامر؟
لا. في معظم الحالات تستطيع تشغيل البرنامج مباشرة مع shell=False. تحتاج shell=True فقط عندما تعتمد فعليًا على ميزات Shell، ومعها يجب الانتباه إلى مخاطر Shell Injection.
كيف أشغّل CMD من بايثون؟
على Windows يمكنك تشغيل أمر داخلي في CMD عبر ["cmd", "/c", "الأمر"]. أما البرامج التنفيذية المستقلة فيمكن استدعاؤها مباشرة بدون CMD غالبًا.
كيف أشغّل PowerShell من بايثون؟
شغّل powershell أو pwsh كبرنامج خارجي، ثم مرر -Command والأمر المطلوب ضمن قائمة Arguments.
لماذا يظهر FileNotFoundError عند استخدام subprocess؟
غالبًا لأن البرنامج الذي تحاول تشغيله غير موجود أو غير متاح عبر PATH. استخدم shutil.which() للتحقق، أو مرر مسارًا كاملًا للبرنامج عند الحاجة.
هل تعمل subprocess داخل محرر Python أونلاين؟
ليس بالضرورة. المكتبة تعتمد على قدرة البيئة على إنشاء Processes حقيقية، وهي غير مدعومة في منصات مثل WASI وبعض بيئات الهاتف. لذلك اختبر هذه الأمثلة على Python محلي على نظام تشغيل يدعمها.



