
نواصل التعامل مع لغة البرمجة جوليا. نظرًا لأنه من الضروري ببساطة أن يكون لديك طريقة تشغيل مجمعة للغة تركز على تحليل البيانات ومعالجتها ، فكر في ميزات تنفيذ البرامج النصية بلغة جوليا وتمرير الحجج من سطر الأوامر إليهم. قد يبدو هذا الموضوع مبتذلًا لشخص ما ، ولكن بالنظر إلى حداثة اللغة ، آمل أن تظل نظرة عامة صغيرة على طرق تحليل الحجج والمكتبات الخاصة بسطر الأوامر لهذا الموضوع ، المقدمة في جوليا ، مفيدة.
بادئ ذي بدء ، بضع كلمات حول كيفية عمل البرنامج النصي. يبدأ أي نص برمجي بخط بتنسيق خاص يشير إلى المترجم. يبدأ الخط بتسلسل يعرف باسم Shebang. بالنسبة لجوليا ، هذا الخط هو:
#!/usr/bin/env julia
بالطبع ، لا يمكنك القيام بذلك ، ولكن عليك بعد ذلك تشغيل البرنامج النصي باستخدام الأمر:
julia .jl
أيضًا ، يجب أن ينتهي أي برنامج نصي بحرف سطر جديد. هذا أحد متطلبات معيار POSIX ، والذي يتبع تعريف السلسلة كتسلسل من الأحرف التي تم إنهاؤها بحرف سطر جديد.
لكي يتم تشغيل البرنامج النصي مباشرة ، يجب أن يكون له السمة executable
. يمكنك إضافة مثل هذه السمة في النهاية الطرفية باستخدام الأمر:
chmod +x .jl
هذه القواعد صالحة لجميع أنظمة التشغيل الحديثة ، ربما باستثناء نظام Windows.
صفيف ARGS
دعنا ننتقل إلى الخيار الأول لتمرير المعلمات. تتوفر وسيطات سطر الأوامر في البرنامج النصي Julia من خلال ثابت الصفيف Base.ARGS. دعونا نجهز أبسط برنامج نصي:
#!/usr/bin/env julia @show typeof(ARGS) @show ARGS
يطبع هذا البرنامج النصي ببساطة إلى وحدة التحكم نوع ومحتويات مصفوفة ARGS.
في كثير من الأحيان ، يتم تمرير اسم الملف كوسيطة سطر الأوامر. وهنا توجد خصوصية في معالجة قالب ملف تم تمريره كوسيطة. على سبيل المثال ، قم بتشغيل برنامجنا النصي باستخدام الأمر ./args.jl *.jl
واحصل على:
>./args.jl *.jl typeof(ARGS) = Array{String,1} ARGS = ["argparse.jl", "args.jl", "docopt.jl"]
والآن دعنا نغير معلمة سطر الأوامر قليلاً ، ونحيط القناع بعلامات اقتباس:
./args.jl "*.jl"
. نتيجة لذلك ، نحصل على:
>./args.jl "*.jl" typeof(ARGS) = Array{String,1} ARGS = ["*.jl"]
نرى الفرق الواضح. في الحالة الأولى ، حصلنا على مصفوفة بأسماء جميع الملفات الموجودة في نفس الدليل. في الحالة الثانية ، هذا هو نفس القناع الذي تم تمريره كوسيطة لسطر الأوامر. والسبب في هذا السلوك المختلف للنص البرمجي هو أن مترجم bash (بالإضافة إلى المقربين منه) ، الذي تم تشغيل البرنامج النصي منه ، يتعرف على قوالب اسم الملف. يمكن العثور على المزيد في محرك البحث لـ "Bash Pattern Matching" أو "Bash Wildcards". وكلها تسمى غلوبس.
من بين القوالب ، من الممكن إخفاء عدة أحرف - * ، إخفاء حرف واحد -؟ .. البحث حسب النطاق [...] ، وحتى القدرة على تحديد تركيبات معقدة:
>./args.jl {args,doc}* typeof(ARGS) = Array{String,1} ARGS = ["args.jl", "docopt.jl"]
راجع ملخص أدوات سطر الأوامر GNU / Linux لمزيد من المعلومات.
إذا لم نرغب ، لسبب ما ، في استخدام آلية globs التي يوفرها bash ، فيمكنك العثور على الملفات بواسطة القناع بالفعل من البرنامج النصي باستخدام حزمة Globs.jl.
يعمل الكود التالي على تحويل كل شيء موجود في سلسلة الوسيطة إلى صفيف واحد من أسماء الملفات. أي ، بغض النظر عما إذا كان المستخدم قد حدد القناع في علامات الاقتباس ، بدون علامات اقتباس ، أو ببساطة سرد أسماء الملفات الموجودة أو غير الموجودة ، ستبقى فقط أسماء الملفات أو الأدلة الفعلية في صفيف قائمة الملفات الناتج.
using Glob filelist = unique(collect(Iterators.flatten(map(arg -> glob(arg), ARGS))))
هذه الأمثلة البسيطة ، في الواقع ، هي دليل على استخدام مصفوفة ARGS ، حيث يقوم المبرمج بتنفيذ كل منطق تحليل الحجج. غالبًا ما يستخدم هذا النهج عندما تكون مجموعة الحجج بسيطة للغاية. على سبيل المثال ، قائمة بأسماء الملفات. أو خيار أو خيارين يمكن معالجتهما بعمليات سلسلة بسيطة. الوصول إلى عناصر ARGS هو نفسه بالنسبة لعناصر أي مصفوفة أخرى. تذكر فقط أن فهرس العنصر الأول للصفيف في جوليا هو 1.
حزمة ArgParse.jl
إنها أداة مرنة لوصف سمات وخيارات سطر الأوامر دون الحاجة إلى تنفيذ منطق التحليل.
سنستخدم مثالًا معدلاً قليلاً من وثائق الحزمة - http://carlobaldassi.imtqy.com/ArgParse.jl/stable/ :
#!/usr/bin/env julia using ArgParse function parse_commandline() s = ArgParseSettings() @add_arg_table s begin "--opt1" help = "an option with an argument" "--opt2", "-o" help = "another option with an argument" arg_type = Int default = 0 "--flag1" help = "an option without argument, ie a flag" action = :store_true "arg1" help = "a positional argument" required = true end return parse_args(s) end function main() @show parsed_args = parse_commandline() println("Parsed args:") for (arg,val) in parsed_args print(" $arg => ") show(val) println() end end main()
إذا قمنا بتشغيل هذا البرنامج النصي دون الحجج ، نحصل على إخراج المعلومات المرجعية على تكوينها:
>./argparse.jl required argument arg1 was not provided usage: argparse.jl [--opt1 OPT1] [-o OPT2] [--flag1] arg1
علاوة على ذلك ، بين قوسين معقوفين نرى الحجج الاختيارية. في حين أن الحجة التي تم وضع علامة عليها كـ arg1
(أي ما نستبدلها) إلزامية.
قم بتشغيله مرة أخرى ، ولكن حدد السمة المطلوبة arg1
.
>./argparse.jl test parsed_args = parse_commandline() = Dict{String,Any}("flag1"=>false,"arg1"=>"test","opt1"=>nothing,"opt2"=>0) Parsed args: flag1 => false arg1 => "test" opt1 => nothing opt2 => 0
يمكننا أن نرى أن parsed_args
عبارة عن مصفوفة parsed_args
، حيث تكون المفاتيح هي أسماء السمات وفقًا للإعلان الذي تم parse_commandline
دالة parse_commandline
، وقيمها هي ما تم تعيينه افتراضيًا أو تمريره كقيم وسيطات سطر الأوامر. علاوة على ذلك ، فإن القيم من النوع المحدد صراحة أثناء الإعلان.
يتم تعريف @add_arg_table
باستخدام الماكرو @add_arg_table
. من الممكن إعلان الخيارات:
"--opt2", "-o" help = "another option with an argument" arg_type = Int default = 0
أو الحجج
"arg1" help = "a positional argument" required = true
علاوة على ذلك ، يمكن تحديد خيارات تشير إلى الشكل الكامل والقصير (في نفس الوقت --opt2
و -o
). أو فقط في شكل واحد. النوع محدد في المجال arg_type
. يمكن تعيين القيمة default = ...
باستخدام default = ...
بديل للقيمة الافتراضية هو طلب وسيطة - required = true
.
من الممكن الإعلان عن إجراء تلقائي ، على سبيل المثال ، تعيين true
أو false
اعتمادًا على وجود أو عدم وجود وسيطة. يتم ذلك باستخدام action = :store_true
"--flag1" help = "an option without argument, ie a flag" action = :store_true
يحتوي حقل help
على النص الذي سيتم عرضه في الموجه في سطر الأوامر.
إذا حددنا عند بدء التشغيل جميع السمات ، نحصل على:
>./argparse.jl --opt1 "2+2" --opt2 "4" somearg --flag parsed_args = parse_commandline() = Dict{String,Any}("flag1"=>true,"arg1"=>"somearg","opt1"=>"2+2","opt2"=>4) Parsed args: flag1 => true arg1 => "somearg" opt1 => "2+2" opt2 => 4
للتصحيح من Atom / Juno IDE ، في الأسطر الأولى من البرنامج النصي ، يمكنك إضافة ما يلي ، إلى حد ما ، قذر ، ولكن رمز العمل لتهيئة مصفوفة ARGS.
if (Base.source_path() != Base.basename(@__FILE__)) vcat(Base.ARGS, ["--opt1", "2+2", "--opt2", "4", "somearg", "--flag"] ) end
@__FILE__
هو اسم الملف الذي يتم نشر الماكرو فيه. وهذا الاسم لـ REPL يختلف عن اسم ملف البرنامج الحالي الذي تم الحصول عليه من خلال Base.source_path()
. من المستحيل تهيئة Base.ARGS
الصفيف Base.ARGS
بقيمة مختلفة ، ولكن في نفس الوقت ، يمكنك إضافة خطوط جديدة ، لأن الصفيف نفسه ليس ثابتًا. المصفوفة هي عمود لـ Julia ، لذلك نستخدم vcat
(سلسلة عمودية).
ومع ذلك ، في إعدادات محرر Juno ، يمكنك تعيين الحجج لتشغيل البرنامج النصي. ولكن يجب تغييرها في كل مرة لكل نص برمجي تم تصحيحه بشكل فردي.
حزمة DocOpt.jl
هذا الخيار هو تطبيق نهج لغة ترميز docopt - http://docopt.org/ . الفكرة الرئيسية لهذه اللغة هي الوصف التعريفي للخيارات والحجج في شكل ، والتي يمكن أن تكون أيضًا وصفًا داخليًا للنص. يتم استخدام لغة قالب خاص.
سنستخدم مثال من وثائق هذه الحزمة https://github.com/docopt/DocOpt.jl
#!/usr/bin/env julia doc = """Naval Fate. Usage: naval_fate.jl ship new <name>... naval_fate.jl ship <name> move <x> <y> [--speed=<kn>] naval_fate.jl ship shoot <x> <y> naval_fate.jl mine (set|remove) <x> <y> [--moored|--drifting] naval_fate.jl -h | --help naval_fate.jl --version Options: -h --help Show this screen. --version Show version. --speed=<kn> Speed in knots [default: 10]. --moored Moored (anchored) mine. --drifting Drifting mine. """ using DocOpt # import docopt function args = docopt(doc, version=v"2.0.0") @show args
تدوين doc = ...
هو إنشاء سلسلة Julia doc
التي تحتوي على تعريف docopt بالكامل. ستكون نتيجة التشغيل على سطر الأوامر بدون وسيطات:
>./docopt.jl Usage: naval_fate.jl ship new <name>... naval_fate.jl ship <name> move <x> <y> [--speed=<kn>] naval_fate.jl ship shoot <x> <y> naval_fate.jl mine (set|remove) <x> <y> [--moored|--drifting] naval_fate.jl -h | --help naval_fate.jl --version
إذا استخدمنا التلميح وحاولنا "إنشاء سفينة جديدة" ، نحصل على نسخة مطبوعة من مجموعة args
الترابطية ، والتي تم إنشاؤها بواسطة نتيجة تحليل سطر الأوامر
>./docopt.jl ship new Bystriy args = Dict{String,Any}( "remove"=>false, "--help"=>false, "<name>"=>["Bystriy"], "--drifting"=>false, "mine"=>false, "move"=>false, "--version"=>false, "--moored"=>false, "<x>"=>nothing, "ship"=>true, "new"=>true, "shoot"=>false, "set"=>false, "<y>"=>nothing, "--speed"=>"10")
تم docopt
وظيفة docopt
النحو التالي:
docopt(doc::AbstractString, argv=ARGS; help=true, version=nothing, options_first=false, exit_on_error=true)
help
الوسيطات المسماة ، version
، oprtions_first
، exit_on_error
سلوك محلل أمر الوسيطة بشكل افتراضي. على سبيل المثال ، في حالة وجود أخطاء - لإكمال التنفيذ ، بناء على طلب الإصدار ، قم بإرجاع القيمة version=…
استبدالها هنا ، بناءً على الطلب -h
- بإصدار المساعدة. options_first
تُستخدم للإشارة إلى أنه يجب أن تكون الخيارات قبل الحجج الموضعية.
الآن ، دعونا نلقي نظرة فاحصة على هذه اللغة التعريفية ورد فعل المحلل اللغوي للقيم المدخلة.
يبدأ الإعلان بنص تعسفي ، والذي ، بالإضافة إلى نص سطر الأوامر ، يمكن أن يكون جزءًا من توثيق البرنامج النصي نفسه. تعلن كلمة الخدمة "Usage:" أنماط الاستخدام لهذا البرنامج النصي.
Usage: naval_fate.jl ship new <name>... naval_fate.jl ship <name> move <x> <y> [--speed=<kn>]
يتم تعريف الوسيطات في النموذج <name>
، <x>
، <y>
. لاحظ أنه في الصفيف النقابي args
الذي تم الحصول عليه سابقًا ، تعمل هذه الحجج كمفاتيح. استخدمنا نموذج الإطلاق. / ./docopt.jl ship new Bystriy
، لذلك حصلنا على القيم المبدئية التالية بشكل صريح:
"<name>"=>["Bystriy"], "ship"=>true, "new"=>true,
وفقًا للغة docopt ، يتم تحديد العناصر الاختيارية بين قوسين مربعين. على سبيل المثال [--speed=<kn>]
. العناصر الإلزامية محددة بين قوسين ، ولكن بشرط معين. على سبيل المثال (set|remove)
تحدد المتطلبات لأحدها. إذا تم تحديد العنصر بدون أقواس ، على سبيل المثال naval_fate.jl --version
، فيقول أنه في خيار التشغيل هذا ، - --version
هو خيار مطلوب.
القسم التالي هو قسم وصف الخيار. يبدأ بكلمة "خيارات:"
يتم الإعلان عن الخيارات في سطر منفصل. الحشو على يسار بداية الخط مهم. لكل خيار ، يمكنك تحديد النموذج الكامل والقصير. وكذلك وصف الخيار المعروض في تلميح الأداة. في هذه الحالة ، الخيارات -h | --help, --version
-h | --help, --version
التعرف على -h | --help, --version
تلقائيًا. يتم الرد عليها من خلال الحجج للدالة docopt
. من المثير للاهتمام النظر في الإعلان:
--speed=<kn> Speed in knots [default: 10].
هنا النموذج ...=<kn>
يحدد وجود بعض القيمة ، و [default: 10]
يحدد القيمة الافتراضية. ننتقل مرة أخرى إلى القيم التي تم الحصول عليها في args
:
"--speed"=>"10"
الفرق الأساسي ، على سبيل المثال ، من حزمة ArgParse ، هو أن القيم ليست مكتوبة. بمعنى ، القيمة default: 10
يتم تعيين القيمة default: 10
كسلسلة "10".
أما الحجج الأخرى ، التي يتم تقديمها في args
نتيجة تحليل الحجج ، يجب الانتباه إلى قيمها:
"remove"=>false, "--help"=>false, "--drifting"=>false, "mine"=>false, "move"=>false, "--version"=>false, "--moored"=>false, "<x>"=>nothing, "shoot"=>false, "set"=>false, "<y>"=>nothing,
أي أن جميع عناصر القالب المحددة في إعلان docopt لجميع حالات الاستخدام معروضة تمامًا نتيجة للتحليل باستخدام الأسماء الأصلية. جميع الحجج الاختيارية التي لم تكن موجودة في سطر الأوامر خاطئة هنا. الوسائط <x>
و <y>
مفقودة أيضًا من سطر التشغيل ولا تحتوي على قيمة أي شيء. تلقى الحجج الأخرى التي يطابقها نمط التحليل القيم الحقيقية:
"ship"=>true, "new"=>true,
وقد حصلنا بالفعل على قيم محددة للعناصر التالية في النموذج:
"<name>"=>["Bystriy"], "--speed"=>"10"
تم تعيين القيمة الأولى بشكل صريح في سطر الأوامر كبديل للوسيطة ، والثانية خيار بقيمة افتراضية.
لاحظ أيضًا أنه يمكن حساب اسم البرنامج النصي الحالي تلقائيًا.
على سبيل المثال ، يمكننا إدخال:
doc = """Naval Fate. Usage: $(Base.basename(@__FILE__)) ship new <name>… """
هناك توصية إضافية لوضع محلل وسيطة سطر الأوامر وهي وضعها في بداية الملف. ميزة غير سارة لجوليا في الوقت الحالي هي اتصال طويل إلى حد ما للوحدات النمطية. على سبيل المثال using Plots; using DataFrames
using Plots; using DataFrames
يمكن إرسال برنامج نصي للانتظار لبضع ثوان. هذه ليست مشكلة بالنسبة إلى البرامج النصية من جانب الخادم ، أحادية التحميل ، ولكنها ستزعج المستخدمين الذين يريدون فقط رؤية تلميح لوسيطات سطر الأوامر. لهذا السبب ، تحتاج أولاً إلى إصدار المساعدة والتحقق من وسيطات سطر الأوامر ، وبعد ذلك فقط ، انتقل إلى تنزيل المكتبات اللازمة للعمل.
الخلاصة
لا تدعي المقالة النظر في جميع طرق تحليل الحجج في جوليا. ومع ذلك ، فإن الخيارات المدروسة ، في الواقع ، تغطي 3 خيارات ممكنة. تحليل يدوي كامل لمجموعة ARGS
. تم الإعلان عن الحجج بدقة ولكن تم تحليلها تلقائيًا في ArgParse. وشكل إعلاني بالكامل ، وإن لم يكن صارمًا ، من docopt. يعتمد اختيار حالة الاستخدام بالكامل على مدى تعقيد الحجج اللغوية. يبدو أن خيار استخدام docopt هو الأسهل للاستخدام ، على الرغم من أنه يتطلب تحويل نوع صريح لقيم الوسائط التي تم تلقيها. ومع ذلك ، إذا لم يقبل البرنامج النصي أي شيء بخلاف اسم الملف ، فمن الممكن تمامًا الاستفادة من إصدار المساعدة عليه باستخدام وظيفة ARGS
println("Run me with file name")
المعتادة ، وتحليل أسماء الملفات مباشرة من ARGS
كما هو موضح في القسم الأول.
المراجع