التابع Process.spawn في روبي

من موسوعة حسوب
< Ruby‏ | Process

يُنفِّذ التابع spawn أمرًا محدَّدًا ثم يعيد مُعرِّف العملية الخاصة به.

البنية العامة

spawn([env,] command... [,options])  pid
spawn([env,] command... [,options])  pid

يشبه التابعُ spawn التابعَ system باستثناء أنّه لا ينتظر إلى أن ينتهي تنفيذ الأمر.

يجب على العملية الأب (parent process) أن تستخدم التابع Process.wait لتحصيل حالة الإنهاء للعملية الفرعية، أو تستخدم Process.detach للإبلاغ بعدم الاهتمام بحالتها؛ خلاف ذلك، قد يُراكم نظام التشغيل عمليات ميتة (zombie processes).

التابع spawn لديه مجموعة من الخيارات لتحديد خاصيات العملية:

env: hash
name => val يضبط متغيرات البيئة.
name => nil يلغي ضبط متغيرات البيئة.
ينبغي تكون المفاتيح والقيم سلاسل نصية باستثناء nil.
...command
commandline تعليمة نصية تُمرر إلى الصدفة القياسية.
... ,cmdname, arg1 تعليمة وواحد أو أكثر من الوسائط (هذا الشكل لا يستخدم الصدفة).
‎[cmdname, argv0], arg1, ...‎ تعليمة والوسيط argv[0]‎ ووسيط واحد أو أكثر.
ptions: hash
مسح متغيرات البيئة (clearing environment variables)
unsetenv_others => true: مسح متغيرات البيئة باستثناء المحددة من قبل env.
unsetenv_others => false: عدم مسح المتغيرات (الخيار الافتراضي).
process group: (مجموعة العمليات)
pgroup => true or 0: إنشاء مجموعة عمليات جديدة.
pgroup => pgid: الانضمام إلى مجموعة العمليات المحددة.
pgroup => nil: عدم تغيير مجموعة العمليات (الافتراضي).
إنشاء مجموعة عمليات جديدة: ويندوز فقط
new_pgroup => true: العملية الجديدة هي العملية الأصل لمجموعة عمليات جديدة.
new_pgroup => false: عدم إنشاء مجموعة عمليات جديدة (الافتراضي).
اسم المورد (resourcename): هو نواة (core)، معالج (cpu)، بيانات، ...إلخ. انظر التابع Process.setrlimit.
‎:rlimit_resourcename => limit
‎:rlimit_resourcename => [cur_limit, max_limit]‎
umask:
umask => int:
إعادة التوجيه (redirection):
  • المفتاح (key):
FD واصف ملف واحد في العملية الفرعية.
[FD, FD, ...‎] واصفات ملف متعددة في العملية الفرعية.
  • القيمة (value):
FD يعيد التوجيه إلى واصف الملف في العملية الأب.
string يعيد التوجيه إلى الملف مع open(string, "r" or "w"‎)‎.
[string] يعيد التوجيه إلى الملف مع open(string, File::RDONLY)‎.
[string, open_mode] يعيد التوجيه إلى الملف مع open(string, open_mode, 0644)‎.
[string, open_mode, perm] يعيد التوجيه إلى الملف مع open(string, open_mode, perm)‎.
[child, FD:] يعيد التوجيه إلى واصف الملف المعاد توجيهه.
close: يغلق واصف الملف في العملية الفرعية.
واصف الملف FD هو أحد القيم التالية:
in: واصف الملف رقم 0 والذي هو الدخل القياسي.
out: واصف الملف رقم 1 والذي هو الخرج القياسي.
err: واصف الملف رقم 2 والذي هو مجرى الخطأ القياسي.
integer واصف الملف ذو العدد الصحيح المحدد.
io واصف الملف io.fileno.
وراثة واصف الملف: أغلق واصفات الملفات غير الموجَّهة وغير القياسية (مثل 3، و 4، و 5، ...إلخ.) أو لا.
close_others => true: لا تستعمل الواصفات الموروثة.
المجلد الحالي:
chdir => str:
 لا يستخدم الشكل 'cmdname, arg1, ...‎' الصدفة. لكن في بعض أنظمة التشغيل، يتم توفير أوامر مدمجة (built-in) مثل "echo"، المُدمج في ويندوز ، خلافًا للأنظمة لينكس وماك التي يعد فيها أمرًا طبيعيًّا. وهذا يعني أن `Process.spawn 'echo', '%Path%'‎` سيعرض محتويات متغير البيئة `%Path%` على ويندوز، لكن `Process.spawn 'echo', '$PATH'‎` سيطبع '‎$PATH‎' حرفيًّا.

إن كانت القيمة المعطاة للمعامل env جدولًا من النوع Hash، فسيتم تحديث البيئة بواسطة env قبل تنفيذ exec(2)‎ في العملية الفرعية. إن كان لأحد مدخلات المعامل env القيمة nil، فسيُحذَف ذلك المتغير.

# set FOO as BAR and unset BAZ.
pid = spawn({"FOO"=>"BAR", "BAZ"=>nil}, command)

إن كانت القيمة المعطاة للمعامل options جدولًا من النوع Hash، فسيُحدِّد مجموعة العمليات (process group)، وينشئ مجموعة عمليات جديدة، ويحدد الموارد، والمجلد الحالي، ويقوم بتقنيع (umask) وإعادة توجيه العملية الفرعية. ويمكن أيضًا ضبطها لمحو متغيرات البيئة. المفتاح ‎:unsetenv_others في options يؤدي إلى محو متغيرات البيئة فضلًا عن تلك المحددة بواسطة env.

pid = spawn(command, :unsetenv_others=>true) # no environment variable
pid = spawn({"FOO"=>"BAR"}, command, :unsetenv_others=>true) # FOO only

يحدد المفتاح ‎:pgroup في الخيارات options مجموعة العملية. يجب أن تساوي القيمة المقابلة true، أو صفرًا، أو عددًا صحيحًا موجبًا، أو القيمة nil. القيمتان true والصفر 0 تجعلان العملية عمليةً قائدةً (process leader) لمجموعة عمليات جديدة. عدد صحيح موجب غير معدوم سيجعل العملية تنضم إلى مجموعة العمليات المعطاة. أما القيمة الافتراضية nil، فستُبقي العملية في نفس مجموعة العمليات.

pid = spawn(command, :pgroup=>true) # process leader
pid = spawn(command, :pgroup=>10) # belongs to the process group 10

المفتاح ‎:new_pgroup في الخيارات options يؤدي إلى تمرير الراية CREATE_NEW_PROCESS_GROUP إلى CreateProcessW()‎، والتي هي واجهة برمجية في أنظمة ويندوز (Windows API). هذا الخيار متاح فقط لنظام التشغيل ويندوز. القيمة true تعني أن العملية الجديدة ستكون العملية الأب لمجموعة العمليات الجديدة. يتم تعطيل CTRL + C في العملية الجديدة. هذه الراية ضرورية للتابع Process.kill(:SIGINT,pid)‎ في العملية الفرعية. قيمة new_pgroup: تساوي false افتراضيًا.

pid = spawn(command, :new_pgroup=>true)  # new process group
pid = spawn(command, :new_pgroup=>false) # same process group

يحدِّد المفتاح ‎:rlimit_foo حدود الموارد. ويجب أن تكون foo إحدى أنواع الموارد مثل core. كما يجب أن تكون القيمة المقابلة إما عددًا صحيحًا، أو مصفوفةً تحتوي على عدد أوعددين صحيحين مثل الوسيطين cur_limit و max_limit في Process.setrlimit.

cur, max = Process.getrlimit(:CORE)
pid = spawn(command, :rlimit_core=>[0,max]) # disable core temporary.
pid = spawn(command, :rlimit_core=>max) # enable core dump
pid = spawn(command, :rlimit_core=>0) # never dump core.

يحدد المفتاح ‎:umask في الخيارات options التقنيع (umask).

pid = spawn(command, :umask=>077)

يحدِّد المفتاح ‎:in و out: و err: و integer و io والمصفوفة إعادة توجيه. تحدد إعادة التوجيه واصف ملف (file descriptor) في العملية الابن. على سبيل المثال، يمكن دمج stderr في stdout كما يلي:

pid = spawn(command, :err=>:out)
pid = spawn(command, 2=>1)
pid = spawn(command, STDERR=>:out)
pid = spawn(command, STDERR=>STDOUT)

تحدد مفاتيح الجدول Hash واصف الملف في العملية الفرعية التي بدأها spawn. أمَّا err:، و 2، و STDERR فيعيّنان مجرى الخطأ القياسي (stderr).

تعيّن قيم الجدول Hash واصف ملف في العملية الأب، والتي تستدعي spawn. أما out: و 1 و STDOUT فتحدد مجرى الخرج القياسي (stdout).

في المثال أعلاه، لم يُحدّد مجرى الخرج القياسي في العملية الفرعية. لذلك فهو يرثها من العملية الأب.

يمكن تحديد مجرى الدخل القياسي (stdin) بوساطة in: و 0 و STDIN.

يمكن تحديد اسم ملف كقيمة في الجدول Hash.

pid = spawn(command, :in=>"/dev/null") # read mode
pid = spawn(command, :out=>"/dev/null") # write mode
pid = spawn(command, :err=>"log") # write mode
pid = spawn(command, [:out, :err]=>"/dev/null") # write mode
pid = spawn(command, 3=>"/dev/null") # read mode

بالنسبة إلى stdout و stderr (أو مزيج منهما) ، يتم فتحهما في وضع الكتابة. وإلا فسيُعتمَد وضع القراءة. لتحديد رايات وأذونات إنشاء الملفات بشكل صريح، يمكن استخدام مصفوفة.

pid = spawn(command, :in=>["file"]) # read mode is assumed
pid = spawn(command, :in=>["file", "r"])
pid = spawn(command, :out=>["log", "w"]) # 0644 assumed
pid = spawn(command, :out=>["log", "w", 0600])
pid = spawn(command, :out=>["log", File::WRONLY|File::EXCL|File::CREAT, 0600])

تحدد المصفوفة اسم الملف والرايات والأذونات. الرايات قد تكون سلاسل نصية أو أعدادًا صحيحةً. إذا حُذفَت الرايات أو كانت قيمتها nil، فستُستعمَل القيمة File::RDONLY الافتراضية. يجب أن يكون الإذن عددًا صحيحًا. إذا تم حذف الإذن أو كان يساوي nil، فسيتم اعتماد القيمة 0644 الافتراضية. إذا تم تحديد مصفوفة من كائنات IO ومن الأعداد الصحيحة كمفتاح للجدول Hash، فسيتم إعادة توجيه جميع العناصر.

# stdout and stderr is redirected to log file.
# The file "log" is opened just once.
pid = spawn(command, [:out, :err]=>["log", "w"])

هناك طريقة أخرى لدمج عدة واصفات ملفات وهي [‎:child، fd]. والتي تعني واصف الملف في العملية الفرعية. وهو مختلف عن fd. على سبيل المثال، تعني err =>:out إعادة توجيه المجرى stderr للعملية الفرعية إلى المجرى stdout للعملية الأب. ولكن ‎:err => [:child،:out]‎ تعني إعادة توجيه المجرى stderr للعملية الفرعية إلى المجرى stdout للعملية الفرعية نفسها، إذ سيكونان مختلفين إذا أُعيد توجيه المجرى stdout في العملية الفرعية على النحو التالي:

# stdout and stderr is redirected to log file.
# The file "log" is opened just once.
pid = spawn(command, :out=>["log", "w"], :err=>[:child, :out])

يمكن استخدام [‎:child، :out] لدمج المجرى stderr في المجرى stdout في IO.popen. في هذه الحالة، يعيد IO.popen توجيه المجرى stdout إلى أنبوب (pipe) في العملية الفرعية، إذ تشير [‎:child ، :out] إلى المجرى stdout المعاد توجيهه.

io = IO.popen(["sh", "-c", "echo out; echo err >&2", :err=>[:child, :out]])
p io.read #=> "out\nerr\n"

يحدد المفتاح ‎:chdir في options المجلد الحالي.

pid = spawn(command, :chdir=>"/var/tmp")

تغلق spawn افتراضيًّا جميع الواصفات غير المحددة وغير القياسية. الواصفات "القياسية" هي 0 و 1 و 2. يتم تحديد هذا السلوك بواسطة الخيار ‎:close_others. الخيار ‎:close_others لا يؤثر على الواصفات القياسية التي يتم إغلاقها إلا في حالة تم تحديد :close بشكل صريح.

pid = spawn(command, :close_others=>true)  # close 3,4,5,... (default)
pid = spawn(command, :close_others=>false) # don't close 3,4,5,...

قيمة ‎:close_others تساوي true بشكل افتراضي، بالنسبة للتابع spawn و IO.popen. لاحظ أن واصفات الملفات التي تم تعيين الراية close-on-exec لها ستُغلق بغض النظر عن الخيار close_others. لذلك يمكن استخدام التابع IO.pipe والتابع spawn مثل التابع IO.popen.

# similar to r = IO.popen(command)
r, w = IO.pipe
pid = spawn(command, :out=>w)   # r, w is closed in the child process.
w.close

يتم تحديد close: كقيمة في الجدول Hash لإغلاق واصف ملف بشكل فردي.

f = open(foo)
system(command, f=>:close)        # don't inherit f.

إذا كانت هناك حاجة إلى توريث واصف الملف، فيمكن استخدام io => io.

# valgrind has --log-fd option for log destination.
# log_w=>log_w indicates log_w.fileno inherits to child process.
log_r, log_w = IO.pipe
pid = spawn("valgrind", "--log-fd=#{log_w.fileno}", "echo", "a", log_w=>log_w)
log_w.close
p log_r.read

من الممكن أيضًا تبادل واصفات الملفات.

pid = spawn(command, :out=>:err, :err=>:out)

تحدِّد مفاتيح الجدول Hash واصفات الملفات في العملية الفرعية بينما تحدِّد قيم الجدول Hash واصفات الملفات في العملية الأب. بناءً على ذلك، يحدد المثال أعلاه تبادل المَجرّيين stdout و stderr. داخليًا، يستخدم spawn واصف ملف إضافي لحل هذا التعيين الدوري لواصفات الملفات.

راجع صفحة التابع exec لأجل لمزيد من المعلومات حول الصدفة (shell) القياسية.

المعاملات

env‎

بيئة التنفيذ.

command...‎

الأمر المراد تنفيذها.

options‎

خيارات إضافية للتحكم بالعملية.

القيمة المعادة

يعاد معرف العملية المنفذة (pid).

أمثلة

مثال على استعمال التابع spawn:

pid = spawn("tar xf ruby-2.0.0-p195.tar.bz2")
Process.wait pid

pid = spawn(RbConfig.ruby, "-eputs'Hello, world!'")
Process.wait pid

انظر أيضًا

  • التابع detach: يمنع سلوك الاحتفاظ بالعمليات الفرعية المنهية التي تنتظر أن تُجمع حالتها من العملية الأب عبر ضبط خيط منفصل من روبي وظيفته الوحيدة هي جمع الحالة لمعرف العملية (pid) عندما تُنهَى.
  • التابع exec: يستبدل العملية الحالية عبر تشغيل الأمر الخارجي المعطى.
  • التابع fork: ينشئ عملية فرعية.
  • التابع kill: يرسل إشارة محدَّدة إلى عملية ذات مُعرِّف معطى أو إلى جميع العمليات التي معرِّف المجموعة التي تملكه مساويًا إلى معرِّف المجموعة للعملية المستدعية.
  • التابع system: ينفذ التعليمة المعطاة في صدفة فرعية (subshell).

مصادر