Powershell: استدعاء عامل التشغيل الأصلي

تم إنشاؤها على ٣٠ يونيو ٢٠٢٠  ·  189تعليقات  ·  مصدر: PowerShell/PowerShell

عرض المشكلة

حاليًا ، هناك حالات يفشل فيها قص سطر أوامر أصلي ولصقه كما هو متوقع في PowerShell. قد يكون هذا بسبب التحليل غير الصحيح لعلامات الاقتباس التي من المفترض أن يتم تمريرها إلى الأمر الأصلي أو استخدام صيغة PowerShell التي لا يُقصد تفسيرها على أنها PowerShell. يحتوي PowerShell على وسيطة خاصة --% عند استخدامه مع الأوامر الأصلية ، ويتعامل مع باقي الوسائط على أنها حرفية تم تمريرها إلى الأمر الأصلي ، ولكن بها العديد من المشكلات:

  1. إنه غير قابل للاكتشاف ، يحتاج المستخدمون إلى معرفة هذه المعلمة الخاصة مسبقًا
  2. | ، && ، و || لها الأسبقية ، لذلك: wsl --% ls | less سينفذ wsl ls ويحول النتائج إلى less تشغيل less في wsl
  3. إذا قمت بقص ولصق سطر أوامر ، فستحتاج إلى تحرير السطر لإدراج --% باتجاه البداية
  4. في أنظمة Unix ، يتم تمرير الحروف بعد -٪ حرفيًا بدون تذبذب حيث تتوقع الأوامر الأصلية على Unix أن يقوم shell بأداء globbing

تفاصيل التنفيذ الفني المقترحة

الاقتراح هو تقديم عامل تشغيل جديد (Call Native) --% .

أي محتوى نصي بعد هذا المشغل سوف يستدعي "الغلاف الافتراضي" لنظام التشغيل ليتم تنفيذه. في نظام التشغيل Windows ، سيكون هذا هو cmd.exe وعلى الأنظمة المستندة إلى Unix سيكون / bin / sh. هذا يحل مشكلة globbing على الأنظمة المستندة إلى Unix ، ويسمح أيضًا بتوسيع %variable% على Windows. بخلاف التبديل --% ، فهذا يعني أيضًا أن | و && و || يتم التعامل معها كجزء من سطر الأوامر الأصلي.

هذا يعني أن هذين هما نفس الشيء وظيفيًا:

wsl --% ls $foo `&`& echo $PWD
--% wsl ls $foo && echo $PWD

حيث يتم تقييم $foo و $PWD بواسطة الغلاف داخل WSL. لاحظ أنه في المثال الأول ، يجب أن تعرف الهروب من && لتنفيذه داخل WSL بدلاً من داخل PowerShell.

لإعادة إخراج هذا التنفيذ إلى PowerShell ، يجب على المستخدم تخزين النتائج في متغير أولاً:

$out = --% ls *.txt
$out | select-string hello

لاحظ أنه بخلاف عامل تشغيل المكالمات الحالي & ، لا يمكنك استخدام أي صيغة PowerShell ، لذلك:

--% $commandline

لن يحل $commandline كمتغير أولاً بواسطة PowerShell ، ولكن بدلاً من ذلك ، قم بتمرير $commandline إلى الصدفة الافتراضية للمعالجة دون حل.

يتم حل مشكلة القص واللصق ببساطة عن طريق اللصق بعد كتابة --% .

سيبدو المثال أعلاه لـ wsl كما يلي:

--% wsl ls | less

حيث يكون القصد من تنفيذ هذا السطر بالكامل داخل مثيل WSL Linux.

الاكتشاف

يمكن للمستخدمين المألوفين بالفعل مع --% كمحول الانتقال بسهولة إلى استخدام هذا المشغل الجديد حيث يكون ذلك منطقيًا. بالنسبة للمستخدمين الجدد ، يعد --% فريدًا بحيث تجد محركات البحث أنه مرتبط بسهولة بـ PowerShell.

اعتبارات بديلة

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

هناك سؤال حول دعم استمرار الخط عند استخدام هذا المشغل الجديد. أود أن أقترح أننا لا ندعمها في البداية.

تم اقتراح حل cmdlet بدلاً من حل المشغل. نعتقد أن هذا لا يحل مشكلة "القص واللصق" حيث تحتاج الآن إلى معرفة كيفية وضع خط الأنابيب في علامات اقتباس فردية و / أو الهروب من الأحرف الخاصة. نعتقد أن الأمر cmdlet كما في Invoke-NativeCommand (يتم تحديد الاسم) سيكون مفيدًا كخيار إضافي بدلاً من استبدال الحاجة إلى عامل.

القضايا ذات الصلة

يجب أن يحل هذا أيضًا هذه المشكلات:

https://github.com/PowerShell/PowerShell/issues/12491
https://github.com/PowerShell/PowerSHell/issues/1761

Committee-Reviewed Issue-Discussion Issue-Enhancement

التعليق الأكثر فائدة

لقد قمت للتو بنشر وحدة ، Native ، ( Install-Module Native -Scope CurrentUser ) والتي أدعوكم جميعًا لتجربتها والتي سأستخدم أوامرها أدناه ؛ حالات الاستخدام الرقمية المشار إليها مأخوذة من تعليق أعلاه .

إذا أردنا في أي وقت إزالة الضباب المفاهيمي ، أعتقد أننا بحاجة إلى تأطير حالات الاستخدامات بشكل مختلف.
_ لا أحد منهم يتطلب أي تغييرات في التحليل_.

حالة الاستخدام [استدعاء shell الأصلي]:

تريد تنفيذ _individ command_ (حالة الاستخدام 1) أو سطر أوامر _multi-command بأكمله _ (حالة الاستخدام 2) _ مكتوبًا من أجل shell الأصلي للنظام الأساسي _ (هذه المشكلة):

  • نظرًا لأنك تستخدم صيغة قشرة مختلفة ، فأنت تقوم بتمرير الأمر (سطر) _كسلسلة واحدة_ إلى الصدفة الهدف ، من أجل _it_ لإجراء التحليل ؛ يوفر استيفاء سلسلة PowerShell القدرة على تضمين قيم PowerShell في السلسلة التي تم تمريرها (حالة الاستخدام 2 أ).
  • يغطي ins ( Invoke-NativeShell ) حالات الاستخدامات هذه.
# Use case 1: Single executable call with line continuation, on Unix.
@'
tar -cvpzf /share/Recovery/Snapshots/$(hostname)_$(date +%Y%m%d).tar.gz \
    --exclude=/proc \
    --exclude=/lost+found 
'@ | ins

# Use case 2: Entire Bash command line (also with line continuation)
@'
ps -o pid,args | awk \
  '/pwsh/ { print $1 }'
'@ | ins

# Use case 2a: Entire Bash command line (also with line continuation) with string interpolation.
# Note the double-quoted here-string and the need to escape the $ that is for Bash as `$
$fields = 'pid,args'
@"
ps -o $fields | awk \
  '/pwsh/ { print `$1 }'
"@ | ins

# Alternative to use case 2a: pass the PowerShell value *as a pass-through argument*,
# which allows passing the script verbatim.
# Bash sees the pass-through arguments as $1, ... (note that the `awk` $1 is unrelated).
@'
ps -o $1 | awk \
  '/pwsh/ { print $1 }'
'@ | ins - 'pid,args'

إن بناء الجملة هنا ليس هو الأكثر ملاءمة (ومن هنا جاء اقتراح تنفيذ متغير مضمّن - راجع # 13204) ، لكنك لا تستخدمه ؛ للأوامر الحرفية ، يمكنك استخدام '...' ، والذي يتطلب فقط _doubling_ تضمين ' ، إذا كان موجودًا.

إليك أيضًا بديل معقول لـ "عامل تشغيل StackOverflow" :

إذا قمت بوضع التالية PSReadLine معالج رئيسي في الخاص بك $PROFILE الملف، عليك أن تكون قادرا على استخدام البديل، ضد لسقالة دعوة إلى ins مع حرفيا سلسلة هنا التي يتم لصق نص الحافظة الحالي فيها.أدخل يرسل المكالمة.

# Scaffolds an ins (Invoke-NativeShell) call with a verbatim here-string
# and pastes the text on the clipboard into the here-string.
Set-PSReadLineKeyHandler 'alt+v' -ScriptBlock {
  [Microsoft.PowerShell.PSConsoleReadLine]::Insert("@'`n`n'@ | ins ")
  foreach ($i in 1..10) { [Microsoft.PowerShell.PSConsoleReadLine]::BackwardChar() }
  # Comment the following statement out if you don't want to paste from the clipboard.
  [Microsoft.PowerShell.PSConsoleReadLine]::Insert((Get-Clipboard))
}

حالة الاستخدام [اتصال مباشر قابل للتنفيذ]:

تريد استدعاء ملف تنفيذي خارجي واحد باستخدام صيغة _PowerShell_ ، مع _حجج فردية_ (استخدام حالتي 1 أ و 3).

  • هذا هو التفويض الأساسي لأي قذيفة ، ومن الأهمية بمكان أن تعمل بقوة.

    • يجب أن تكون قادرًا على الاعتماد على قدرة PowerShell على المرور عبر أي وسيطات تنتج من _its_ parsing _as-is_ إلى الهدف القابل للتنفيذ. هذا ليس هو الحال حاليا - انظر # 1995 .
  • يتطلب منك فهم بناء جملة _PowerShell's_ و _its_ الوسيطات الوصفية.

    • يجب أن تدرك أنه يتم استخدام ` كحرف هروب ولمتابعة السطر.
    • يجب أن تدرك أن PowerShell يحتوي على أحرف أولية إضافية تتطلب الاقتباس / الهروب للاستخدام الحرفي ؛ هذه (لاحظ أن @ يمثل مشكلة فقط كأول حرف للحجة.):

      • للأصداف التي تشبه POSIX (على سبيل المثال ، Bash): @ { } `$ ، إذا كنت تريد منع التوسيع المسبق بواسطة PowerShell)
      • مقابل cmd.exe : ( ) @ { } # `
      • بشكل فردي ` -إلغاء مثل هذه الأحرف. يكفي (على سبيل المثال ، printf %s `@list.txt ).

بينما ننتظر رقم 1995 حتى يتم إصلاحه ، تعمل الوظيفة ie (لـ i nvoke (خارجي) e xecutable) على ملء الفراغ ، ببساطة عن طريق إرسال مكالمة مباشرة ؛ على سبيل المثال ، بدلاً من المكالمة التالية:

# This command is currently broken, because the '{ "name": "foo" }' argument isn't properly passed.
curl.exe -u jdoe  'https://api.github.com/user/repos' -d '{ "name": "foo" }'

يمكنك استخدام ما يلي:

# OK, thanks to `ie`
ie curl.exe -u jdoe  'https://api.github.com/user/repos' -d '{ "name": "foo" }'

تأتي الوحدة النمطية Native مع شيء يشبه echoArgs.exe ، الأمر dbea ( Debug-ExecutableArguments ) ؛ عينة الإخراج على Windows:

# Note the missing first argument, the missing " chars., and the erroneous argument boundaries.
PS> dbea '' 'a&b' '3" of snow' 'Nat "King" Cole' 'c:\temp 1\' 'a \" b'
7 argument(s) received (enclosed in <...> for delineation):

  <a&b>
  <3 of snow Nat>
  <King>
  <Cole c:\temp>
  <1\ a>
  <">
  <b>

Command line (helper executable omitted):

  a&b 3" of snow "Nat "King" Cole" "c:\temp 1\\" "a \" b"

باستخدام رمز التبديل -UseIe ( -ie ) ، يمكنك إخبار dbea لتمرير الوسيطات عبر ie ، مما يدل على أنه يحل المشاكل:

# OK, thanks to -UseIe
PS> dbea -UseIe '' 'a&b' '3" of snow' 'Nat "King" Cole' 'c:\temp 1\' 'a \" b'
6 argument(s) received (enclosed in <...> for delineation):

  <>
  <a&b>
  <3" of snow>
  <Nat "King" Cole>
  <c:\temp 1\>
  <a \" b>

Command line (helper executable omitted):

  "" a&b "3\" of snow" "Nat \"King\" Cole" "c:\temp 1\\" "a \\\" b"

ملاحظة: بمجرد إصلاح 1995 # ، لم يعد مطلوبًا ie ؛ من أجل التوافق إلى الأمام ، تم تصميم ie لاكتشاف الإصلاح وتأجيله تلقائيًا ؛ أي بمجرد أن يتم الإصلاح ، سيتوقف ie عن تطبيق الحلول وسيتصرف بشكل فعال مثل مكالمة مباشرة / & .

حالة الاستخدام [استدعاء مباشر قابل للتنفيذ لـ Windows مخادع]:

هناك مشكلتان رئيسيتان تظهران في _Windows فقط_:

  • أنت تستدعي ملف تنفيذي "خادع" له متطلبات اقتباس تختلف عن أكثر الاصطلاحات استخدامًا ؛ على سبيل المثال ، يتطلب الأمر msiexec.exe و msdeploy.exe أن يتم اقتباس prop="<value with spaces>" بهذه الطريقة بالضبط - الاقتباس حول الجزء _value_ - على الرغم من "prop=<value with spaces>" - اقتباس من الكل الحجة - _يجب_ أن تكون متكافئة (هذا الأخير هو ما يفعله PowerShell - بشكل مبرر - وراء الكواليس).

  • أنت تستدعي _ ملف دفعي _ مع _ وسيطة لا تحتوي على مسافات ، ولكنها تحتوي على أحرف أولية cmd.exe مثل & أو ^ أو | ؛ على سبيل المثال:

    • .\someBatchFile.cmd 'http://example.org/a&b'
    • PowerShell - بشكل مبرر - يمرر http://example.org/a&b _unquoted_ (نظرًا لعدم وجود مسافة بيضاء مضمنة) ، لكن هذا يكسر استدعاء ملف الدُفعات ، لأن cmd.exe - بشكل غير معقول - تخضع الوسائط التي تم تمريرها إلى ملف دفعي إلى نفس حكم الإعراب الذي سيتم تطبيقه داخل cmd.exe بدلاً من قبولها كحرفية.

    • ملاحظة: أثناء استخدام الملفات الدفعية _directly_ للتنفيذ الوظيفي ربما يتضاءل ، فإن استخدامها كنقاط إدخال CLI لا يزال شائعًا جدًا ، مثل Azure az CLI ، والذي يتم تنفيذه كملف دفعي az.cmd .

ملاحظة: يتعامل ie تلقائيًا مع هذه السيناريوهات لملفات الدُفعات و msiexec.exe و msdeploy.exe ، لذلك لن تكون هناك حاجة لبذل جهد إضافي للمكالمات _ most_ ؛ ومع ذلك ، من المستحيل توقع _all_ الملفات التنفيذية "المارقة".

هناك طريقتان لحل هذا:

  • بالنظر إلى أن cmd.exe ، بعد تطبيق تفسيره الخاص على الوسيطات في سطر الأوامر ، _ يفعل_ الاحتفاظ بالاقتباس كما هو محدد ، يمكنك التفويض إلى ins call على Windows:

    • ins '.\someBatchFile.cmd "http://example.org/a&b"'
    • إذا كنت تستخدم سلسلة _expandable_ ، فهذا يمكّنك مرة أخرى من تضمين قيم PowerShell في سلسلة الأوامر.

      • $url = 'http://example.org/a&b'; ins ".\someBatchFile.cmd `"$url`""

  • بدلاً من ذلك ، استخدم التنفيذ الحالي --% ، لكن احذر من حدوده:

    • .\someBatchFile.cmd --% "http://example.org/a&b"'
    • بالنظر إلى كيفية تنفيذ --% ، فإن الطريقة الوحيدة لتضمين قيم PowerShell هي - بشكل محرج - تحديد _aux. متغير البيئة_ وقم بالرجوع إليها باستخدام بناء الجملة %...% :

      • $env:url = 'http://example.org/a&b'; .\someBatchFile.cmd --% "%url%"


معالجة الأخطاء

سيؤدي https://github.com/PowerShell/PowerShell-RFC/pull/88 المعلق إلى تكامل أفضل لمعالجة الأخطاء مع الملفات التنفيذية الخارجية (الأصلية).

في غضون ذلك ، تأتي الوحدة النمطية Native مع ميزتين للاشتراك المخصص للتعامل مع

  • ins يدعم -e / -ErrorOnFailure التبديل، الذي يلقي خطأ إذا $LASTEXITCODE هو غير صفرية بعد استدعاء قذيفة الأم.

  • iee هي دالة مجمعة لـ ie والتي تتسبب في حدوث خطأ بشكل مماثل إذا كان $LASTEXITCODE غير صفري بعد استدعاء الملف التنفيذي الخارجي.

هناك العديد من التفاصيل الدقيقة للأوامر التي تأتي مع الوحدة النمطية.
نأمل أن تغطي المساعدة المستندة إلى التعليقات الشاملة إلى حد ما هذه المعلومات بشكل كافٍ.

ال 189 كومينتر

تعجبني الفكرة وأجدها مفيدة ، لكنني أعتقد أنها ستكون أكثر فائدة (أفكر تحديدًا في حالة DSL) إذا كان بإمكاني الحصول على توسعة سلسلة واحدة. لذلك إذا قمت بإنشاء سلسلة متوافقة مع cmd.exe في PS الخاص بي ، فلدي طريقة لربطها حرفياً بـ cmd.exe. ربما

&n -command $string

من المحتمل أن يسمح لي ذلك أيضًا بتحديد المترجم الفوري الخاص بي:

&n -shell /bin/sh -command $string
أو
&n -shell cmd.exe -command $string

من حيث الاسم / المشغل ، هو "&!" في الاستخدام؟ هذا يشبه shbang ("#!").

$! اقتراح جيد!

يمكن تحديد الغلاف ببساطة عن طريق تحديده كأمر:

&! /bin/sh -c blah

يخلق التوسيع $var مشكلة في أن $ قد يحتاج إلى أن يكون حرفيًا ليتم تمريره إلى الأمر / shell الأصلي. إحدى المشاكل التي يحاول هذا تجنبها هي عندما يحتاج الناس إلى معرفة كيفية الهروب من كل شيء بشكل صحيح. إذا كنت تريد توسيعًا متغيرًا ، فيمكنك دائمًا القيام بما يلي:

$mycommand = "/bin/sh ls"
Invoke-Expression "&! $mycommand"

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

$mycommand = "/bin/sh ls"
Invoke-Expression "&! $mycommand"

لا أصدق أنك اقترحت للتو iex. :-)

essentialexch هناك عدة مرات حيث يكون ذلك مناسبًا :)

لاحظ أنه في المثال ، التوقع هو أن المستخدم قام بالتحقق من صحة محتويات $mycommand قبل التنفيذ!

هناك حاجة بالتأكيد إلى كتابة رائعة وحل لمشكلات مثل تلك التي وصفتها.
لم أكن أعرف بنفسي شيئًا عن --% ولا أتذكر رؤيته لسوء الحظ. لذلك فإن عامل التشغيل المقترح &n قد يعاني من مشاكل اكتشاف مماثلة ولا يبدو من الطبيعي بالنسبة لي أن أجمع بين رمز وحرف (وهذا يذكرني بـ٪ f في عبارات C printf). نظرًا لأنه تغيير مفاجئ على أي حال ، فهل هناك سبب لعدم إمكانية حدوثه على سبيل المثال && ؟
ربما سيكون من البديهي استخدام شيء مثل الأقواس (أو الأقواس المزدوجة؟) لتمييز المنطقة التي تريد تنفيذها. مثال: & [ wsl ls ] | less

أوافق على أن &! هي الطريقة الأكثر بديهية التي يجب اتباعها لأولئك القادمين من قذائف أخرى ، ولكن في super-duper-linter ، عادةً ما أقوم بتشغيل أوامر أصلية عن طريق بناء مصفوفة معلمات ثم توزيعها على الأمر.

$command = 'linter'
$myargs = @(
    '-config'
    'linterconfig.path'
)
if ($Test) {$myargs += 'test'}
& $command <strong i="7">@myargs</strong>

لذا فهذه هي أفضل طريقة في حالة الشرط وغير ذلك بالنسبة لي

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

JustinGrote ، ليس هناك سبب لعدم الاستمرار في استخدام ذلك. إن بناء الجملة &! هو حقًا للحالات التي تريد فيها فقط القص واللصق أو الحصول على بعض الوسائط التي تتعارض مع بنية PowerShell ولا تريد أو لا تعرف كيفية الهروب بشكل صحيح

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

# run ls in wsl, return results to powershell, then pipe to wsl again, to grep.
& wsl ls | wsl grep -i "foo"  

#  the entire pipeline right of wsl will run in wsl. 
& --% wsl ls | grep -i "foo"

لماذا لم يقترح أحد هذا؟ يتوافق منطقيًا مع استخدام --% أي مكان آخر لقول "كل شيء بعد ذلك يتم تمريره بدون معالجة خاصة."

oising well for one ، هذا الأمر لا يعمل لأنه عليك أن
image

هذا النوع يفعل ما هو متوقع:
function Invoke-LiteralCommand ($command) {Invoke-Expression "& $command --% $args"}

Invoke-LiteralCommand ping -W 200 www.google.com | grep icmp

JustinGrote نعم ، أعلم أنها لا تعمل الآن :) أقترح أن _ بدلاً من &n أو &! أو أي شيء آخر يتم الحديث عنه. يبدو الأمر أكثر منطقية بالنسبة لي: & هو اتصال و --% هو منع تحليل بوويرشيل ؛ معًا تكون متماسكة وقابلة للاكتشاف أكثر من إضافة شيء جديد. لا أحب فكرة وجود عامل تشغيل "مكالمة" و "اتصال محلي".

لقد وسعت المثال الخاص بي لإظهار الاختلافات.

oising سأكون رائعًا مع ذلك على عامل جديد ، على الرغم من أن هذا كثير من الكتابة المنفصلة لـ "مستخدم powerhell جديد يعرف bash" وهو ما أفترض أن هذا يعنيه.

oising سأكون رائعًا مع ذلك على عامل جديد ، على الرغم من أن هذا كثير من الكتابة المنفصلة لـ "مستخدم powerhell جديد يعرف bash" وهو ما أفترض أن هذا يعنيه.

على الاطلاق. إنه لمستخدم PowerShell الذي لا يفهم قواعد الاقتباس المعقدة بين PowerShell / cmd.exe / bash. كما يقول عنوان المشكلة "اتصل بالمواطنين" ، لاستدعاء الملفات التنفيذية الأصلية.

oising سأكون رائعًا مع ذلك على عامل جديد ، على الرغم من أن هذا كثير من الكتابة المنفصلة لـ "مستخدم powerhell جديد يعرف bash" وهو ما أفترض أن هذا يعنيه.

على الاطلاق. إنه لمستخدم PowerShell الذي لا يفهم قواعد الاقتباس المعقدة بين PowerShell / cmd.exe / bash. كما يقول عنوان المشكلة "اتصل بالمواطنين" ، لاستدعاء الملفات التنفيذية الأصلية.

صحيح ، أو لأولئك منا الذين يفضلون عدم التفكير فيهم على الإطلاق.

نعم أنا معoising. هذا المفهوم موجود ، إنه غير كافٍ بشكل مؤسف. إذا أردنا تنفيذ شيء جديد تمامًا ، فمن الأفضل إهمال / إزالة الصيغة القديمة.

أشعر في كثير من الأحيان أن هذه الأفكار يتم التعبير عنها ، لا يتم إعطاء وزن كافٍ للهدف الديموغرافي الفعلي المستهدف. إذا كان المستخدمون _already_ تكافح للعثور على الطرق القائمة، وإيجاد الطرق الحالية تفتقر عندما وجدوا، انها دعوة لأ) تحسين وثائق، وب) تحسين وظائف الفعلية للمشغلين الحاليين.

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

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

السؤال الأول الذي أميل إلى طرحه عندما يدرك الناس أن هناك 5 طرق لفعل شيء ما هو "لماذا توجد طريقتان أو ثلاث طرق تفعل الشيء نفسه حرفيًا ولكنها لا تعمل بشكل جيد" ، وإجابتي كما كانت دائمًا - - يركز فريق PS _way_ بشكل كبير على التأكد من أن كل شيء من العقد الماضي ++ لا يزال يعمل ، عند محاولة إضافة / تحسين الوظائف. هنا نراه مرة أخرى ، لدينا تطبيقات قائمة ولكن غير كافية وتحتاج إلى مراجعة وتحسين ، والحل المقترح هو زيادة تعكير المجموعة عن طريق إضافة تنفيذ آخر يحتمل أن يكون غير مكتمل.

يجب أن ننهي ما بدأناه ، وليس البدء في تطبيق آخر من جديد ، المنظمة البحرية الدولية.

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

آخر شيء أريده هو الارتباك حول ما هو المقصود القيام به. في مجمله.

كنت أفكر في 3 سيناريوهات:

  1. التوسع الكامل - سلوك PowerShell الحالي.
  2. حرفية كاملة - التي تم اقتراحها في OP.
  3. التوسيع الجزئي - لا يزال يعمل wsl ls $path

أتساءل أين تعليق @ mklement0 ؟ :-)

في بداية قراءة هذا الموضوع فكرت ؛ فكرة عظيمة! لكن بعد قراءة التعليقات ، بدأت أفكر. لقد وجدت دائمًا أن & الأمر "ليست معايير PS جديرة" وشيء يذكرني بـ "أيام PERL" (لاف). لن يساعد تقديم أمر PS آخر غير قياسي (لا يكون فعلًا اسميًا). بالتأكيد ليس هؤلاء أقل ذكاءً في ملاحظة.

لم أكن أعرف أيضًا عن المعلمة -٪. أستخدم نفس مبدأ JustinGrote كحل.

لم يكن قص / لصق أوامر PS shell "الشيء" الرئيسي بالنسبة لي.
ألن نكون أفضل من استبدال تلك الأوامر الأصلية بـ PowerShell؟
اصنع مسارًا لاستبدال cmd.exe بالكامل ...

أنا أصوت لاستكشاف تحسين الأوامر الموجودة. و - بالفعل - تحسين بعض الوثائق حول -٪ والاستخدام

iSazonov ، حالة الاستخدام التي يقترحها @ SteveL-MSFT هي سيناريو "قص لصق". التوسيع الجزئي سيجعل الأمور أكثر صعوبة على ما أعتقد (من ناحية AST من الأشياء)

على الفور على الرغم من "#!" وثم "!#". إعجاب "&!".

ربما يمكننا النظر في إضافة مسرعات الرمز المميز لاستدعاءات الوظائف في الرمز المميز. سيسمح هذا باستخدام ما يلي.

Iex -l
أو استدعاء Expression -literal التي تتوقف عن الإعراب قبل أن تفوت.

أشعر أن إضافة المزيد من الرموز المميزة الفريدة على مستوى الإعراب يجعل حاجز الدخول يرتفع وتنخفض قابلية الاكتشاف لهذه الميزة.

Get-Help & على سبيل المثال لا تظهر مع أي شيء. وعلينا أن نبحث عنه في about_Operators.

ومع ذلك ، هناك حالات فريدة لـ call_operator لا يتم توثيقها
& اسم النموذج {أمر}
يسمح لك بالنطاق في وحدة نمطية. وأنا متأكد من أن هناك المزيد. لكن قابلية الاكتشاف فيه منخفضة للغاية بحيث يصعب العثور عليها في الوثائق الأصلية. والمجتمع يعرف ذلك فقط من خلال JSnover والحديث الذي قدمه ليطلعنا على أشياء رائعة.

أعتقد أن كل ما يتم تحديده يجب أن يأخذ في الاعتبار تمامًا مدى قابلية اكتشاف هذه "الميزة" ، من منظور مستخدم جديد وتذكر أن المستخدمين الجدد سيحاولون استخدام هذا على Powershell 5 ليس بدون معرفة جوهره الجديد إذا قابلية الاكتشاف منخفضة جدًا.

أرغب في تغيير السلوك الحالي ، لكن تغيير واجهة برمجة التطبيقات الأساسية في PowerShell سيؤدي إلى كسر الكثير من الأشياء. ربما يمكننا التفكير في الترحيل باستخدام تكوين.

ربما كان من الممكن كسر الأشياء بشكل أكثر مباشرة قبل أن يذهب PS 6 إلى GA ، ولكن بصراحة ، حتى ذلك الحين ، كان يمكن أن يمثل تهديدًا خطيرًا للتوافق مع الإصدارات السابقة (على عكس وظيفة Python print() ).

فيما يتعلق بتمرير الحجج إلى العمليات الفرعية ، أعتقد أن كل من الاستدعاء المتزامن واستدعاء Start-Process يحتويان بالفعل على مشكلات طوابق تناقش الإصلاح الشامل ، وأشعر أن كلاهما يحتاج إلى الاستثمار في وقت واحد لتحقيق الاتساق. يحتاج Start-Process على وجه الخصوص إلى تحديث دعمه لتمرير مجموعة من الحجج.

للاستدعاء المتزامن مع تمرير cmdline arg ، أرى أربعة أنواع من الحجج التي تمر ممكنًا:

  • السلوك الحالي ، الذي سيصبح قديمًا ، والذي يخضع لـ CommandLineToArgvW على Windows وله نتائج غير متوقعة
  • السلوك الافتراضي ، يجب أن تمرر الوسيطات حسب قيمة التعبير الخاصة بها ولكن تطبق قواعد الرمز الشريطي المعتادة ، بحيث تكون أشياء مثل > و | أوامر منفصلة. في هذا الوضع ، يجب أن تكون القيمة التي تأخذها العملية الفرعية من التعبير هي ما يتم عرضه بواسطة Write-Host $val
  • السلوك الحرفي ، حيث يتم تفسير جميع الرموز المميزة على أنها سلاسل حرفية حتى يتم رؤية رمز الهروب. هذا ما يفترض أن يفعله --% اليوم ، لكن من الناحية المثالية سيكون له رمز نهاية واحد فقط يمكن تضمينه في نفس السطر مثل --% ... %--
  • سلوك قراءة Bash ، حيث يتم تطبيق منطق هروب بديل موجه لـ sh ، مما يسمح بتوافق أبسط

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

يمكن أن يكون للسلوكين الثاني والثالث علاماتهم الخاصة مثل &! و &# أو ربما +% ... -% أو شيء من هذا القبيل. ولكن بالنسبة للوضع الحرفي ، أعتقد أن أحد الجوانب المهمة سيكون تبسيط رمز الهروب بحيث يتم أخذ المزيد من الرموز حرفياً. على غرار هيريدوك.

إذا كان الطلب فقط لمعالجة سيناريو لصق النسخ مثل "أي محتوى نصي بعد هذا المشغل سوف يستدعي" shell الافتراضي "لنظام التشغيل لتنفيذه." لماذا لا نقول هذا صراحة بـ shell ؟
`` بوويرهيل
PS> shell wsl ls | أقل
PS> (shell wsl ls * .txt) | حدد سلسلة مرحبا

إنها أكثر قابلية للاكتشاف والقراءة من العوامل المشفرة بأسلوب Forth / APL.

لا أرى مطلقًا كيف سيحل هذا # 1995: راجع https://github.com/PowerShell/PowerShell/issues/1995#issuecomment -653174261

أيضًا ، مشكلة WSL هي مشكلة سلوك wsl.exe (انظر https://github.com/PowerShell/PowerShell/issues/12975#issuecomment-650353021) وليس من بوويرشيل.
(حسنًا ، هناك مشكلة في بوويرشيل ، ولكن هذا # 1995)

أوه ، أليس هذا تقريبًا نسخة مكررة من https://github.com/PowerShell/PowerShell/issues/12975 ؟ لأنه يمكنني في الغالب أن أكرر ما ذكرته هناك:

تضمين التغريدة
تكمن المشكلة في أن الافتقار إلى القدرة على تحديد جزء من سطر الأوامر ليتم تمريره varbatim إلى الأمر / البرنامج النصي المستلم هو أمر يوجه المستخدمين طوال الوقت.
ماذا تقصد ب "جزء من سطر الأوامر لتمرير varbatim"؟ هل تقصد 1. قم بتمرير بعض التسلسل الحرفي للأحرف إلى الملف القابل للتنفيذ الذي يسمى ، بحيث يحتوي الملف القابل للتنفيذ الذي يسمى هذا التسلسل من الأحرف في عنصر واحد من مصفوفة الوسائط الخاصة به (على سبيل المثال ، تتوفر هذه الأحرف في `` argv [1] `في [main ] (https://docs.microsoft.com/en-us/cpp/cpp/main-function-command-line-args؟view=vs-2019#command-line-arguments)) أو تقصد 2. أدخل بعض التسلسل الحرفي للأحرف في المعلمة [`lpCommandLine` الخاصة بـ` CreateProcess`] (https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw#parameters) - - إذا كنت تقصد (1.) ، فهذا يعني أنه يعمل بالفعل بالفعل:
PS /home/User> /bin/echo 'cd / && ls . | cowsay'
cd / && ls . | cowsay
PS /home/User>
(باستثناء مشكلة الاقتباسات المضمنة كما تمت مناقشتها في https://github.com/PowerShell/PowerShell/issues/1995) يمكن للمرء أن يجادل بأن إضافة سلسلة من سطر واحد هنا من شأنها تحسين بعض حالات الاستخدام ، لكنني أعتقد ، هذا ليس حقا الهدف من هذه القضية. نظرًا لأن هذا يعمل بالفعل إلى حد ما أو أقل ، أفترض ، أنك تقصد (2.) --- إذا كنت تقصد (2.) ، فدعني أوضح رأيي في ذلك بطريقة دراماتيكية إلى حد ما: من فضلك من فضلك من فضلك لا تضيف بناء جملة خاص لهذا. هذا هو أساسًا ما حاول "-٪" فعله ، والذي أيضًا ما كان يجب أن يتم تنفيذه مطلقًا. لماذا أنا ضد هذا بشدة؟ 1. إنها مشكلة Windows فقط ، لذا فإن إضافة بناء الجملة يعني أن بوويرشيل على Windows له صيغة مختلفة عن لينكس. (أو سيتم دعم بناء الجملة ولكنه لا معنى له تمامًا ، كما هو الحال حاليًا بالنسبة لـ "-٪") 2. إذا كان غلاف سطر الأوامر الرئيسي على Windows المنشور بواسطة Microsoft يضيف ميزة من الدرجة الأولى (عبر بناء جملة خاص يعارض عبر cmdlet) لاستدعاء الملفات التنفيذية التي لا تتبع [قواعد تحليل سطر الأوامر] النموذجية (https://docs.microsoft.com/en-us/cpp/cpp/main-function-command-line-args؟view=vs -2019 # parsing-c-command-line-arguments) (إذا كانت الأداة تتبع القواعد النموذجية ، فلن تحتاج (2.) ، يمكنك عادةً استخدام (1.) بشكل أفضل) ، فهذا يشجع مؤلفي سطر الأوامر أداة ، لعدم اتباع هذه القواعد ، والتي تؤدي فقط إلى تفاقم ["فوضى سطر أوامر Windows"] (https://stackoverflow.com/a/4094897/2770331). كلما قل عدد الأشخاص الذين يتبعون القواعد النموذجية ، كلما كان من الصعب استدعاء الملفات التنفيذية الخارجية برمجيًا أو كتابة التعليمات البرمجية عبر الأنظمة الأساسية بشكل عام ، لذلك أعتقد بالتأكيد أنه يجب تشجيع مؤلفي البرنامج على اتباع تلك القواعد النموذجية. 3. أشك بشدة في أن هذه حالة استخدام شائعة> وهذه ليست مجرد مشكلة تؤثر على WSL: إنها تؤثر أيضًا على استدعاءات سطر أوامر Windows Terminal والعديد من الأدوات الأخرى. هل يمكنك إضافة بعض الأمثلة ، حيث تحدث مثل هذه المشاكل؟ لأنه في حالة WSL ، أود أن أقول إن تحليل WSL لسطر الأوامر [معطل] (https://github.com/Microsoft/WSL/issues/1746) (كانت المشكلة تتعلق بـ `bash.exe` ولكن الوضع كذلك بشكل افتراضي ليس أفضل مع "wsl.exe") في الحالة الافتراضية - سأعتبر كل أداة لا تتبع [قواعد تحليل سطر الأوامر] النموذجية (https://docs.microsoft.com/en-us/ cpp / cpp / main-function-command-line-args؟ view = vs-2019 # parsing-c-command-line-arguments) معطلة ، لكن سلوك WSL الافتراضي هو IMHO غير موثق بشكل صحيح حتى ... "سلوك" wsl.exe "معطل - أثناء كتابة هذه الاستجابة ، لاحظت أن" wsl.exe "يبدو أنه يتصرف كما هو متوقع ، عند استخدام" -e ":
PS C:\> wsl -e bash -c 'cd / && ls . | cowsay'
 _______________________________________
/ acct bin boot cache cygdrive data dev \
| etc home init lib lib64 lost+found    |
| media mnt opt proc root run sbin snap |
\ srv sys tmp usr var                   /
 ---------------------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
PS C:\>
لذا فإن الشيء الوحيد المفقود لحالة الاستخدام الصريحة هذه هو IMO معلمة لـ `wsl.exe` لاستدعاء shell الافتراضي مع تحليل وسيطات سطر الأوامر كما هو الحال في أي exe عادي آخر.

الشيء الوحيد المتعلق بـ "جزء من سطر الأوامر الذي سيتم تمرير varbatim إلى الأمر / البرنامج النصي المستلم" ، والذي سيتم تحسينه باستخدام هذا المشغل سيكون المعنى (2.) أعلاه ، وكما ذكرنا ، أعتقد أن التطوير في هذا الاتجاه هو سيئة.

إذا كان كل ما تريد القيام به هو اختصار ، فقم بنسخ ولصق أسطر الأوامر الموجودة ، فلماذا لا تضيف أمر cmdlet (على سبيل المثال ، Invoke-Shell ، الذي يستدعي bash -c على linux و cmd /c on شبابيك؟
ثم يمكنك أن تفعل فقط

Invoke-Shell @'
whatever existing comandline containg '"quotes"' or whatnot
'@

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

ورجاء لا تتخلى عن 1995 # لهذا!

+10 نقاط لاستخدام كلمة "سيجيل".

الشيء الجميل في التعامل مع &! مقابل shell هو أن كلمة "shell" هي كلمة إنجليزية شائعة ، لذلك قد يكون لدى الأشخاص أمر موجود يسمى shell. (في الواقع ، لديّ وظيفة باسم "shell" ووظيفة باسم "n" (ومن ثم لا أحب &n ).)

oising : يعد & --% أمرًا رائعًا ، باستثناء أن أحد الأغراض الصريحة للميزة المقترحة هو أن يعني أن | يصبح شيئًا يتم تمريره إلى الغلاف الأصلي ؛ ليس شيئًا يعيدك إلى تحليل PowerShell. وإذا جعلنا أسبقية خط الأنابيب مختلفة لـ & --% عن foo $blah --% more args ، سأجد ذلك محيرًا ... ماذا لو فعلت & $foo --% more args | blah ؟ وبالتالي ، في رأيي ، فإن &! المقترح مختلف بما يكفي بحيث يضمن وجود عامل تشغيل مختلف. (بعبارة أخرى: الوظيفة المقترحة مرتبطة ولكنها تختلف عن الجمع بين & و --% .)

هذه الميزة أكثر من مجرد "مستخدم PowerShell جديد يعرف bash" و "مستخدم لا يعرف كل قواعد الاقتباس / الهروب المعقدة". إنه أيضًا خاص بالمستخدمين الأكثر خبرة ، الذين يريدون فقط نسخ / لصق أمر من StackOverflow دون الحاجة إلى الدخول والتلاعب بكل شيء. يحدث هذا لي قليلاً - المنتج الذي أعمل عليه يحتوي على الكثير من الوثائق حول كيفية القيام بالأشياء ، واللغة المشتركة هي أوامر cmd.exe - لذلك يجب أن أذهب وأتعامل مع إصلاح٪ VARIABLE_REFERENCES٪ إلخ . ؛ سيكون من الأجمل كتابة &! ثم لصقها. في الواقع ، إذا تم تنفيذ ذلك ، فمن المحتمل أن أشير إليه على أنه "مشغل StackOverflow". :د

@ vexx32 : هذه ليست "حلقة واحدة

TSlivede : أوافق على أن 1995 # منفصل. لكنني لا أتفق مع "إنها مشكلة Windows فقط": نسخ ولصق الأوامر الخاصة بالنظام الأساسي من StackOverflow تنطبق بالتساوي على أي نظام تشغيل. (في الواقع ، سيكون هذا مفيدًا جدًا للعديد من الأشخاص مثلي الذين هم أقوى على نظام أساسي واحد من الآخر - فأنا أكثر كفاءة في استخدام تقنيات Windows ، لذلك عندما كنت على نظام Linux ، أميل إلى القيام بالكثير من النسخ واللصق من SO.)

سواء عن طريق مشغل جديد &! أو أمر Invoke-Shell ، ليس لدي مشاعر قوية مثل الآخرين ... أنا أتعاطف مع الأشخاص الذين يشكون من صعوبة البحث عن المشغلين ، إلخ. أنا حقًا أحب توتر &! .

jazzdelightsme ، هذه ليست "أداة أخرى في صندوق الأدوات" بقدر ما هي "ملحق مفك براغي محدد بشكل لا يصدق لمفك براغي يحتوي بالفعل على حوالي 3-5 والتي هي حاليًا بالفعل _ okay_ ويمكن تحسينها" في رأيي.

jazzdelightsme ربما كان جزء "Windows فقط" أكثر ارتباطًا بالمسألة التي نشرت فيها هذا البيان في الأصل - نعم حسنًا ، هذه ليست نسخة طبق الأصل من هذه المشكلة.

إذا لم يتم التخلي عن # 1995 ولم يتم حل الميزة المطلوبة هنا من خلال بناء جملة خاص ولكن عبر commandlet (أو ربما بناء جملة جديد لسلسلة من سطر واحد هنا تعمل في كل مكان ليس فقط لهذه الحالة الخاصة) فأنا بالفعل أؤيد مضيفا هذه الوظيفة. (أو ربما ليس "لصالح" ولكن "هذا مقبول تمامًا بالنسبة لي")

فكرة أخرى: إذا كانت هذه المشكلة تتعلق في الواقع بنسخ ولصق الأوامر الكاملة التي كانت مخصصة للأصداف الأصلية ، فربما يمكن لـ PsReadLine إضافة ميزة لترجمة أمر من نمط bash أو cmd إلى powerhell. يمكن تشغيل الترجمة من خلال مجموعة مفاتيح خاصة أو تلقائيًا في حالة حدوث خطأ في التحليل عند محاولة تنفيذ أمر ما.

سيكون لهذا ميزة إضافية تتمثل في تعليم المستخدمين بناء جملة بوويرشيل.

فيما يتعلق بقابلية الاكتشاف: يمكن لـ PsReadLine دائمًا عرض رسالة لفترة قصيرة مفادها أنه يمكن استخدام مجموعة المفاتيح المحددة ، عند لصق محتوى غير صحيح من الناحية التركيبية (سيكون صالحًا بعد الترجمة).

لكن يمكنني أن أفهم ما إذا كان هذا معقدًا بعض الشيء.

jazzdelightsme هل تحدثت إلىjoeyaiello؟ اعتقدت أنه فقط أطلق عليها اسم StackOverflow operator مما جعلني أشعر بالضيق رغم أنه حقيقي جدًا

@ SteveL-MSFT لا لم أتحدث إلى أي شخص عن هذا ؛ وصلت إلى "StackOverflow عامل" بشكل مستقل. وجه ضاحك

تضمين التغريدة

... باستثناء أحد الأغراض الصريحة للخاصية المقترحة يعني أن | يصبح شيئًا يتم تمريره إلى الغلاف الأصلي ؛ ليس شيئًا يعيدك إلى تحليل PowerShell.

لست متأكدًا من أنك فهمت اقتراحي ؛ ما تقوله هو _بشكل دقيق_ ما أقوله. اسمحوا لي أن أكون أكثر تفصيلاً مع بعض التلميحات ذات الرسملة الاستراتيجية: د

# NON-OPTIMAL SOLUTION: run "ls" in wsl, return results to powershell, then pipe to wsl again, to "grep."
& wsl ls | wsl grep -i "foo"  

# NEW SOLUTION: the entire pipeline/string, INCLUDING THE PIPE SYMBOL, right of wsl will be executed in wsl. 
& --% wsl ls | grep -i "foo"

# NEW SOLUTION: the entire pipeline AS ABOVE is sent to WSL, then the results are returned to powershell
# and piped, in powershell, to foreach-object
(& --% wsl ls | grep -i "foo") | % { "match {0}" -f $_ }

# NEW SOLUTION: allow placing --% beyond first argument
# pass everything right of --% to the command in $wsl 
$wsl = gcm wsl
& $wsl --% ls | grep -i "foo"

# or

& wsl --% ls | grep -i "foo"

# NEW SOLUTION: execute multiline pasted code without powershell parsing.
& --% @'
(pasted multiline code)
@'

ما الذي افتقده هنا؟ إذا ظهر الأنبوب بعد --% فهو مجرد شخصية أخرى غبية: وسيطة. ليس هناك تلاعب بأسبقية عامل التشغيل. إذا تم احتوائه في خط أنابيب متداخل أو تعبير فرعي ، فابدأ في التحليل من أجل powerhell مرة أخرى.

ماذا لو فعلت & $ foo -٪ أكثر من args | بلاه؟

حسنًا ، سيحاول ذلك تنفيذ الوسيطة في $foo وتمرير "more" و "args" و "|" و "blah" ليتم التعامل مع أي شيء في $foo يريد. تبدو القواعد بسيطة بما يكفي بالنسبة لي ، لكن من المسلم به أنني كنت أستخدم بوويرشيل / موناد لفترة طويلة. هذا ليس تغييرًا جذريًا في & حيث أن & $foo --% ... يعامل --% مثل أي وسيطة أخرى. لذلك ما لم نستخدم هذا sigil في مكان آخر بشكل شائن ، يجب أن نكون آمنين.

أفكار؟

لقد أجريت تعديلات متعددة على ما سبق ، لتغطية التقييم الجزئي للخط ، والتقييم متعدد الأسطر والموضع المتغير لـ --% . كل ذلك بدون إدخال سيجيلات جديدة أو عوامل تشغيل أو بناء جملة غريب. أعتقد أن هذا يغطيها. الشيء الوحيد هو: هل يستطيع المحلل اللغوي التعامل معها؟ ما رأيكlzybkrJamesWTruherBrucePay؟

اسمع ، اسمع ،TSlivede.

سامحني لكوني صريحًا ، لكننا نتحدث عن هذه القضايا لفترة طويلة:

ما تقترحه هذه القضية يرقى إلى مستوى التفكير السحري:
إنه مرتبط بـ "رمز إيقاف التحليل" المشؤوم ، والمشكل بطبيعته ، --% ، والذي في شكله الحالي محدود الاستخدام _ على Windows_ (انظر https://github.com/MicrosoftDocs/PowerShell- Docs / Issues / 6149) وعديمة الفائدة تقريبًا على الأنظمة الأساسية التي تشبه Unix (راجع https://github.com/MicrosoftDocs/PowerShell-Docs/issues/4963).
--% يجب أن يتم تنفيذه مطلقًا ، ولا يجب تنفيذ هذا الاقتراح كما هو معروض.

التفكير السحري هو خلط مشوش من الناحية المفاهيمية لفكرتين:

  • (أ) "أرغب في تمرير الرموز المميزة المفصولة بمسافات إلى بعض البرامج الخارجية ، مما يتيح استخدام أي كلمات بارزة ، دون الحاجة إلى القلق بشأن أحرف أولية للصدفة مثل & أو | ." - راجع https://github.com/PowerShell/PowerShell/issues/12975#issuecomment -646276628

    • بالطبع ، تتعارض هذه الميزة مع استخدام مثل هذه الأوامر _ كجزء من خط_أنابيب_ أو مع _ مشغلي تسلسل خطوط الأنابيب_ ( && و || ) ، وكذلك وضع أوامر إضافية على نفس السطر ، بعد ; - وليس آخراً ، القدرة على استخدام أي متغيرات وتعبيرات PowerShell في سطر الأوامر.
  • (ب) "أريد أن يُعامل سطر الأوامر الخاص بي بالطريقة التي اعتدت أن أستخدمها في _من الغلاف الذي أستخدمه عادةً_ (أو الغلاف الذي تمت كتابة سطر الأوامر من أجله في الأصل)" ، والتي ، بالطبع ، _is_ تخضع لاستخدام غير مقتبس من الأحرف مثل & أو | يتم تفسيرها على أنها أحرف أولية وبالتالي لها معنى _syntactic_.

    • مثال على ذلك: لن يقبل أي من cmd ولا /bin/sh (أو أي غلاف يشبه POSIX مثل bash ) wsl ls | less بطريقة ls ، | ، و less _verbatim_ حتى wsl - جميعهم يفسرون _غير الاقتباس_ | أنه رمز الأنبوب الخاص بهم.

تتعارض هذه الأفكار مع بعضها البعض ، وتتطلب حلولا متميزة - ولا يتطلب أي منهما صياغة خاصة في حد ذاتها:

  • الحل لـ (أ) هو التخلي عن الفكرة واستخدام بناء الجملة الخاص بـ PowerShell الخاص ، بدلاً من ذلك ، لضمان استخدام الأحرف الوصفية _الكلمات_التي تتطلب دائمًا _الاقتباس_ أو _ escaping_ ،:

    • إما: علامات اقتباس (الرموز المميزة غير المرفقة بعلامات اقتباس) تحتوي على أحرف أولية _ ككل_: wsl ls '|' less
    • أو: ` -escape metacharacters _individually_ in barewords: wsl ls `| less
    • أو: استخدم _array [متغير] _ لتمرير الوسيطات _verbatim_: $wslArgs = 'ls', '|', 'less'; wsl $wslArgs
    • بالطبع ، يوضح # 1995 أنه ، للأسف ، تم كسر هذا النهج ودائمًا ما تم كسره عندما يتعلق الأمر بالحجج التي تحتوي على _مضمنة_ " _عند استدعاء البرامج الخارجية _ _ يجب معالجة هذا _: انظر أدناه.
  • الحل لـ (ب) هو في الواقع _ استدعاء الصدفة التي أستخدمها عادة_ ، وتمرير سطر الأوامر _ كسلسلة واحدة_.

    • كما يقترح TSlivede ، فإن cmdlet Invoke-Shell التي تمرر إليها سطر الأوامر _ كسلسلة واحدة_ والتي تستدعي _platform-native shell_ هو الحل - ولدينا بالفعل بناء جملة للسلاسل الحرفية ( '...' أو متغيرها هنا ، @'<newline>...<newline>'@
    • توصيتي بتسميتها Invoke-NativeShell ، والاتصال بـ /bin/sh - وليس bash - على منصات تشبه Unix.

      • بالإضافة إلى ذلك ، أقترح تحديد ins كاسم مستعار موجز.

    • يحل هذا النهج جميع المشكلات المفاهيمية مع --% ومع الاقتراح المطروح:

      • إنه يجعل الأمر واضحًا للغاية حيث ينتهي الأمر الذي تم تمريره إلى الغلاف الأصلي (بحكم كونه _ سلسلة واحدة_) ، ويسمح باستخدام مكالمة Invoke-NativeShell / ins في خط أنابيب PowerShell عادي / مع عمليات إعادة توجيه PowerShell بدون غموض.

      • يمكنك اختياريًا استخدام سلسلة _expandable_ ( "...." أو متغيرها هنا) لتضمين قيم متغير _PowerShell_ في سطر الأوامر (شيء لا يمكن لـ --% فعله).


نظرًا لأن الصلاحيات التي استنتجت أنه لا يمكن إصلاح 1995 # خشية تعطل التوافق مع الإصدارات السابقة - فبعد كل شيء ، ستتعطل جميع الحلول الحالية ، راجع https://github.com/PowerShell/PowerShell/issues/1995#issuecomment -562334606 - أفضل شيء يمكننا القيام به هو دعم التقيد بالسلوك الصحيح باستخدام بناء جملة مقتضب قدر الإمكان ، وذلك لتقليل ألم الاضطرار إلى الخروج عن طريقك للحصول على السلوك الذي كان يجب أن يكون دائمًا إفتراضي.

لذلك: يجب توفير بناء جملة خاص مثل &! كمشترك للحصول على تمرير مناسب للحجج إلى البرامج الخارجية من أجل معالجة # 1995 ، بناءً على السلوك المقترح في TSlivede 's RFC - راجع https://github.com/PowerShell/PowerShell-RFC/pull/90. إذا تم السماح لإصدار PowerShell مستقبلي بقطع التوافق مع الإصدارات السابقة ، فإن الاستدعاء / الاستدعاء المباشر مع & الذي يجب أن يظهر هذا السلوك.

من وجهة نظر المستخدم ، هذا يعني: كل ما علي فعله هو تلبية متطلبات بناء الجملة _PowerShell's_ - راجع https://github.com/PowerShell/PowerShell/issues/1995#issuecomment -640711192 - ويمكنني الاعتماد على PowerShell من أجل قم بتمرير الرموز المميزة الحرفية الناتجة بقوة إلى البرنامج المستهدف - _هذا هو التفويض الأساسي لأي قذيفة ، والتي للأسف لم ترضي PowerShell أبدًا فيما يتعلق بالبرامج الخارجية _.

على سبيل المثال ، الأمر التالي - الذي يعمل حاليًا _not_ على النحو المنشود (عند استدعائه مباشرة أو مع & - راجع مشكلة المستندات هذه ) - يجب أن يعمل بعد ذلك:

PS> &! bash -c 'echo "one two"'
one two   # Currently (invoked with & instead of &! or with neither) prints only 'one', 
          # because PowerShell passes the entire argument (brokenly) as  "echo "one two"",
          # which the target program sees as *2* verbatim arguments `echo one` and `two`

يمكن لأولئك الذين يبحثون عن حل بديل في إصدارات PowerShell الحالية / السابقة العثور على وظيفة بسيطة تغطي معظم حالات الاستخدام على https://github.com/PowerShell/PowerShell/issues/1995#issuecomment -303345059 (تمت مناقشة القيود في https: // github.com/PowerShell/PowerShell/issues/1995#issuecomment-649560892) ، وإصدار أكثر تفصيلاً على https://github.com/PowerShell/PowerShell/issues/1995#issuecomment -562334606

ملاحظة: مشكلة اكتشاف المشغلين (ليس فقط المستندة إلى الرموز) هي مشكلة منفصلة تستحق المعالجة في حد ذاتها: الحل هو تحسين Get-Help للسماح بالبحث عن المشغل _ - راجع # 11339 ، والذي أيضًا روابط لحل مؤقت.

نظرًا لأن الصلاحيات التي خلصت إلى أنه لا يمكن إصلاح 1995 # خشية كسر التوافق مع الإصدارات السابقة - بعد كل شيء ، ستتعطل جميع الحلول الحالية ، راجع # 1995 (تعليق) - أفضل شيء يمكننا فعله هو دعم الاشتراك السلوك السليم مع بناء الجملة موجز قدر الإمكان ، وذلك لتقليل ألم الاضطرار إلى الخروج عن طريقك للحصول على السلوك الذي كان يجب أن يكون دائمًا هو الافتراضي.

@ mklement0 أعتقد أن الاشتراك كان جزءًا من https://github.com/PowerShell/PowerShell/issues/1995 وقد تم رفض ذلك. لذا بالنسبة لي يبدو الأمر وكأنه تمني. هل انا مخطئ

AndrewSav ، لقد ناقشنا في الأصل فقط خيار الاشتراك عبر التكوين أو متغير التفضيل.

ومع ذلك ، قال joeyaiello ما يلي في https://github.com/PowerShell/PowerShell/issues/1995#issuecomment -653164987 عندما أغلق المشكلة (التشديد مضاف):

أي شيء نتطرق إليه هنا هو تغيير جذري للغاية ،

عامل جديد _ هو نوع من الاشتراك ، لكنه غير إشكالي ، كما آمل (على الرغم من أن الحاجة إليه أمر مؤسف ، ولكن هذا هو ثمن التوافق مع الإصدارات السابقة).

بينما يُزعم أن هذا الاقتراح يحل أيضًا # 1995 ، إلا أنه لا يحل ، نظرًا لأنه يهدف (بشكل أساسي) إلى استيعاب بناء جملة الأصداف الأخرى. بالنظر إلى أن كلتا المشكلتين تستحقان الحل ، بشكل مستقل ، كان اقتراحي كما يلي:

  • دعنا نقدم مشغلًا جديدًا ، ولكن نستخدمه فقط لإصلاح # 1995 (عبر https://github.com/PowerShell/PowerShell-RFC/pull/90) ، أي لإصلاح PowerShell's _own_ (non-other-shell-emulating) التعامل مع الحجة التي تنتقل إلى البرامج الخارجية.

    • يجب أن يستخدم الرمز الجديد دائمًا &! (أو أي شكل نقرره) بدلاً من & عند استدعاء البرامج الخارجية (يمكنك التفكير في الأمر على أنه إهمال & للبرامج الخارجية) .
    • عند استدعاء أوامر _PowerShell_ ، يجب أن يتصرف &! مثل & الآن (لم تكن هناك مشكلة أبدًا) ، وبالتالي تمكين الاستخدام المتسق لـ &! .
  • لحل مشكلة reuse-command-lines-from-other-shells ، فلنطبق Invoke-NativeShell / ins cmdlet الذي يستدعي الصدفة الأصلية المناسبة للنظام الأساسي ( cmd /c على Windows ، /bin/sh -c على الأنظمة الأساسية الشبيهة بـ Unix) مع تمرير سطر الأوامر كسلسلة واحدة_.

    • في أبسط الحالات ، مع عدم وجود ' في سطر الأوامر ، ستعمل سلسلة عادية ذات علامة اقتباس فردية ؛ على سبيل المثال:

      الإضافية | القط -n '

    • مع وجود ' ، يمكن أن تكون إما مضاعفة ؛ على سبيل المثال:

      إن 'صدى' 'مرحبا' '| القط -n '

    • أو ، إذا كانت الرغبة لا تضطر إلى لمس سطر الأوامر على الإطلاق ، فيمكن استخدام سلسلة هنا (كما هو موضح بالفعل بواسطةTSlivede) - في حين أن بناء الجملة هذا أكثر تعقيدًا ، يجب أن يعمل دائمًا:

      الإضافية @ '
      صدى "مرحبا" | القط -n
      "@

    • بالإضافة إلى ذلك ، باستخدام سلسلة _ قابلة للتوسيع_ (استيفاء) ( "..." أو @"<newline>...<newline>"@ ) ، لديك خيار دمج متغيرات _PowerShell_ في السلسلة التي تم تمريرها إلى الصدفة الأصلية (شيء --% لا يدعم):

      $ foo = "مرحبًا"
      الإضافية @ "
      صدى "$ foo" | القط -n
      @

    • ملحوظة:

      • Invoke-NativeShell cmdlet سيكون غلافًا رقيقًا إلى حد ما حول cmd /c / /bin/sh -c المكالمات ، والتي من الواضح أنه يمكنك إجراؤها بنفسك مباشرة ، لكن لديها ميزة لا تحتاج إليها معرفة الاسم المحدد القابل للتنفيذ وبناء جملة تمرير سطر الأوامر.
      • كأثر جانبي محتمل مفيد ، ستكون قادرًا على استخدام المعلمات الشائعة مثل -OutVariable ، ويمكنك التفكير فيما إذا كنت تريد السماح لمعلمات -Error* بالعمل على _stderr_ (على الرغم من التماثل ، Invoke-Command يجب أن يكون ذلك أيضًا ، والذي سيكون تغييرًا مفاجئًا)

        • نظرًا لأن الأصداف الشبيهة بـ POSIX تدعم وسيطات _multiple_ مع -c - الأولى التي تشكل الكود المطلوب تنفيذه ، والأخرى اللاحقة هي الوسيطات لتمرير هذا الرمز ، بدءًا من $0 (!) - على سبيل المثال bash -c 'echo $@' _ 1 2 3 - يجب دعم الوسائط الإضافية الاختيارية أيضًا.

        • نظرًا لأنه يتم استدعاء shell الأصلي للنظام الأساسي ، فإن مثل هذه المكالمات بحكم تعريفها _not_ محمولة ، نظرًا للاختلافات الأساسية بين cmd و sh .هذا هو السبب في أنه من المهم جدًا إصلاح _own_ الوسيطة تمرير (# 1995) ، لأنه يوفر بعد ذلك طريقة موثوقة وعبر الأنظمة الأساسية لاستدعاء البرامج الخارجية.


الجزء الأخير من اللغز هو _ التوثيق_.

https://github.com/MicrosoftDocs/PowerShell-Docs/issues/5152 هو اقتراح طويل الأمد لكتابة موضوع تعليمات مفاهيمي حول استدعاء البرامج الخارجية (على سبيل المثال ، about_Native_Calls ) ، والتي يجب أن تكون في مكان واحد ، تغطية _ جميع_ الجوانب ذات الصلة باستدعاء البرامج الخارجية ؛ بصرف النظر عما تم تغطيته بالفعل هناك (عيوب بناء الجملة بسبب أحرف أولية إضافية ، عدم وجود خط أنابيب أولي للبايت ، عدم التكامل مع معالجة أخطاء PowerShell ، ...) ، يجب مناقشة المشكلات المطروحة أيضًا:

  • كيف يتم تقسيم الوسيطات الممررة باستخدام " (وسيطات _empty_) في الإصدارات السابقة (التي نأمل أن تكون قريبًا) (تمت مناقشتها حاليًا في اقتراح منفصل ، https://github.com/MicrosoftDocs/PowerShell-Docs / issues / 2361) ، وكيفية التغلب على ذلك (يدوي \ الهروب أو استخدام إحدى الوظائف المساعدة من # 1995 ، إحداها موجزة بما يكفي لتضمينها مباشرة في الموضوع).

  • كيف يجب استخدام &! من الآن فصاعدًا لاستدعاء الملفات التنفيذية الأصلية (الخارجية) ، وذلك لضمان تمرير الوسيطة بشكل صحيح.

  • كيف يمكن استخدام Invoke-NativeShell / ins لتنفيذ أسطر الأوامر _ المكتوبة لمنصة shell الأصلية_ كما هي.

مثير للاهتمام ، يمكن للمستخدمين اليوم:

  1. الاحتجاج المباشر
  2. & المشغل أو العامل
  3. بدء العملية

ليس من الواضح على الإطلاق أنه يجب على المستخدمين استخدامها.

بعد إصلاح السلوك المعطل ، سيكون لدى المستخدمين الميزات التالية:

  1. الاحتجاج المباشر
  2. & المشغل أو العامل
  3. بدء العملية
  4. &! المشغل أو العامل
  5. بدء العملية

أليس الكثير بالنسبة للصدفة لتشغيل ping 127.0.0.1 ؟

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

إذا كنا نهتم بتجربة المستخدم على الإطلاق ، فيجب أن نختار تحسين الحالات الحالية بدلاً من إضافة المزيد.

إذا كنا نهتم بتجربة المستخدم على الإطلاق ، فيجب أن نختار تحسين الحالات الحالية بدلاً من إضافة المزيد.

لا يمكنك ذلك لأنه يجب أن تكون متوافقًا مع الإصدارات السابقة. أشعر أننا نسير في دوائر. https://github.com/PowerShell/PowerShell/issues/1995 كان ذلك وتم إغلاقه لهذا السبب بالذات.

@ iSazonov :

يجب معالجة النقص الحالي في الإرشادات حتى إذا لم نقدم مشغلًا جديدًا:

للتلخيص بإيجاز:

  • لا تستخدم Start-Process لاستدعاء برامج _console_ (طرفية) (إلا إذا كنت ترغب في تشغيلها _في نافذة جديدة _ في نافذة جديدة - وهي متوفرة على Windows فقط).

  • الاستدعاء والاستدعاء المباشر عبر & _ مكافئ_ ؛ (مع ترك كتل البرنامج النصي جانبًا) ، هناك حاجة إلى & فقط لأسباب _syntactic_ ، عندما يتم اقتباس اسم الأمر أو المسار و / أو احتوائه على مراجع متغيرة.


بعد إصلاح السلوك المعطل ، سيكون لدى المستخدمين الميزات التالية:
الاحتجاج المباشر

  • & المشغل أو العامل
  • بدء العملية
  • &! المشغل أو العامل
  • بدء العملية
  • لا ، لن يكون هناك Start-ProcessV2 ، فقط معلمة _new_ ، -IndividualArguments - راجع https://github.com/PowerShell/PowerShell/issues/5576#issuecomment -552124719

  • نعم ، سيكون هناك &! (أو أي رمز نقرره) ، لكنه فعليًا _ يتفوق على كل من & والاستدعاء المباشر_ (على الأقل بالنسبة للبرامج الخارجية_ ، ولكن ستتمكن من استخدامه مع _all_ نماذج الأوامر) - والتي يجب أن تكون سهلة التواصل.

أليس الكثير بالنسبة للصدفة لتشغيل ping 127.0.0.1 ؟

سيستمر ping 127.0.0.1 في العمل ، ولكن إذا كنت تريد عمل bash -c 'echo "one two"' ، فسيتعين عليك استخدام
&! bash -c 'echo "one two"'

هذا أمر مؤسف ، ولكن - بالنظر إلى أن الاستدعاء المباشر / & سلوك _ لا يمكن إصلاحه_ - يبدو لي أفضل حل.

لحسن الحظ ، إنها قاعدة بسيطة للحفظ: _إذا كنت تريد تمرير حجة يمكن التنبؤ بها إلى برامج خارجية ، فاستخدم &! _

تعد الأشكال البديلة للاشتراك - التكوين (عبر powershell.config.json ) أو متغير التفضيل - أكثر إشكالية:

  • يجعل النطاق الديناميكي لمتغيرات التفضيل من السهل جدًا تطبيق الاشتراك عن غير قصد على الكود القديم الذي لم يتم تصميمه من أجله - راجع https://github.com/PowerShell/PowerShell/issues/1995#issuecomment -650262164

  • سيتم تطبيق التكوين على الجلسات ككل ، مما يجعل إلغاء الاشتراك مستحيلًا تمامًا.

  • في كلتا الحالتين ، يلزم اتخاذ إجراء _ منفصل_ عن مكالمة معينة ، والنظر إلى مكالمة معينة لن يخبرك كيف ستتصرف - على النقيض من ذلك ، لا يترك أي شك في السلوك الذي سيتبعه &! .

بالنسبة للمستخدم النهائي ، يبدو الأمر فظيعًا تمامًا كما لو أننا أطلقنا آلة حاسبة ووجدنا هناك 5 أزرار لعملية الإضافة. 😄

إذا أردنا تحسينه كثيرًا بحيث نكون مستعدين لمثل هذه التعقيدات ، فربما يكون هذا كافيًا لقبول تغيير كسر (للاستدعاء المباشر و & ) لتبسيط السلوك وإصدار V8.0.

إذا لم تكن رغبتنا قوية جدًا ، فمن الممكن تحسين التشخيص بشكل كافٍ ( prog.exe param1 param2 -Whatif ونفس الشيء بالنسبة لـ Start-Process -WhatIf) بحيث يعرض ما يعرضه البرنامج testargs والتوصيات حول الكيفية لأداء الهروب بشكل صحيح.

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

@ iSazonov :

إذن ربما يكون هذا كافيًا لقبول تغيير كسر (للاستدعاء المباشر و &) لتبسيط السلوك وإصدار V8.0

لديك بالتأكيد _ my_ صوتي - ولكن هل القوى التي تدعم هذه الخطة ؟ [_update_ - راجع # 13129]
إذا قمنا بتغيير بهذا الحجم ، يمكننا أخيرًا معالجة جميع الأمتعة التاريخية - انظر # 6745

إذا أردنا تحسينه كثيرًا

هناك سببان جيدان لرغبتك في ذلك كثيرًا:

  • لإنهاء سنوات من الألم بسبب كسر الجدل - كما يتضح من # 1995 ، والعديد من القضايا ذات الصلة ، وعدد لا يحصى من أسئلة Stack Overflow.

  • لأنه - كما قيل عدة مرات من قبل - استدعاء البرامج الخارجية بالحجج هو التفويض الأساسي لأي قشرة.

تاريخيًا ، في الأيام التي تعمل بنظام Windows فقط ، أدت ندرة CLIs الخارجية القادرة إلى جعل عدم القدرة على الاتصال بها بشكل صحيح أقل إشكالية ، ولم يشعر المستخدمون الذين بقوا في حديقة PowerShell المحاطة بأسوار (يستدعون أوامر PowerShell الأصلية فقط) بالألم. لكن الأوقات تغيرت بالتأكيد:

نحن نعيش في عصر ثروة من CLIs عبر الأنظمة الأساسية والتي تعتبر بالغة الأهمية لمهام التطوير و CI والنشر.
إذا أراد PowerShell أن يؤخذ على محمل الجد كصدفة ، فيجب معالجة هذه المشكلة.


حتى في حالة حدوث الإصدار 8.0 من التوافق المسموح به للكسر والخلف (تقاطع الأصابع) ، فقد يستغرق إصداره وقتًا طويلاً ، ونحن بحاجة إلى حل مؤقت.

بقدر الحاجة إلى التحسين المقترح للوثائق ، لا أعتقد أنها وحدها تخفف الألم بشكل كافٍ ، بسبب عدم وجود حل وقت تشغيل متاح بسهولة.

فهمت أن عامل التشغيل قبيح ، لكنه حل غير منقطع _ ضروري _ بناء جملة إضافي (للكتابة أكثر) ، مهما كان شكله.

البديل لـ &! الأقل قبحًا وأسهل في الكتابة ولا "يلوث" اللغة هو شحن دالة _ مضمنة _ باسم مختصر ، مثل الوظيفة iep ( I nvoke- E xternal P rogram) الذي يخفي جميع المشكلات الموضحة هنا .
(لاحظ أننا نشحن بالفعل الدوال التي إما أن تلتف بوظائف أخرى (على سبيل المثال ، pause ) أو تستوعب مستخدمي cmd.exe (على سبيل المثال ، cd.. [sic]).)

وبالتالي ، للحصول على bash -c 'echo "one two"' للعمل بشكل صحيح ، يمكنك الاتصال بـ iep bash -c 'echo "one two"'
أو لاستخدام سيناريو أكثر واقعية:

# Pass JSON to an external utility (Unix example)
# Without `iep`, the embedded double quotes are lost and *broken JSON* is passed.
iep /bin/echo '{ "foo": "bar" }'

مرة أخرى ، نحن نتحدث في النهاية عن "حل وسط" في الخدمة للحفاظ على التوافق مع الإصدارات السابقة - وهذا أمر مزعج لا محالة للمستخدمين النهائيين.


تحسين التشخيص (prog.exe param1 param2 -Whatif ونفس الشيء بالنسبة إلى Start-Process -WhatIf) بحيث يعرض ما يعرضه برنامج testargs والتوصيات حول كيفية إجراء الهروب بشكل صحيح.

نظرًا لأن الاستدعاء المباشر / & -based ليس استدعاء cmdlet ويفترض أن جميع الوسيطات عبارة عن وسيطات تمريرية ، فإن معاملة -WhatIf كمعامل مشترك بمثابة تغيير فاصل (على الرغم من أنه من غير المحتمل ذلك في الممارسة).

إذا كنت على استعداد لقبول مثل هذا التغيير ، فقد ندعم أيضًا (أيضًا) مفتاح -DoItRight (أو مفتاح قائم على الرمز ، يشبه --% ) كمفتاح السلوك الثابت - وهذا يبدو لي أسوأ من نهج iep -prefix / &! .

(أعتقد أن خيار التشخيص غير المنكسر هو تعزيز Invoke-Command ، والذي لا يدعم حاليًا -WhatIf - ومع ذلك ، إذا قدمنا ​​اشتراكًا موثقًا جيدًا في الخيار الصحيح السلوك ، لا أعتقد أن هذا يستحق القيام به.)

أتفق مع iSazonov على أن الموقف ليس مثاليًا لتقديم شيء آخر لفعل شيء من المفترض أن يعمل ، ولكن كما ذكر @ mklement0 ، قد يستغرق انتظار إصدار عاجل يعمل على إصلاح هذا الأمر وقتًا طويلاً جدًا ، و الكثير منا بحاجة ماسة إلى حل في أسرع وقت ممكن. بالنسبة إلى كل ما يمكنني رؤيته ، فإن أفضل حل حاليًا هو الاستخدام فقط
https://github.com/PowerShell/PowerShell/issues/1995#issuecomment -562334606 أليس كذلك؟

@ mklement0 لست متأكدًا من كيفية عمل برنامج iep / invoke-externalprogram ، نظرًا لأن الأمر cmdlet يخضع لنفس المعلمة التي نحاول إصلاحها. هذه مشكلة محلل ، أليس كذلك؟ إذا حاولنا إخفاء كل شيء داخل أمر cmdlet / وظيفة ، فأنا أتخيل أنه سيكون معقدًا بشكل بشع نظرًا لأنه سيتعين عليه التراجع عن نية munging / إعادة البناء. أم هل فاتني شيء؟

oising :

لكي نكون واضحين: إصلاحات الوظيفة iep المرتبطة # 1995 ، وليس ما يدور حوله هذا الاقتراح بشكل أساسي (والذي أعتقد أنه لا يستحق المتابعة ، كما ذكرنا أعلاه ) ، على الرغم من ملاحظة أن الهدف المعلن في OP هو _أيضا_ حل # 1995.

تدور 1995 حول القدرة على الاعتماد على بناء جملة _PowerShell_ (وليس قشرة أخرى) لتمرير الحجج إلى البرامج الخارجية - بإخلاص ، كما رأينا حرفياً بواسطة PowerShell بعد التحليل الخاص به.

تحليل PowerShell الخاص جيد ، ولا توجد مشاكل طالما قمت بتمرير الوسائط إلى أوامر _PowerShell_.

على النقيض من ذلك ، فإن تمرير الوسيطات إلى البرامج الخارجية معطل بشكل سيئ ، وهذا ما يصلحه iep .

إنه معطل بسبب خلل في إعادة الاقتباس والهروب من الوسيطات خلف الكواليس ، عندما يتم إنشاء سطر الأوامر المستخدم في النهاية.
https://github.com/PowerShell/PowerShell-RFC/pull/90 يقترح إصلاحًا مناسبًا (بدون اتفاقية حول كيفية التعامل مع التوافق مع الإصدارات السابقة ، ومع بعض الأسئلة الثانوية التي لم تتم الإجابة عليها بعد) ، والتي تعتمد في جوهرها على قدم مؤخرًا System.Diagnostics.ProcessStartInfo.ArgumentList لإجراء إعادة الاقتباس المناسبة والهروب لنا (نحن فقط نمرر مجموعة الحجج التي نتجت عن تحليل PowerShell الخاص) - والتي ، بالمناسبة ، مطلوبة فقط على Windows_ ؛ في نظام التشغيل Unix ، بشكل منطقي ، _ لا يوجد سطر أوامر_ (خارج الصدفة) عند تمرير الوسائط عند بدء تشغيل العملية: يمكنك فقط تمرير المعطيات حرفيًا ، كمصفوفة.

بالمختصر:

  • إن توفير iep كوظيفة مدمجة سيكون بمثابة اختيار مؤقت لحفل منخفض لتقديم حجة مناسبة لتمريرها إلى البرامج الخارجية ، حتى يمكن تنفيذ الإصلاح المناسب - في سياق تغيير مفاجئ -

  • cmdlet Invoke-NativeShell ( ins ) هو الحل المناسب - وليس فجوة مؤقتة - لتوفير طريقة لاستدعاء أسطر أوامر shell المختلفة (الصدفة الأصلية) ، باستخدام بناء الجملة _its_ - انظر أعلاه .

حاليًا ، هناك حالات يفشل فيها قص أمر PERL ولصقه كما هو متوقع في Python. إذهب واستنتج. يجب أن يكون هذا عيبًا كبيرًا لجميع هؤلاء القواطع والقائمين هناك. أعتقد أنه يجب أن يكون لبايثون عامل خاص لذلك.

لست متأكدًا من أنك فهمت اقتراحي ؛ ما تقوله هو _بشكل دقيق_ ما أقوله. اسمحوا لي أن أكون أكثر تفصيلاً مع بعض التلميحات ذات الرسملة الاستراتيجية: د

# NEW SOLUTION: the entire pipeline AS ABOVE is sent to WSL, then the results are returned to powershell
# and piped, in powershell, to foreach-object
(& --% wsl ls | grep -i "foo") | % { "match {0}" -f $_ }

ما الذي افتقده هنا؟ إذا ظهر الأنبوب بعد --% فهو مجرد شخصية أخرى غبية: وسيطة. ليس هناك تلاعب بأسبقية عامل التشغيل. إذا تم احتوائه في خط أنابيب متداخل أو تعبير فرعي ، فابدأ في التحليل من أجل powerhell مرة أخرى.

أفكار؟

ما تفتقده هو الحاجة إلى تمرير قوس إغلاق كوسيطة لبرنامج خارجي. إنه نهج DWIM نموذجي - لكن PowerShell ليس HAL.

شكرا لجميع ردود الفعل المفصلة ، الجميع. أتحدث مثلي هنا. بضع نقاط قبل أن أتعمق أكثر في التفاصيل الجوهرية:

  • ما زلت غير مشترك مع vNext / 8.0 الذي يقرر كسر مجموعة جديدة كاملة من الأشياء. التوافق مع الإصدارات السابقة مهم. أعلم أنه أمر مؤلم ، وأنا أفضل العيش في عالم يمكننا فيه العودة وتصحيح كل خطأ ارتكبته PowerShell على الإطلاق ، والعديد منها غير مقصود. لكن الغالبية العظمى من مستخدمي PS لا يتسكعون هنا في المشاكل ، الركبة عميقة في حالات SO edge. لقد قاموا بنسخ / لصق نفس الحل البديل لشيء ما لمدة 4-10 سنوات ، ولا يعرفون بالضرورة سبب نجاحه ، ولن يهتموا بأننا كنا "نصلح الأخطاء" عندما يتعطل البرنامج النصي عند الترقية. إنهم يعرفون فقط أن "تحديث PS قد كسرني ، ولا يمكنني الوثوق في التحديثات" ، ثم ينتهي بنا الأمر مع المزيد من المستخدمين الذين يبطئون تحديثاتهم واعتمادهم.
  • أعتقد أن بعض الأشخاص في هذه المشكلة قد يتوقعون العديد من الآمال والرغبات المختلفة في هذه المشكلة ، أو يرون أنها إما / أو مع إصلاحات أخرى. أدرك أنني قد فاقمت ذلك بإغلاق # 1995 ، وأنا آسف لذلك (على الرغم من أنني سأقول ، ما زلت غير متأكد من أنه يمكن إصلاح واحد على وجه التحديد ، لكننا سنلقي نظرة أكثر جدية عليه) ، ولكن هذا هو حقًا حل "باب مصيدة" يخرج المستخدمين الجدد وذوي الخبرة من المأزق بسرعة دون ترك الإحباط يتصاعد. لا يزال بإمكاننا إجراء محادثات طويلة المدى حول إصلاحات جانب تحليل PS في المنزل حتى نتمكن من تقديم حل حقيقي عبر الأنظمة الأساسية لكل شيء.

الآن ، التعليقات كما قرأت:

  • أنا قلق بشأن الرغبة المقترحة في التوافق مع #! (إما مع &! أو $! نظرًا لأنه ، في الحالة الافتراضية ، من المحتمل ألا يقوم المستخدمون بتحديد المترجم الفوري . إذا كنت أريد أن أفعل شيئًا مثل $! net <stuff> ، net.exe ليس مترجمي. وفي غير أنظمة Windows ، فإن الشيء "الأصلي" الذي يجب فعله لا يزال يمر إلى sh / bash / أيًا كان من قبل الانتقال إلى الملف الثنائي الذي يتم تشغيله. على سبيل المثال ، لا أريد تحليل Python *.py في السلسلة $! /usr/bin/python *.py أو حتى $! python *.py . أريد أن يقوم Bash بالمراقبة ثم تسليم قائمة المطابقات مع python .
  • مثل oising المُقترَح ، أنا أؤيد --% كمُشغل ، مُحمّل بشكل زائد لاستخدامه في المقدمة. تُعد قابلية الاكتشاف مشكلة ، وبالنظر إلى أننا بالفعل 10 سنوات في العمل على اكتشاف إمكانية اكتشاف هذا واحد ( إنه أصبح الآن قادرًا على Google! ، أقول إننا نوافق على ذلك. (لقد كنت من صنع @ SteveL-MSFT ضعه في اقتراحه كاعتبار بديل) سؤال ، على الرغم من: هل نحتاج حتى إلى عامل الاتصال & هنا؟ لماذا لا نبدأ السطر بـ --% native.exe do /some $stuff ؟
  • rjmholt : لم أفهم تمامًا تعليقك هنا ، لكن من وجهة نظري أنه من المحتمل ألا نغير أي شيء باستخدام السلوك الحالي --% حيث يأتي بعد الملف القابل للتنفيذ ، ولكن أعتقد أنه يمكننا تنفيذ "الجديد" السلوك "حيث يأتي قبل الملف القابل للتنفيذ.
  • اقرأ هذا من jazzdelightsme وأنا أوافق بشكل قاطع:

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

    في رأيي ، هذا جانب كبير من السيناريو ، وربما أكبر جانب. إنها ليست SO فقط ، فهي مستندات من جميع أنحاء الويب تفترض مسبقًا أنك في غلاف يشبه Bash.

  • بصرف النظر عما إذا كانت أشياء مثل # 1995 قد تم إصلاحها ، فإن النقطة هنا هي أن أ) هناك ذيل طويل من الحالات الغريبة من هذا القبيل ، و ب) من الصعب حقًا إصلاحها دون كسر الأشخاص. ليس بالضرورة أن يكون هذا صحيحًا بالنسبة لهم جميعًا ، ولكننا حققنا ذلك بشكل كافٍ خلال العامين الماضيين لدرجة أنه من الواضح لي أننا بحاجة إلى "باب مصيدة" مثل هذا لإخراج الأشخاص من المواقف التي يتسمون فيها بالشعر حيث لا يريدون الغوص حفرة أرنب لدينا متداخلة الهروب (فقط لاكتشاف هناك خلل مثل # 1995 أن يمنعها من العمل ولو مرة واحدة أنهم لا يعرفون ما يعرفون).

عند مراجعة التعليقات ، أعتقد أن هناك سؤالين مفتوحين ما زلنا بحاجة إلى الإجابة:

  1. هل نستمر في تحليل فواصل الأوامر وكل شيء بعدها في PowerShell ، أم أن فاصل الأوامر يتم تمريره حرفيًا إلى الصدفة الأصلية؟
    أقول إننا يجب أن ننقل كل شيء حرفيًا إلى الغلاف الأصلي لأن هذا شيء لا يمكنك فعله حاليًا ، وأن حل oising لأصل رئيسي قد يكون هو الحل لأنه لا يزال بإمكاننا دعم الأنابيب وسلاسل خطوط الأنابيب ، إلخ. . إذا كنت تريد المزج / المطابقة بين التحليل الأصلي والتحليل PS (على الرغم من أنني أريد الحصول على بعض الآراء من أولئك الأقرب إلى المحلل اللغوي).
  2. ما هو المشغل؟
    كما أشرنا أعلاه ، أحب --% لأنه حصل بالفعل على سمعة باعتباره عامل التشغيل "فقط افعل ما كان يفعله" ، وسوف يتعين علينا إعادة ضبط القابلية للاكتشاف مع أي شيء جديد. أتفهم حججًا مثل @ mklement0 وهي أنه إذا فعلنا ذلك ، فإننا نغير المعنى الفني لـ --% (و @ SteveL-MSFT جعلت هذه الحجة لي أيضًا) ، لكنني لا أعتقد يفكر معظم الناس في البرية في --% من حيث "إنه يفعل ما كان يفعله في cmd". لا أعتقد أنه من المبالغة تدوين هذا الافتراض في تعريف المشغل على أنه "افعل ما تفعله الصدفة الأصلية هنا".

بشكل متعامد ، فكرت فقط في سيناريو آخر قد نرغب أو لا نريد دعمه.

في نظام Windows ، يتضمن cmd (بشكل فعال) الدليل الحالي في بحثه PATH . ومع ذلك ، يتطلب PowerShell أن يعلق المستخدم مسبقًا ./ أجل تنفيذ أي EXE (أو أي شيء في PATHEXT ) إذا لم يكن الدليل الحالي في PATH .

لذا فإن سؤالي المفتوح هو: هل نريد بالفعل تسليم سلسلة الأمر بأكملها إلى cmd؟ أقترح أنه إذا كنا نريد حقًا تسليط الضوء على سيناريو النسخ / اللصق باستخدام عامل التشغيل هذا ، فإن الإجابة هي نعم ، نظرًا لأن بعض المستندات / البرامج التعليمية التابعة لجهات خارجية لا توضح بالتفصيل بالضرورة كيفية وضع الأدوات التي يتوقعون منك استخدامها في PATH . ربما لا يهم كثيرًا في كلتا الحالتين ، لكنني أردت تعداده هنا.

  • ما زلت غير مشترك مع vNext / 8.0 الذي يقرر كسر مجموعة جديدة كاملة من الأشياء.

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

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

  • مثل oising المُقترَح ، أنا أؤيد --% كمُعامل ، --% native.exe do /some $stuff ؟

أنا حقا أحب هذا. من الناحية المثالية أقرب إلى استدعاء CreateProcess / exec قدر الإمكان (بالإضافة إلى معالجة nix env var وإعادة توجيه داخلي / خارجي أو مرفق وحدة التحكم). أو ربما يتراجع إلى cmd.exe / bash تمامًا.

أنا لست عالقًا في الاحتفاظ بـ & أمام --% أيضًا. يمكنني تبرير فكرة معاملة خام --% مثل التوجيه / المشغل في رأسي على الأقل. ماذا عن متعدد الأسطر؟ السماح --% مع @" و "@ لاستبدال var والتعبيرات الفرعية ، والاقتباس الفردي @' و '@ لتمرير الحرف؟ بدون السلاسل هنا ، إنه سطر واحد فقط؟

مثل oising المُقترح ، أنا أؤيد -٪ كمُشغل

يعمل لدي.

السؤال ، على الرغم من ذلك: هل نحتاج حتى إلى عامل التشغيل & Call هنا؟

طالما أنه لا يزال بإمكاني القيام بـ --% & $computedPathToNativeExe foo;@workspace فلا بأس من قبلي. نحن بحاجة إلى أن نكون قادرين على استخدام عامل الاتصال مع هذا.

أقول إننا يجب أن ننقل كل شيء حرفيا إلى الغلاف الأصلي لأن هذا شيء لا يمكنك فعله حاليًا

متفق عليه.

لا أعتقد أنه من المبالغة تدوين هذا الافتراض في تعريف المشغل (-٪) على أنه "افعل ما تفعله الصدفة الأصلية هنا".

وافق أيضا!

أيضًا ، ربما تكون هذه طريقة للدخول إلى الميزة لتعريف env vars قبل الملف القابل للتنفيذ الذي تم تحديده فقط لجلسة الملف التنفيذي (# 3316):

--% JEKYLL_ENV=production jekyll build

مجرد فكرة.

rkeithhill ، الفكرة مع call native operator هي أن الخط لا تتم معالجته بواسطة PowerShell ويتم إرساله حرفياً إلى "shell الافتراضي" لنظام التشغيل. لذلك في هذه الحالة ، لن يعمل المثال الأول --% & $computerPathToNativeExe foo;@workspace . سيكون عليك استخدام الطريقة الحالية والهروب حسب الاقتضاء. يجب أن تعمل الحالة الثانية --% JEKYLL_ENV=productoin jekyll build فقط.

لا تتم معالجة السطر بواسطة PowerShell ويتم إرساله حرفيًا إلى "الغلاف الافتراضي" لنظام التشغيل

حسنًا ، هذا يبدو معقولًا. ولكن هذا --% JEKYLL_ENV=productoin jekyll build سيعمل فقط على Linux / macOS ولكن ليس على Windows - على الأقل ليس بدون بعض المساعدة من PowerShell ، أليس كذلك؟

rkeithhill كما هو مقترح حاليًا لن يعمل أبدًا على Windows لأنه يعتمد على نظام التشغيل "الافتراضي" shell. بالنسبة إلى PowerShell الذي يعلن env var لعملية ما ، لدينا مشكلة مختلفة مفتوحة لمناقشة ذلك.

@ PowerShell / بوويرشيل-جنة ناقشت هذا اليوم ، لقد قمت بتحديث الاقتراح الأصلي ليعكس نتيجة تلك المناقشة. سنمضي قدمًا في تنفيذ ميزة تجريبية ونحصل على مزيد من التعليقات من المستخدمين برمز العمل. ما زلنا مفتوحين على سيجيل للمشغل ، ولكن باستخدام --% في الوقت الحالي

حيث $foo هو اسم ملف حرفي و $PWD هو الدليل الحالي داخل WSL. لاحظ أنه في المثال الأول ، يجب أن تعرف الهروب من && لتنفيذه داخل WSL بدلاً من داخل PowerShell.

كلا من $foo و $PWD مرجعان متغيران يتم تقييمهما بواسطة sh .

لإعادة إخراج هذا التنفيذ إلى PowerShell ، يجب على المستخدم تخزين النتائج في متغير أولاً:

$out = --% ls *.txt
$out | select-string hello

لاحظ أنه بخلاف عامل تشغيل المكالمات الحالي & ، لا يمكنك استخدام أي صيغة PowerShell ، لذلك:

--% $commandline

سيحاول تنفيذ $commandline حرفيًا (أقل من cmd ) أو بعد توسيع shell (أقل من sh ). لن يحاول PowerShell حل هذا المتغير.

يتم حل مشكلة القص واللصق ببساطة عن طريق اللصق بعد كتابة &n .

ببساطة عن طريق اللصق بعد --%

سيبدو المثال أعلاه لـ wsl كما يلي:

أي واحدة؟

نظرًا لأن جميع الوسائط بعد --% يتم تمريرها إلى shell "الافتراضي" ، لدعم التسلسل في PowerShell ، ستحتاج إلى استخدام متغير:

هذا تكرار.

إذا أردنا إضافة شيء مفيد أقترح Pivot.

لماذا لا نستطيع الحصول على شيء مثل حرفي هرطقة

@! ""! @

لذلك يمكننا الحصول على طريقة حقيقية للقيام بذلك بدلاً من -٪ التي لديها أيضًا مجموعة من المشكلات الخاصة بها.

على الأقل بهذه الطريقة يمكننا أن ندفن المشكلة بأساليب تصميم "أفضل".
وتوجد قابلية الاكتشاف لهذه الحالات المتطورة في About_Strings حيث يجب حلها.

مجرد فكرة.

فشلت في رؤية كيف أن @!"…"!@ أفضل من Invoke-NativeShell @"…"@ . هل نحاول جعل PowerShell أكثر شبهاً بالعقل؟

@ yecril71pl

فشلت في رؤية كيف أن @!"…"!@ أفضل من Invoke-NativeShell @"…"@ . هل نحاول جعل PowerShell أكثر شبهاً بالعقل؟

أعتقد أن @ romero126 يعني اقتراح حرف هرمي مباشر على الإنترنت ، بحيث يمكن للمرء أن يكتب

Invoke-NativeShell @!"complicated native command with "quotes" and | pipe"!@

بدلا من

Invoke-NativeShell @"
complicated native command with "quotes" and | pipe
"@

إذا تم النظر في مثل هذا التسلسل عبر الإنترنت ، فإنني أقترح استخدام بناء جملة مثل @"""…"""@ و @'''…'''@ ، فسيكون كتابة هذا أسهل من كتابة @!"…"!@ .


@ romero126 هل يمكنك توضيح ما تعنيه؟

@ yecril71pl شكرًا على وقم بتحديث الرسالة الأولى

لم يتم تحديد ما إذا كان سيتم تنفيذ --% كسطر أوامر أو كملف دفعي.

أعتقد أن @ romero126 يعني اقتراح حرف هرمي مباشر على الإنترنت ، بحيث يمكن للمرء أن يكتب

Invoke-NativeShell @!"complicated native command with "quotes" and | pipe"!@

بدلا من

Invoke-NativeShell @"
complicated native command with "quotes" and | pipe
"@

إذا تم النظر في مثل هذا التسلسل عبر الإنترنت ، فإنني أقترح استخدام بناء جملة مثل @"""…"""@ و @'''…'''@ ، فسيكون كتابة هذا أسهل من كتابة @!"…"!@ .

@ romero126 هل يمكنك توضيح ما تعنيه؟

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

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

قد يعني هذا المحور أيضًا أننا لن نضطر للتعامل مع المشكلات المذكورة أعلاه حيث نقوم بتدوير عجلاتنا على حل تقريبًا عندما نتمكن من التعامل مع حالة الحافة ، مقابل معالجة المشكلة ككل.

أمثلة سريعة:

# For this scenario let @!"<text>"!@ be our HereString Verbatim

Invoke-NativeShell @!"complicated native command with "quotes" and | pipe"!@
# or
Invoke-NativeShell @!"
Complicated native command with "quotes" and pipe and <tabs>
"!@

#or 
$r = @!"
complicated native command with custom arguments: {0}
"!@ -format "foo"
Invoke-NativeShell $r

هذا لا يعالج مشكلة غطاء @ mklement0 في الجزء الثاني من هذا التعليق . حقيقة الأمر هي أنه لا يمكننا تمرير سلسلة واحدة إلى كل قائد على الإطلاق ؛ في كثير من الحالات يجب تقسيمهم.

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

هذا هو الغرض من ' و @' .

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

تُرجع الأوامر الأصلية سلسلة من السلاسل. من المحتمل أن يصبح @!" عنصرًا أساسيًا لما يبدو عليه عدم وضوح الصوت.

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

هذا هو الغرض من ' و @' .

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

تُرجع الأوامر الأصلية سلسلة من السلاسل. من المحتمل أن يصبح @!" عنصرًا أساسيًا لما يبدو عليه عدم وضوح الصوت.

أعتقد بأنك محتار. مع النقطة التي كنت أوضحها.
علامات الاقتباس المنفردة والاقتباسات المزدوجة لا توسع إلا متغير $ أم لا. لا يهرب تلقائيًا من الأحرف. كما أنه يقيدني لذا لم يعد بإمكاني استخدام طابعه المميز. لذا بدلاً من ذلك لكي تعمل بشكل صحيح كما هي الآن. لا يزال يتعين علي الهروب من الأحرف وهذا هو السبب الكامل وراء حاجتنا إلى تضمين a &! أمر.

إذا كان لديك حل أفضل فأنا كلي آذان صاغية. أعتقد أن هذا يضرب حالات متطرفة أكثر من إضافة &!

علامات الاقتباس المنفردة والاقتباسات المزدوجة لا توسع إلا متغير $ أم لا. لا يهرب تلقائيًا من الأحرف. كما أنه يقيدني لذا لم يعد بإمكاني استخدام طابعه المميز. لذا بدلاً من ذلك لكي تعمل بشكل صحيح كما هي الآن. لا يزال يتعين علي الهروب من الأحرف وهذا هو السبب الكامل وراء حاجتنا إلى تضمين a &! أمر.

ما هي الشخصيات التي يجب عليك الهروب ولماذا؟

@ romero126 الآن أنا لديه سلسلة هنا ؟

اعتقدت سابقًا ، أنه يمكنك اعتبار بناء جملة powerhells هنا سلاسل مزعجة (على الأقل أنا منزعج أحيانًا ، لأنه يجب أن يكون هناك سطر جديد في البداية والنهاية ...) ، لكنني الآن لست متأكدًا مما انت تقول هل يمكن ان توضح؟

TSlivede ، وافق على أن السلاسل هنا مرهقة إلى حد ما من الناحية التركيبية.

هناك اقتراح حالي ، # 2337 ، يقترح تحسينات ، وبينما يركز على السماح بإدخال مسافة بادئة lzybkr أيضًا https: // github. com / PowerShell / PowerShell / issues / 2337 # issuecomment -391152107 ، مما يتيح لنا القيام بما يلي ، على سبيل المثال:

# `ins` is `Invoke-NativeShell`
ins @' python -c 'print("hi")' | cat -n '@

يمكن تجنب الحاجة إلى الهروب من خلال الجمع بين _multiple_ ' @ ، حسب الحاجة (على سبيل المثال ، @'' can use @' here ''@ .

بمعنى آخر: سيكون هذا تحسينًا عامًا لسلسلة PowerShell الحرفية ، والتي يمكن استخدامها في كل مكان ، والتي سيستفيد منها Invoke-NativeShell أيضًا.

نظرًا لأن # 2337 يركز بشكل أساسي على شيء آخر ، فقد قمت بإنشاء اقتراح مركز في # 13204 ، وأقترح أن نواصل المحادثة هناك.

سيتم تجنب الحاجة إلى الهروب

لقد رأيت هذا عدة مرات في هذا الموضوع.

سيحتاج أي مؤشر للرمز المميز لبدء وضع جديد إلى آلية هروب ، لأنك تحتاج إلى تمييز المؤشر إلى الرمز المميز الذي تتركه من هذا الوضع من الشكل الحرفي لذلك الحرف.

الشكل الأكثر طبيعية لذلك اليوم هو السلاسل ذات الاقتباس الفردي:

  • ' : ابدأ عملية الترميز ذات الاقتباس الفردي
  • ' : إنهاء ترميز الاقتباس الفردي
  • '' : اكتب اقتباسًا منفردًا حرفيًا ضمن سلسلة مقتبسة واحدة

أعتقد أن سبب حديثنا عن الهروب بالرغم من ذلك هو:

  • يحدد عامل التشغيل --% طرقًا كثيرة جدًا للخروج من وضعه ( | ، && ، || ، ; ، سطر جديد) ويسمح بالسلاسل بداخلها (تجريد شخصياتهم ' )
  • عزم Herestrings وزملائه على حجة سلسلة واحدة بدلاً من مجموعة منها

إن الرغبة في تمرير الوسائط إلى استدعاء قابل للتنفيذ تعني أننا نتحدث بالفعل عن بنية مصفوفة:

  • كيف تبدأ المصفوفة (ابدأ الوضع الحرفي)
  • كيفية فصل المصفوفة (تمرير وسيطة واحدة إلى الملف القابل للتنفيذ الجديد)
  • كيف تنتهي المصفوفة (نهاية الوضع الحرفي)

(هذا مفهوم أصلي في * nix ، نظرًا لأن exec يتوقع مصفوفة. في Windows ، أعتقد أننا مجبرون على أخذ مصفوفة ، وتسلسلها إلى بنية سلسلة معينة وتمريرها عبر CommandLineToArgvW . ومع ذلك ، يوفر .NET تجريدًا قائمًا على المصفوفة لكليهما - لذلك لا تزال المصفوفات منطقية للغاية)

هذا يعني أننا بحاجة إلى هروبين:

  • فاصل الصفيف حرفي
  • نهاية المصفوفة حرفية

على سبيل المثال ، دعنا نقول:

  • --% قبل أن يصبح الأمر الصيغة الحرفية الجديدة
  • كيف ننهي بناء الجملة؟ newline و ; ربما؟
  • كيف نفصل بين الحجج؟ ربما ؟

الأسئلة إذن هي:

  • كيف نمرر حرفيا ; أو سطر جديد؟
  • كيف نمرر ؟

سطر الأوامر الأصلي ليس مصفوفة. إنها إما سلسلة أو AST. نظرًا لأن PowerShell لا يعرف أي شيء عن ASTs في الأصداف الأصلية ، لم يتبق سوى سلسلة.

سطر الأوامر الأصلي ليس مصفوفة. إنها إما سلسلة أو AST

لم تقدم أي أسباب لهذا التأكيد.

إليك المكان الذي يبني فيه PowerShell AST لأمر (من أي نوع ، لأنه لا يعرف حتى وقت التشغيل عندما يحل الأمر نوع الأمر):

https://github.com/PowerShell/PowerShell/blob/f82f74d89811e91613a7450e536d652c5d8f784e/src/System.Management.Automation/engine/parser/Parser.cs#L6391 -L6634

لاحظ أن عناصر الأمر (بما في ذلك المعلمات والوسيطات) تُضاف إلى مصفوفة.

يمكنك رؤية هذا عمليًا في PowerShell مثل هذا:

> { ping 192.168.0.1 }.Ast.EndBlock.Statements[0].PipelineElements[0].CommandElements

StringConstantType : BareWord
Value              : ping
StaticType         : System.String
Extent             : ping
Parent             : ping 192.168.0.1

StringConstantType : BareWord
Value              : 192.168.0.1
StaticType         : System.String
Extent             : 192.168.0.1
Parent             : ping 192.168.0.1

يتم تجميع هذه المصفوفة في تعبيرات هنا:

https://github.com/PowerShell/PowerShell/blob/f82f74d89811e91613a7450e536d652c5d8f784e/src/System.Management.Automation/engine/parser/Compiler.cs#L4127 -L4160

ثم يتم تمرير ذلك إلى استدعاء خط الأنابيب هنا (لاحظ أن Expression.NewArrayInit(typeof(CommandParameterInternal[]), pipelineExprs) هو المكان الذي يتم فيه تمرير الوسيطات):

https://github.com/PowerShell/PowerShell/blob/f82f74d89811e91613a7450e536d652c5d8f784e/src/System.Management.Automation/engine/parser/Compiler.cs#L3798 -L3805

في وقت التشغيل ، عند تشغيل التعبيرات المترجمة ، يصبح ذلك استدعاء الطريقة هذا ، والذي يمر عبر هذا الاستدعاء الذي يقرر معالج الأوامر الذي يجب استخدامه:

https://github.com/PowerShell/PowerShell/blob/f82f74d89811e91613a7450e536d652c5d8f784e/src/System.Management.Automation/engine/runtime/Operations/MiscOps.cs#L29 -L312

في النهاية ، عندما يتم استدعاء خط الأنابيب ، فإن مصفوفة الوسيطة هذه مرتبطة بالأمر الأصلي باستخدام NativeCommandParameterBinder :

https://github.com/PowerShell/PowerShell/blob/f82f74d89811e91613a7450e536d652c5d8f784e/src/System.Management.Automation/engine/NativeCommandParameterBinder.cs#L69 -L137

يأخذ هذا مصفوفة الوسيطة ، التي تتضمن بيانات تعريف AST مثل نوع السلسلة التي تم استخدامها لكل وسيطة ، ويبني سلسلة جديدة لاستدعاء الوسيطة في NativeCommandProcessor هنا:

https://github.com/PowerShell/PowerShell/blob/f82f74d89811e91613a7450e536d652c5d8f784e/src/System.Management.Automation/engine/NativeCommandProcessor.cs#L1094 -L1166

يتم ذلك لأن .NET API الذي نستخدمه حاليًا لاستدعاء العملية هو الإصدار القديم "جميع الوسائط في سلسلة واحدة" ، بدلاً من الإصدار الجديد في .NET Core الذي يسمح لك بتمرير مصفوفة ويسمح لـ .NET بإعادة إنشاء الاستدعاء حسب الحاجة بطريقة محددة لمنصة.

لكننا باستخدام واجهة برمجة التطبيقات (API) هذه هي تفاصيل التنفيذ. على سبيل المثال ، يمكننا الاتصال بـ fork / exec مباشرة على * nix ، كما نفعل هنا:

https://github.com/PowerShell/PowerShell/blob/f82f74d89811e91613a7450e536d652c5d8f784e/src/powershell/Program.cs#L268 -L330

لاحظ أن exec هنا يأخذ مصفوفة - لقد فعلنا ذلك لأنها الطريقة الأبسط والأكثر مباشرة لتمرير الحجج إلى syscall ، والتي هي في النهاية الهدف من بناء جملة حرفية.

rjmholt :

_ وظيفيًا_ ، تتم تغطية جميع الاحتياجات بالفعل من خلال النماذج الحرفية الموجودة ، _ إذا قمت بتمرير سطر الأوامر الأصلي كسلسلة واحدة_ ، وهو ما أوصي به بشدة ، عبر Invoke-NativeShell / ins cmdlet جديد.

نقطة البداية هنا هي _سلسلة واحدة_ ، وليست مصفوفة: إنها _ سطر أوامر كامل _ - يتم تحليلها بواسطة shell الهدف _ - ومن المنطقي أن تعكس ذلك في PowerShell على هذا النحو - بدلاً من محاولة رفع الحذاء بشكل محرج بناء جملة قذيفة مختلفة في PowerShell بشيء مثل --%

كل ما يتعين على Invoke-NativeShell فعله هو تمرير السلسلة المفردة التي تحتوي على سطر أوامر shell الأصلي بالكامل إلى الصدفة الأصلية عبر CLI:

  • في نظام يونكس ، هذا يعني: تمرير السلسلة كما هي ، _ ككل_ ، كعنصر ثانٍ من الوسيطة _array_ تم تمريره إلى exec (مع -c هو أول عنصر مصفوفة وسيطة ، و /bin/sh الملف القابل للتنفيذ) ؛ معبرًا عنها في مصطلحات .NET بمثال بسيط ، حيث printf "'%s'" foo | cat -n هو المحتوى الحرفي للسلسلة المفردة التي تحتوي على سطر الأوامر للمرور (لاحظ استخدام .ArgumentList ، وليس .Arguments ؛ مضاعفة ' s قطعة أثرية من هذا المثال فقط):

    • $psi = [Diagnostics.ProcessStartInfo]::new('/bin/sh'); $psi.ArgumentList.Add('-c'); $psi.ArgumentList.Add('printf "''%s''" foo | cat -n'); [Diagnostics.Process]::start($psi).WaitForExit()
  • في Windows ، هذا يعني: لاستيعاب المراوغات cmd ، املأ الوسيطة lpCommandLine لـ CreateProcess النحو التالي (مع افتراض أن قيمة lpApplicationName هي قيمة متغير البيئة ComSpec ، والذي يشير إلى cmd.exe ): "/c " + cmdLine ، حيث cmdLine هو كامل سلسلة سطر الأوامر كما هي ؛ معبرًا عنها بمصطلحات .NET بمثال بسيط ، حيث echo a^&b & ver هو المحتوى الحرفي للسلسلة المفردة التي تحتوي على سطر الأوامر للمرور عبره:

    • $psi = [Diagnostics.ProcessStartInfo]::new($env:ComSpec); $psi.Arguments = '/c ' + 'echo a^&b & ver'; [Diagnostics.Process]::start($psi).WaitForExit()

      • @ yecril71pl ، هذا يعني الإجابة على سؤالك حول ما إذا كان يجب استخدام موجه الأوامر أو دلالات الملفات الدفعية: فهو الأول ، كما تستخدمه أيضًا لغات البرمجة النصية الأخرى ، مثل Python مع os.system() ؛ المعنى الضمني (ربما المؤسف) هو أنك لن تتمكن من الهروب من الأحرف % ، وأن متغيرات الحلقة for يجب أن تستخدم % (على سبيل المثال ، %i بدلاً من %%i )؛ وأنه يجب عليك إضافة بادئة لأوامر جسم الحلقة بـ @ لمنع صدى صوتها (على سبيل المثال ، for %i in (*.txt) do <strong i="56">@echo</strong> %i ).

ستكون هذه العملية _شفافة للمستخدم النهائي_ ، لذلك كل ما يحتاجون إلى التركيز عليه هو تمرير سطر أوامر shell الأصلي _verbatim_ ، حيث يحتاجون فقط إلى تلبية متطلبات بناء جملة _PowerShell's_ string-literal:

باستخدام النموذج ins @'<newline>...<newline>'@ ، يمكنك بالفعل _يمكنك_ استخدام أسطر أوامر shell الأصلية كما هي: انظر أعلاه لمعرفة كيف يمكن استخدام مختلف النماذج الحرفية الموجودة ، والتي - نظرًا لتوفر _interpolating_ هنا- نموذج السلسلة ( @"<newline>...<newline>"@ ) أيضًا - يتضمن القدرة على استخدام متغيرات وتعبيرات _PowerShell_ في سطر الأوامر (عدم القدرة على القيام بذلك هو أحد أوجه القصور الرئيسية في --% ).

ما يقترحه تعليقي السابق هو _شكل عام جديد من السلسلة الأولية الحرفية _ ، والتي _ منفصلة عن هذا الاقتراح _ (ومنطق التحليل الخاص به (نأمل) محدد جيدًا) ؛ على الرغم من ذلك ، كما هو مذكور ، فإن المكالمات Invoke-NativeShell ستكون عندئذٍ أكثر ملاءمة.

بدلاً من ما يمكنك فعله بالفعل (بافتراض أمر Invoke-NativeShell / ins ):

# ALREADY WORKS: Literal here-string
ins @'
python -c 'print("hi")' | cat -n
'@

باستخدام الحرفي الخام الجديد أحادي السطر المقترح ، يمكنك التبسيط إلى:

# PROPOSED, more convenient syntax: new raw literal.
ins @' python -c 'print("hi")' | cat -n '@

إذا كانت تفاصيل هذه الصيغة الجديدة للسلسلة الحرفية الخام تحتاج إلى مناقشة ، من فضلك دعنا نفعل ذلك في # 13204 ، وليس هنا.

لذا ، عند إعادة قراءة الاقتراح لفهم المقصد الأصلي ، أرى أنه في الحقيقة يطلب فقط صياغة أفضل لـ /bin/sh -c '<command>' + إصدار cmd ، جنبًا إلى جنب مع منطق هروب سلسلة خاص لكل قذيفة هدف. لقد بنيت تصوري الأولي على بناء جملة خاص وأحتاج إلى العمل مع المحلل اللغوي ومعالج الأوامر الأصلي ، ومن الصعب جدًا استخدام خاصية .NET ProcessStartInfo.Arguments بشكل صحيح فيما يتعلق بتمرير عرض الأسعار .

ولكن في الواقع ، يتم تمرير السلسلة النصية Arguments حرفياً . لذا كل ما علينا فعله هو تمرير مثل هذه السلسلة مباشرة.

في هذه الحالة ، أعتقد أن أي بناء جملة جديد غير ضروري تمامًا (سيؤدي فقط إلى تعقيد منطق الترميز وأعتقد أنه يربك الناس) وبدلاً من ذلك ، هذا مجرد أمر جديد ، ins كما تقول. NET لديها بعض المنطق لهذا هنا والذي سنضطر إلى إعادة تنفيذه ، لكن هذا جيد لأننا نحتاج إلى أن نكون أكثر ذكاءً على أي حال.

بعض التعليقات علىrjmholt الصورة تعليق https://github.com/PowerShell/PowerShell/issues/13068#issuecomment -660231641

سيحتاج أي مؤشر للرمز المميز لبدء وضع جديد إلى آلية هروب ، لأنك تحتاج إلى تمييز المؤشر إلى الرمز المميز الذي تتركه من هذا الوضع من الشكل الحرفي لذلك الحرف.

أوافق ولا أعتقد أن بناء جملة في السطر هنا يمكن أن يتجنب تمامًا الحاجة إلى الهروب.

يحدد عامل التشغيل -٪ طرقًا كثيرة جدًا للخروج من وضعه (| ، && ، || ، ؛ ، سطر جديد) ويسمح بالسلاسل داخله (تجريد أحرفها)

عند الحديث عن --% ، هل تشير إلى المحول الحالي --% ؟ إذا كان الأمر كذلك ، فمن الأفضل توضيح ذلك في تعليقك ، حيث يُقترح الآن أن يكون --% مشغل مكالمات.

إن الرغبة في تمرير الوسائط إلى استدعاء قابل للتنفيذ تعني أننا نتحدث بالفعل عن بنية مصفوفة:

الاقتراح هو استدعاء shell الأصلي (sh أو cmd) وتمرير كل شيء حرفياً بعد عامل الاتصال --% ، مثل sh -c ... . لذلك ليس بوويرشيل هو الذي يمرر الحجج إلى الهدف القابل للتنفيذ. في هذه الحالة ، أعتقد أننا لسنا بحاجة إلى بنية مصفوفة ، أليس كذلك؟

كيف ننهي بناء الجملة؟ خط جديد و يمكن؟
كيف نفصل بين الحجج؟ "الفضاء" ربما؟

أعتقد أن التحليل الحرفي ينتهي عند سطر جديد. لتمرير سطر جديد كجزء من الوسيطة ، استخدم \n أعتقد ، تمامًا كما تفعل في bash مباشرةً.

سطر الأوامر الأصلي ليس مصفوفة. إنها إما سلسلة أو AST

لم تقدم أي أسباب لهذا التأكيد.

إليك المكان الذي يبني فيه PowerShell AST لأمر (من أي نوع ، لأنه لا يعرف حتى وقت التشغيل عندما يحل الأمر نوع الأمر):

إذا تم تنفيذ هذا الاقتراح ، فسوف يقدم بنية خاصة حيث لن يقوم PowerShell ببناء AST على الإطلاق.

سعيد لسماع ذلك ،rjmholt.

NET لديها بعض المنطق لهذا هنا والذي سنضطر إلى إعادة تنفيذه

لا أعتقد أننا في الواقع بحاجة إلى إعادة تنفيذ أي شيء ، كما تظهر الأوامر الواردة في تعليقي السابق: على Windows ، استخدم .Arguments لتمرير سلسلة سطر الأوامر بالكامل إلى WinAPI ؛ في نظام التشغيل Unix ، استخدم .ArgumentList لإنشاء الوسيطة _array_ التي تُستخدم مباشرةً مع exec .

إذا تم تنفيذ هذا الاقتراح ، فسوف يقدم بنية خاصة حيث لن يقوم PowerShell ببناء AST على الإطلاق.

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

_ وظيفيًا_ ، تتم تغطية جميع الاحتياجات بالفعل من خلال النماذج الحرفية الموجودة ، _ إذا قمت بتمرير سطر الأوامر الأصلي كسلسلة واحدة_ ، وهو ما أوصي به بشدة ، عبر Invoke-NativeShell / ins cmdlet جديد.

أنا شخصياً أحب فكرة cmdlet Invoke-NativeShell ، من بعض النواحي أفضل من عامل الاتصال --% . مصدر القلق الرئيسي الذي سمعته عن هذه الفكرة هو أنها كتابة أكثر من --% + Ctrl + v وتمييز سلسلة هنا الحرفية من استيفاء سلسلة هنا هو عبء آخر على المستخدم (_أعتقد شخصيًا أن ins أسهل طريقة للكتابة من --% _).

القلق الرئيسي الذي سمعته عن هذه الفكرة هو أنها كتابة أكثر من --% + Ctrl + v وتمييز سلسلة هنا الحرفية من استيفاء سلسلة هنا هو عبء آخر على المستخدم (_أعتقد شخصيًا ins أسهل طريقة للكتابة من --% _).

ربما يمكن أن تساعد PSRL. على غرار المشكلة المتعلقة بمعالج المفاتيح لإحاطة المسارات الملصقة ، يمكن لـ PSRL قراءة CommandAst ، ورؤية أنه ins والهروب بشكل صحيح من السلسلة الملصقة.

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

بالتأكيد لكن الشجرة ستكون تافهة. لن يعكس معنى الأوامر التي سيتم تنفيذها.

ابدأ عملية إعادة توجيه cmd.exe stdin / stdio ويمكننا حرفياً استخدام سلسلة لاستدعاء NativeCommand نفسه مع bash

سعيد لسماع ذلك ، @ daxian-dbw.
أحب الفكرة ، SeeminglyScience .

يعتبر التفريق بين سلسلة هنا الحرفية واستيفاء سلسلة هنا عبئًا آخر على المستخدم

أعتقد أن هذا _plus_ ، لأنه - على عكس --% - يتيح لك استخدام @"<newline>...<newline>"@ دمج قيم متغيرات وتعبيرات PowerShell_ مباشرةً في سطر الأوامر الأصلي.

بالطبع ، هذا يفترض أن المستخدمين يعرفون الفرق بين السلاسل ذات الاقتباس الفردي (حرفيا) والمزدوجة الاقتباس (الاستيفاء) وحول الانتقائية ` الهروب من $ ، لكنني أعتقد أنها مهمة (متقدم) الخيار لديك.

لمساعدة مستخدمي القص واللصق ، يجب أن تكون ميزة PSReadLine المقترحة افتراضيًا على @'<newline>...<newline>'@ (حرفيا).


في النهاية ، لا نريد الترويج لعقلية لا يحتاج المستخدمون فيها إلى معرفة وفهم متطلبات بناء الجملة الفريدة لـ PowerShell - بدلاً من ذلك ، نريد تعزيز فهمهم ، في ضوء _القوة المضافة التي يجلبونها_.

ولكن لتشجيع المستخدمين على استخدام بناء جملة PowerShell's _own_ ، والذي يعد بحكم التعريف _ عبر النظام الأساسي_ ، يجب أن يعمل بشكل متوقع .
تحقيقا لهذه الغاية ، يجب إصلاح # 1995 ، بشكل مثالي بشكل مباشر ، السماح بتغيير كسر ، أو ، إذا لم يكن هذا خيارًا ، عبر مراسم بسيطة _opt-in_.

كي تختصر:

  • شيء من هذا القبيل --% (نموذج المشغل الجديد المقترح هنا) ، حسب التعريف ، ميزة خاصة بالمنصة ، ليس بأي حال من الأحوال بديلاً لإصلاح # 1995 .

  • Invoke-NativeShell ( ins ) يتجنب كل قيود عامل التشغيل المقترح --% ويوفر حل "trap door" الذي ذكره joeyaiello : طريقة سريعة لتنفيذ سطر أوامر مكتوب للقشرة الأصلية ، دون الحاجة إلى تكييفها مع بناء جملة PowerShell.

  • يجب أن يظل --% في شكله _النموذج_ الأصلي فقط ، ويجب أن يظل ميزة _Windows-only_ (والتي _ فعالة_ ، وإن لم تكن _ من الناحية الفنية_) - بعبارة أخرى: لا حاجة للتغيير.

    • بمجرد إصلاح # 1995 ، سيكون الغرض الوحيد --% هو استيعاب حالات _edge على Windows_: السماح لك بالتحكم في الاقتباس الصريح لسطر الأوامر الذي تم تمريره إلى البرامج المارقة مثل msiexec التي تتطلب أشكال محددة للغاية من الاقتباس داخل الحجة.

إحدى الميزات الأخرى التي أريدها حقًا في PS v7.x هي القدرة على إخراج أمر أصلي برمز خطأ يوقف البرنامج النصي الخاص بي ، مثل set -e كما تمت مناقشته في RFC هذا. إذا كان حل ذلك هو شيء مثل Invoke-NativeCommand ، فهل سيتسبب ذلك في الخلط مع Invoke-NativeShell ؟

مجرد محاولة تشغيل الفيلم إلى الأمام قليلاً لأنني بقدر ما أريد ميزة الاتصال الأصلية ، أريد حقًا أن تخطئ البرامج النصية للبناء والاختبار عند استدعاء msbuild و cl و cmake و Conan و npm وما إلى ذلك وتخرج تلك الأوامر الأصلية باستخدام رمز خروج غير صفري دون الحاجة إلى تذكر التحقق من $ LASTEXITCODE طوال الوقت. إذا كان التنفيذ عن طريق متغير تفضيل آخر مثل $PSNativeCommandInErrorActionPreference إذن أفترض أن ذلك سيؤثر على استدعاء الصدفة الأصلية - هل هي "أمر" أصلي وكل شيء؟

القلق الرئيسي الذي سمعته عن هذه الفكرة هو أنها كتابة أكثر من --% + Ctrl + v وتمييز سلسلة هنا الحرفية من استيفاء سلسلة هنا هو عبء آخر على المستخدم (_أعتقد شخصيًا ins أسهل طريقة للكتابة من --% _).

ربما يمكن أن تساعد PSRL. على غرار المشكلة المتعلقة بمعالج المفاتيح لإحاطة المسارات الملصقة ، يمكن لـ PSRL قراءة CommandAst ، ورؤية أنه ins والهروب بشكل صحيح من السلسلة الملصقة.

لكن ماذا عن:

$c = gcm ins
& $c ...

سيواجه PSRL صعوبة في التعرف على ما يحدث هناك. يجب أن يكون مفهوماً ، وحل الأسماء المستعارة لاستدعاء nativeshell ، ثم اكتشف أنك تريد استدعاء commandinfo ، ثم قم بإلغاء تشكيل args؟ أنا حقا ، حقا لا أحب فكرة الغلاف الخاص لأمر مزيف.

يعتبر التفريق بين سلسلة هنا الحرفية واستيفاء سلسلة هنا عبئًا آخر على المستخدم

أعتقد أن هذا _plus_ ، لأنه - على عكس --% - يتيح لك استخدام @"<newline>...<newline>"@ دمج قيم متغيرات وتعبيرات PowerShell_ مباشرةً في سطر الأوامر الأصلي.

أنا لا أتابعك @ mklement0. لماذا لا يمكن تعليم --% للقيام بذلك؟ لقد أعطيت هذا بالفعل كحالة استخدام.

أنا حقا ، حقا لا أحب فكرة الغلاف الخاص لأمر مزيف.

لا يوجد أمر مزيف هنا ، فقط أمر cmdlet حسن النية ، Invoke-NativeShell ، اسم مستعار إلى ins .

سيوفر gcm ins ( Get-Command ins ) معلومات حول الاسم المستعار ins في شكل مثيل [System.Management.Automation.AliasInfo] ، والذي يمكنك تمريره لاحقًا إلى & للاستدعاء ، كما هو الحال مع أي أمر آخر أو اسم مستعار.

لذلك ، سيعمل المثال الخاص بك تمامًا على النحو المنشود - إنه فقط إذا استخدمت التحويلة gcm ( Get-Command ) ، فسيتعين عليك توضيح البنية الحرفية المناسبة _yourself_ ، بدون _ سقالات أمر الراحة الاختيارية _ التي يمكن أن توفرها PSRL ، إذا تم تنفيذ اقتراح SeeminglyScience :

$c = gcm ins
& $c @'
python -c 'print("hi")' | cat -n
'@

أو ، إذا تم تنفيذ الصيغة الحرفية الجديدة للسلسلة الأولية المقترحة في # 13204:

$c = gcm ins
& $c @' python -c 'print("hi")' | cat -n '@

بالطبع ، إذا كنت معتادًا على بناء جملة القيم الحرفية لسلسلة PowerShell ، فستعمل السلسلة ذات الاقتباس الفردي العادية أيضًا: ما عليك سوى مضاعفة ' داخل السلسلة الإجمالية '...' :

$c = gcm ins
& $c 'python -c ''print("hi")'' | cat -n'

لماذا لا يمكن تعليم --% للقيام بذلك؟

  • يفتقر --% إلى محدد الإغلاق ، مما يمنعه من استخدامه في خطوط أنابيب Powershell ، وهو قيد غير مقبول (لاحظ أن (...) الضميمة _لا _ خيار ، لأن ذلك يعني ضمناً التجميع المسبق لجميع المخرجات في الذاكرة بدلاً من المعالجة المتدفقة).

  • في نظام التشغيل Unix ، لا يمكن أن يدعم --% _both_ (بدون إلغاء) $ كحرف أولي لـ PowerShell _ و_ كحرف أول POSIX-shell

مرة أخرى: لا يوجد مبرر ولا فائدة من تأليف بناء جملة مختلف للقذيفة في PowerShell - مرر سطر أوامر shell الأصلي _ كسلسلة_ ، إلى ins ، وستختفي جميع المشكلات المفاهيمية.

يشير Invoke-NativeShell إلى أن PowerShell ليس الغلاف الأصلي. هل هذا الافتراض صحيح دائمًا وسيظل كذلك دائمًا؟

oising the use case هو شخص يقوم بنسخ ولصق أمر أصلي من README أو شيء ما. إذا كانوا يفعلون شيئًا أكثر تعقيدًا من كتابة ins SPACE CTRL + v ، فسيقومون ببناء سلسلة خاصة بهم والهروب منها كالمعتاد.

ههههههههه

ولكن لتشجيع المستخدمين على استخدام بناء جملة PowerShell's _own_ ، والذي يعد بحكم التعريف _ عبر النظام الأساسي_ ، يجب أن يعمل بشكل متوقع .
تحقيقا لهذه الغاية ، يجب إصلاح # 1995 ، بشكل مثالي بشكل مباشر ، السماح بتغيير كسر ، أو ، إذا لم يكن هذا خيارًا ، عبر مراسم بسيطة _opt-in_.

هذا منفصل عن المناقشة على ins / --% أليس كذلك؟ إذا كنت لا توافق ، هل يمكنك توضيح سبب تأثير هذه المشكلة على الأمر / بناء الجملة الجديد؟

SeeminglyScience ، نعم ، إنها منفصلة ، لكن هذا لم يكن واضحًا في هذا الموضوع.
السبب الوحيد لظهور # 1995 هنا هو أنه تم إغلاقه في الأصل لصالح هذه المشكلة (على الرغم من إعادة فتحه لحسن الحظ منذ ذلك الحين) ، ولا يزال OP هنا ينص على أن هذه المشكلة ستصلحها ("يجب أن يحل هذا أيضًا هذه المشكلات:") .
لذلك ، أردت أن أؤكد أن ins / --% لن _not_ عنوان # 1995 ، الأمر الذي يتطلب إصلاحه الخاص ، بشكل عاجل.
(فقط إذا كانت حجة PowerShell الخاصة بالتمرير تعمل بشكل صحيح ، يمكننا أن نوصي بضمير جيد بأن يتعلم المستخدمون تمامًا ويتبنوا بناء جملة PowerShell الخاص - وهو ما يجب علينا.)

@ SP3269 ، يمكننا عبور هذا الجسر عندما نصل إليه 😁.

لكن بجدية:

إذا كنت تفكر في كلمة "أصلي" على أنها "مكتوبة خصيصًا للمنصة المضيفة [العائلة]" ، فسيظل الاسم مناسبًا ، حتى لو كان PowerShell يجب أن يصبح هيكل النظام الافتراضي على نظام أساسي معين (هذا ما نأمله ، لكنني لا أعتقد هذا واقعي ، على الأقل ليس في المستقبل المنظور).

بالنسبة للبدائل:

  • Invoke-[System]DefaultShell هو الاسم الأكثر دقة (على الرغم من أنه لن يتم تطبيقه بشكل لا لبس فيه إذا أصبح PowerShell في أي وقت قشرة افتراضية للنظام) ، ولكن يبدو أن مصطلح "أصلي" هو المصطلح الأكثر استخدامًا في عالم PowerShell.

  • Invoke-LegacyShell لديه بعض المبررات على Windows ، لكنني لا أعتقد أن مستخدمي Unix سيتعاملون بلطف شديد مع هذا المصطلح.

أعتقد أنني بدأت في كشف الارتباك المطلق الذي أواجهه في محاولة تتبع دوافع وأفكار وقضايا الجميع هنا. يبدو أننا ( @ mklement0 وأنا ، على الأقل) ننظر إلى هذا على أنه حلين مختلفين --% كتلميح إلى _parser_ لتغيير الطريقة التي يتم بها تحليل الأشياء بالاقتران مع عامل التشغيل & (وليس بالضرورة استخدام --% مستقل.) من ناحية أخرى ، يبدو أن مايكل ينظر إلى ins باعتباره أمر cmdlet للإسقاط لاستبدال وسيط الأوامر الأصلي الداخلي ومحلل الحجة الخاص بـ powerhell ، ولا يتطلع إلى تغيير محلل powerhell ، بدلاً من ذلك ، باستخدام سلاسل / هنا - سلاسل لالتقاط المعلمات المقصودة (والتي أقولها يمكن استخدامها مع --% أيضًا.)

- يفتقر٪ إلى محدد الإغلاق ، مما يمنع استخدامه في خطوط أنابيب Powershell

هذه النقطة لا أفهمها على الإطلاق. لم يعد يفتقر إلى محدد إغلاق أكثر من الأمر ins / invoke-nativecommand. إذا كنت بحاجة إلى التحديد أو التغذية من LHS ، فاستخدم هنا سلاسل ، وإلا فسيتم اعتبارها بمثابة بيان واحد.

بغض النظر عن الطريقة التي يتم اختيارها ، يبدو أنه ستكون هناك حاجة لاختيار shell أصلي لإرسال سطر الأوامر. أقترح استخدام متغيرات البيئة COMSPEC على نظام التشغيل Windows (القيم الافتراضية هي %systemroot%\system32\cmd.exe ) و SHELL على Linux (الإعدادات الافتراضية هي /bin/bash ) - إذا لم يكن SHELL ' إذا كان موجودًا ، يجب أن نستهدف /bin/sh (وهو في معظم الحالات رابط رمزي للتقسيم على أي حال.)

- يفتقر٪ إلى محدد الإغلاق ، مما يمنع استخدامه في خطوط أنابيب Powershell

هذه النقطة لا أفهمها على الإطلاق. لم يعد يفتقر إلى محدد إغلاق أكثر من الأمر ins / invoke-nativecommand. إذا كنت بحاجة إلى التحديد أو التغذية من LHS ، فاستخدم هنا سلاسل ، وإلا فسيتم اعتبارها بمثابة بيان واحد.

في الأساس لا يمكنك استدعاء أشياء مثل cmd --% /c someapp | someOtherApp ولديك cmd للتعامل مع خط الأنابيب ؛ لا يزال PowerShell يفسر خط الأنابيب (وبعض الأشياء الأخرى مثل && و || والتي قد تكون مفيدة لأفراد Unix) على أنها رمز PowerShell بدلاً من تمريرها إلى الأمر الأصلي كجزء من سلسلة الوسيطة.

و SHELL على Linux (القيمة الافتراضية هي /bin/bash )

لا: غلاف _system_ على الأنظمة الأساسية الشبيهة بـ Unix هو _invariably_ /bin/sh .
يختلف هذا عن قذيفة تفاعلية _user_ معينة (تنعكس في $env:SHELL - ولكن ، للأسف ، ليس حاليًا إذا كان _PowerShell_ هو غلاف المستخدم ، انظر # 12150) ، وهو (أ) قابل للتكوين و (ب) غالبًا _defaults to_ /bin/bash ، ولكن حتى هذا ليس معطى ، كما يتضح من انتقال macOS مؤخرًا إلى /bin/zsh كصدفة تفاعلية افتراضية للمستخدمين الجدد.

أقترح استخدام متغيرات البيئة COMSPEC على Windows

نقطة جيدة ، هذه هي الطريقة الأفضل للإشارة إلى غلاف النظام (مترجم الأوامر) على Windows - لقد قمت بتحديث الأمر النموذجي أعلاه وفقًا لذلك.

إحدى الميزات الأخرى التي أريدها حقًا في PS v7.x هي القدرة على إخراج أمر أصلي برمز خطأ يوقف البرنامج النصي الخاص بي ، مثل set -e كما تمت مناقشته في RFC هذا. إذا كان حل ذلك هو شيء مثل Invoke-NativeCommand ، فهل سيتسبب ذلك في الخلط مع Invoke-NativeShell ؟

مجرد محاولة تشغيل الفيلم إلى الأمام قليلاً لأنني بقدر ما أريد ميزة الاتصال الأصلية ، أريد حقًا أن تخطئ البرامج النصية للبناء والاختبار عند استدعاء msbuild و cl و cmake و Conan و npm وما إلى ذلك وتخرج تلك الأوامر الأصلية باستخدام رمز خروج غير صفري دون الحاجة إلى تذكر التحقق من $ LASTEXITCODE طوال الوقت. إذا كان التنفيذ عن طريق متغير تفضيل آخر مثل $PSNativeCommandInErrorActionPreference إذن أفترض أن ذلك سيؤثر على استدعاء الصدفة الأصلية - هل هي "أمر" أصلي وكل شيء؟

لدينا Start-NativeExecution في وحدة build الخاصة بنا لهذا الغرض.

لقد رأيت ذلك. كيف ستجمع بالضبط بين Start-NativeExecution Invoke-NativeShell إذا كنت ترغب في أن يقوم الأحدث برمي رمز خروج غير صفري بشكل فعال؟ آمل حقًا أن يكون شيء مثل PR # 3523 متوافقًا مع ميزة الاتصال الأصلية هذه لأنني أريد أن يعمل الاثنان معًا. أفترض أنه إذا تم تنفيذ استدعاء winds الأصلي باعتباره cmdlet (Invoke-NativeShell مقابل -٪) ، فيمكن تنفيذ -ErrorAction Stop لإلقاءه (خطأ إنهاء) على رمز خروج غير صفري.

- يفتقر٪ إلى محدد الإغلاق ، مما يمنع استخدامه في خطوط أنابيب Powershell

هذه النقطة لا أفهمها على الإطلاق. لم يعد يفتقر إلى محدد إغلاق أكثر من الأمر ins / invoke-nativecommand. إذا كنت بحاجة إلى التحديد أو التغذية من LHS ، فاستخدم هنا سلاسل ، وإلا فسيتم اعتبارها بمثابة بيان واحد.

في الأساس لا يمكنك استدعاء أشياء مثل cmd --% /c someapp | someOtherApp ولديك cmd للتعامل مع خط الأنابيب ؛ لا يزال PowerShell يفسر خط الأنابيب (وبعض الأشياء الأخرى مثل && و || والتي قد تكون مفيدة لأفراد Unix) على أنها رمز PowerShell بدلاً من تمريرها إلى الأمر الأصلي كجزء من سلسلة الوسيطة.

نعم ، أفهم السلوك الحالي @ vexx32 . لكننا لا نتحدث (على الأقل أنا لا) عن السلوك الحالي لـ --% - نحن نتحدث عن تحسينه ، أليس كذلك؟ لماذا أشعر بأننا نتحدث جميعًا حول بعضنا البعض هنا؟ :)

كما قلت بالطريقة السابقة ، يمكننا تحسين & للعمل مع --% لذلك هذا ممكن . أعتقد أيضًا أننا بحاجة إلى أن نكون واضحين بشأن exec الأصلي الضمني مقابل الاستدعاء الصريح للصدفة مع الحجج. هذا مصدر دائم للارتباك - حتى بالنسبة لمستخدمي الويندوز المخضرمين - أن الأمر cmd.exe (a shell) مطلوب بطريقة ما "لتشغيل" الملفات التنفيذية الأخرى ؛ الأمر نفسه ينطبق على نظام التشغيل Linux / osx.

نعم ، أفهم السلوك _current_ @ vexx32 . لكننا لا (على الأقل أنا لا) نتحدث عن السلوك _الحالي _ --% - نحن نتحدث عن تحسينه ، أليس كذلك؟ لماذا أشعر بأننا نتحدث جميعًا حول بعضنا البعض هنا؟ :)

لذا فإن الخطوة الحالية لضبط --% هي أنه إذا كان هذا هو المكان الذي سيكون فيه اسم الأمر عادةً ، فسيتم تحليل كل شيء على يمينه كما هو (حتى سطر جديد) وإرساله مباشرةً إلى bash / cmd. لا توجد مساحة لأي بنية PowerShell مثل هنا سلاسل وما ليس لأنه يعاني من نفس المشكلات التي يواجهها حاليًا معالج الأوامر الأصلي --% .

لقد رأيت ذلك. كيف ستجمع بالضبط بين Start-NativeExecution Invoke-NativeShell إذا كنت ترغب في أن يقوم الأحدث برمي رمز خروج غير صفري بشكل فعال؟ آمل حقًا أن يكون شيء مثل PR # 3523 متوافقًا مع ميزة الاتصال الأصلية هذه لأنني أريد أن يعمل الاثنان معًا. أفترض أنه إذا تم تنفيذ استدعاء winds الأصلي باعتباره cmdlet (Invoke-NativeShell مقابل -٪) ، فيمكن تنفيذ -ErrorAction Stop لإلقاءه (خطأ إنهاء) على رمز خروج غير صفري.

حاليًا سيكون Start-NativeExecution { Invoke-NativeShell <strong i="10">@whatever</strong> } .

هذه النقطة لا أفهمها على الإطلاق. لم يعد يفتقر إلى محدد إغلاق أكثر من الأمر ins / invoke-nativecommand. إذا كنت بحاجة إلى التحديد أو التغذية من LHS ، فاستخدم هنا سلاسل ، وإلا فسيتم اعتبارها بمثابة بيان واحد.

Invoke-NativeShell لا _ يحتاج_ إلى أي محدد إغلاق لأنه أمر عادي ، بينما الرعب --% ليس كذلك.

و SHELL على Linux (القيمة الافتراضية هي /bin/bash )

لا: غلاف _system_ على الأنظمة الأساسية الشبيهة بـ Unix هو _invariably_ /bin/sh .

أعتقد أن الشيء يجب أن يكون مكافئًا لإنشاء ملف نصي قابل للتنفيذ وتشغيله ، والذي يفوض مهمة اختيار الصدفة الصحيحة لنظام التشغيل ولا ينبغي أن نتضايق. بما في ذلك ، إذا كان يبدأ بـ #! ، فليكن.

الفكرة وراء Invoke-NativeShell هي توفير غلاف ملائم حول _CLI_ للقشرة الأصلية.

  • في نظام يونكس ، هذا كافٍ تمامًا ، وإنشاء ملف نصي إضافي لا يؤدي فقط إلى زيادة النفقات الإضافية ، ولكن بعد ذلك يبلغ عن قيمة عشوائية في $0 (مسار ملف البرنامج النصي) ، بينما الاستدعاء عبر CLI يحتوي على /bin/sh هو متوقع sh -c 'echo $0' foo )

    • (جانبا: إنشاء نص برمجي مع سطر shebang #!/bin/sh يعني استهداف غلاف النظام بالمسار الكامل تمامًا مثل استدعاء /bin/sh مباشرة).
  • على ويندوز، وتنفيذ طريق ملف دفعي _would_ جلب مزايا (ولكن ليس لتفويض مهمة تحديد مكان وجود قذيفة النظام الذي $env:ComSpec لا يمكن التنبؤ به)، كما أن تجنب المشاكل مع % الهروب وسلوك for المذكور أعلاه .

للتعامل مع هذا الأخير على سبيل المجاملة (حتى لا يضطر المستخدمون إلى كتابة ملفات aux الخاصة بهم) ، من أجل الوضوح المفاهيمي ، يمكننا تقديم
مفتاح -AsBatchFile كـ _opt-in_.

ومع ذلك ، إذا كان هناك إجماع على أن غالبية أسطر الأوامر العامة cmd المستخدمة للقص واللصق تتم كتابتها مع وضع دلالات _batch-file_ في الاعتبار ( %%i بدلاً من %i كمتغير حلقة ، القدرة على الهروب من الحرف % كـ %% ) ، ربما بشكل دائم باستخدام aux. يعد ملف الدُفعات _ على Windows_ (أثناء التمسك بـ CLI على Unix) هو الحل الأفضل - لا أشعر بشدة بهذا الأمر ، ولكن يجب توثيقه بوضوح ، لا سيما بالنظر إلى أنه يعني إظهار سلوك مختلف عن لغات البرمجة النصية الأخرى.

تضمين التغريدة

بالنسبة لي ، فإن تكامل أخطاء RFC التي ترتبط بها يستحق المعالجة بشكل عاجل مثل # 1995:

كلاهما يمثل خطوات ضرورية نحو جعل البرامج الخارجية (المرافق الأصلية) مواطنين من الدرجة الأولى في PowerShell (قدر الإمكان من الناحية المفاهيمية) ، وهو ما كان يجب أن يكون دائمًا.

أن تكون مواطنًا من الدرجة الأولى يعني: _direct_ (استدعاء & مطلوب فقط لأسباب تزامنية _ ، ظرفية) ، وليس _ عبر cmdlet_.
بمعنى آخر: يجب ألا يكون هناك cmdlet Invoke-NativeCommand أو cmdlet Start-NativeExecution .

(جانبا: تم تسمية Start-NativeExecution خطأ ، حيث أن العديد من الوظائف في الوحدة النمطية build هي ؛ إشارات Start _ غير متزامنة_ ، في حين أن معظم هذه الوظائف _ متزامنة _ - راجع المناقشة حول Start-Sleep على https://github.com/MicrosoftDocs/PowerShell-Docs/issues/4474).

لذلك ، لا يتطلب Invoke-NativeShell أي اعتبار خاص: سيقوم PowerShell ، كما هو الحال بالفعل ، بتعيين $LASTEXITCODE استنادًا إلى رمز الخروج الذي تم الإبلاغ عنه بواسطة عملية تنفيذ الصدفة الأصلية ( cmd / sh استدعاء

ثم ستعمل الآلية المقترحة في RFC على ذلك ، لأنها ستعمل على الملفات التنفيذية التي تم استدعاؤها مباشرة (على سبيل المثال ، إذا تم تعيين $PSNativeCommandErrorAction = 'Stop' ، فسيحدث خطأ في إنهاء البرنامج النصي إذا كان $LASTEXITCODE غير صفري. )

(جانبا سريعا - هذه المناقشة لا تنتمي هنا: بالنسبة لآلية _per-call_: شيء مثل
/bin/ls nosuch || $(throw 'ls failed) ، وكذلك /bin/ls nosuch || $(exit $LASTEXITCODE) (ما يعادل /bin/ls nosuch || exit لقشرة POSIX) ؛ # 10967 يناقش لماذا للأسف لا يمكننا تجنب $(...) (بدون تغييرات كبيرة في القواعد) ؛ وبالمثل ، فإن الحاجة إلى الإشارة إلى $LASTEXITCODE صراحة ربما لا يمكن تجنبها.)

(جانبا: إنشاء نص برمجي مع سطر shebang #!/bin/sh يعني استهداف غلاف النظام بالمسار الكامل تمامًا مثل استدعاء /bin/sh مباشرة).

ليس هذا ما أردت أن أقوله. أردت أن أقول إن PowerShell لا يحتاج إلى معرفة ماهية الصدفة الافتراضية لأن أنظمة التشغيل بها هذه الميزة مضمنة. يعرف Linux كيفية تنفيذ نص برمجي قابل للتنفيذ في حال لم يبدأ بـ #! أو أنه يبدأ بـ شيء آخر ، مثل #!/usr/bin/env python و Windows يعرف ما يجب فعله لاستدعاء برنامج نصي .CMD ، لذلك يجب ألا نلقي نظرة خاطفة على %COMSPEC% 'n'stuff إما IMHO. يمكن لـ Windows أيضًا تنفيذ برامج نصية أخرى ولكنها تستند إلى امتداد ملف البرنامج النصي ، لذلك من الواضح أنها لا تنطبق على هذه الحالة.

مرة أخرى ، يجب أن يكون تفويض Invoke-NativeShell هو استدعاء _CLI_ للقشرة الأصلية ، وليس إنشاء ملفات نصية مساعدة (مع تأثيرات جانبية) خلف الكواليس (باستثناء أسباب مختلفة ، كما تمت مناقشته أعلاه ).

فيما يتعلق بالتحديد القوي لصدفة النظام ، لا توجد مشكلة يجب حلها هنا: الترميز الثابت /bin/sh على Unix مناسب تمامًا ، كما هو الحال مع الاستشارات $env:ComSpec على Windows.

لا ، منصات Unix على مستوى استدعاء النظام لا تعرف كيفية تنفيذ ملف نص عادي قابل للتنفيذ بدون سطر shebang ؛ التي لا تزال _يمكنك_ من استدعاء مثل هذه الملفات هي ميزة ملائمة للأصداف الشبيهة بـ POSIX: فهي تحاول exec ، ثم _ تتراجع _ لتفسير هذه الملفات كما هو مكتوب _ for them_؛ أي أن أي غلاف يشبه POSIX يتم تشغيله وينتهي به الأمر بتنفيذ الملف - في حين أن PowerShell ببساطة _fails_ ، لأنه لا ينفذ هذا الاحتياطي المجاملة (ستحصل على Program 'foo' failed to run: Exec format error ).

وغني عن القول أنه من غير الحكمة إذن إنشاء مثل هذه النصوص.

لا ، منصات Unix على مستوى استدعاء النظام لا تعرف كيفية تنفيذ ملف نص عادي قابل للتنفيذ بدون سطر shebang ؛ التي لا تزال _يمكنك_ من استدعاء مثل هذه الملفات هي ميزة ملائمة للأصداف الشبيهة بـ POSIX: فهي تحاول exec ، ثم _ تتراجع _ لتفسير مثل هذه الملفات كما هو مكتوب _ for them_؛ أي أن أي غلاف يشبه POSIX يتم تشغيله وينتهي به الأمر إلى تنفيذ الملف - في حين أن PowerShell ببساطة _fails_ ، لأنه لا ينفذ هذا الإجراء الاحتياطي (ستحصل على Program 'foo' failed to run: Exec format error ).

csh لا يشبه POSIX ولا يفشل في البرنامج النصي exec . تستدعي sh . وكذلك الحال مع perl .

آمل أن يكون من الواضح أن هذا يوضح وجهة نظري: الأمر متروك لكل صدفة لتقرير ما يجب فعله ، والأصداف / لغات البرمجة النصية المختلفة تفعل أشياء مختلفة ؛ فشل PowerShell حاليًا - إذا كان عليه أن يختار ، وأردت أن يكون هذا الخيار /bin/sh ، فقد عدنا إلى المربع الأول: يجب افتراض /bin/sh .

آمل أن يكون من الواضح أن هذا يوضح وجهة نظري: الأمر متروك لكل صدفة لتقرير ما يجب فعله ، والأصداف / لغات البرمجة النصية المختلفة تفعل أشياء مختلفة ؛ فشل PowerShell حاليًا - إذا كان عليه أن يختار ، وأردت أن يكون هذا الخيار /bin/sh ، فقد عدنا إلى المربع الأول: يجب افتراض /bin/sh .

exec في perl هو اتصال مباشر بالنظام ، ولا يقوم perl بتعديله بأي شكل من الأشكال. على وجه الخصوص ، لا تختار المترجم.

بالطبع ، هذا يفترض أن المستخدمين يعرفون الفرق بين السلاسل ذات الاقتباس الفردي (حرفيا) والمزدوجة الاقتباس (الاستيفاء) وحول الانتقائية ` الهروب من $ ، لكنني أعتقد أنها مهمة (متقدم) الخيار لديك.

ربما أنا فقط ، لكنني سأقوم بتداول ألف " مقابل -f .

@ yecril71pl

exec in perl هو استدعاء مباشر للنظام ، ولا يقوم perl بتعديله بأي شكل من الأشكال. على وجه الخصوص ، لا تختار المترجم.

لا يمكن أن يكون هذا صحيحًا إذا كان يعمل مع البرامج النصية بدون سطر #! . لا يعمل نظام exec syscall على نظام Linux بدون #! ، حيث يمكن للمرء بسهولة اختبار:

user@Programming-PC:/tmp/exec_test$ ls
test.c  testscript
user@Programming-PC:/tmp/exec_test$ cat test.c
#include <unistd.h>
#include <stdio.h>

int main(int argc, char **argv) {
  char *binaryPath = "./testscript";

  execl(binaryPath, binaryPath, NULL);

  perror("Error");

  return 0;
}
user@Programming-PC:/tmp/exec_test$ gcc test.c -o testexecutable
user@Programming-PC:/tmp/exec_test$ chmod +x testscript 
user@Programming-PC:/tmp/exec_test$ cat testscript 
echo test from script
user@Programming-PC:/tmp/exec_test$ #works from shell:
user@Programming-PC:/tmp/exec_test$ ./testscript 
test from script
user@Programming-PC:/tmp/exec_test$ #doesn't work via exec syscall:
user@Programming-PC:/tmp/exec_test$ ./testexecutable 
Error: Exec format error
user@Programming-PC:/tmp/exec_test$ vim testscript 
user@Programming-PC:/tmp/exec_test$ cat testscript 
#!/bin/sh
echo test from script
user@Programming-PC:/tmp/exec_test$ #exec syscall works with #! line:
user@Programming-PC:/tmp/exec_test$ ./testexecutable 
test from script
user@Programming-PC:/tmp/exec_test$ uname -a
Linux Programming-PC 4.4.0-176-generic #206-Ubuntu SMP Fri Feb 28 05:02:04 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
user@Programming-PC:/tmp/exec_test$ 

تحرير: لقد لاحظت للتو أنه إذا كنت تستخدم وظيفة المكتبة execlp فوفقًا لصفحة الدليل:

إذا لم يتم التعرف على رأس الملف (فشلت محاولة التنفيذ (2) مع الخطأ ENOEXEC) ، ستقوم هذه الوظائف بتنفيذ الصدفة (/ bin / sh) بمسار الملف كوسيطه الأول. (إذا فشلت هذه المحاولة ، فلن يتم إجراء مزيد من البحث.)

ومع ذلك ، فهذه ليست سمة من سمات "linux" ولكنها خاصة بمكتبة gnu c - ومرة ​​أخرى وفقًا لصفحة الدليل التي تستخدمها بشكل صريح / bin / sh وليس بعض الصدفة التي يمكن تعريفها بواسطة المستخدم. (تم ترميزه الثابت في مصدر posix/execvpe.c ( new_argv[0] = (char *) _PATH_BSHELL; ) و sysdeps / unix / sysv / linux / paths.h (أو sysdeps / generic / paths.h - لا أعرف أي رأس هو مستخدم ...) ( #define _PATH_BSHELL "/bin/sh" ))

ومع ذلك ، فهذه ليست سمة من سمات "linux" ولكنها خاصة بمكتبة gnu c - ومرة ​​أخرى وفقًا لصفحة الدليل التي تستخدمها بشكل صريح / bin / sh وليس بعض الصدفة التي يمكن تعريفها بواسطة المستخدم. (ترميزًا ثابتًا في مصدر posix/execvpe.c ( new_argv[0] = (char *) _PATH_BSHELL; ) و sysdeps / unix / sysv / linux / paths.h (أو sysdeps / generic / paths.h - لا أعرف أي رأس هو مستخدم ...) ( #define _PATH_BSHELL "/bin/sh" ))

نظرًا لأنه يأتي من sysdeps/**/linux ، فهو شيء Linux. قد يكون أيضًا الشيء العام ولكنه قابل للتجاوز - من الواضح أنه ليس محليًا ولكن وفقًا لنظام التشغيل.

نعم ، أفهم السلوك _current_ @ vexx32 . لكننا لا (على الأقل أنا لا) نتحدث عن السلوك _الحالي _ --% - نحن نتحدث عن تحسينه ، أليس كذلك؟ لماذا أشعر بأننا نتحدث جميعًا حول بعضنا البعض هنا؟ :)

لذا فإن الخطوة الحالية لضبط --% هي أنه إذا كان هذا هو المكان الذي سيكون فيه اسم الأمر عادةً ، فسيتم تحليل كل شيء على يمينه _as_ (حتى سطر جديد) وإرساله مباشرةً إلى bash / cmd. لا توجد مساحة لأي بنية PowerShell مثل هنا سلاسل وما ليس لأنه يعاني من نفس المشكلات التي يواجهها حاليًا معالج الأوامر الأصلي --% .

يا لورد ... هل الجميع يحاول فقط أن يتصيدني؟ 😄 لا ، باتريك - إذا كنت تريد استخدام تعبيرات بوويرشيل ، فاستخدم هنا سلاسل مع --% . إذا كنت تريد متعدد الأسطر ، فاستخدم هنا سلاسل. إذا كنت تريد خطوطًا متعددة بدون استبدال متغير ، فيمكنك استخدام سلاسل هنا ذات علامة اقتباس مفردة.

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

تحرير: الكلمة الأخيرة

عنوان هذا العنصر هو "الاتصال بالمشغل الأصلي". أرى فرصة ضائعة عندما يكون لدينا بالفعل مشغل مكالمات & ولدينا بالفعل رمز مميز تم تصميمه للتعامل مع تمرير الوسائط إلى الأوامر الأصلية ، --% . في الوقت الحالي ، لم يتم التعرف على استخدام & مع --% وبالتالي لن يتم إدخال تغيير فاصل إذا قررنا تمكين هذا السيناريو وإعطائه سلوكًا محددًا لإصلاح المشكلات التي تتم مناقشتها هنا.

إذا كنت تريد استخدام تعبيرات بوويرشيل ، فاستخدم هنا سلاسل مع --% . إذا كنت تريد متعدد الأسطر ، فاستخدم هنا سلاسل.

تكمن نقطة عامل التشغيل في أنه لا يحلل حرفياً أي صيغة PowerShell. لا يوجد شيء مثل هنا سلاسل. لا يوجد شيء مثل ثوابت السلسلة المفرد المقتبسة. إنها "إرسال النص إلى اليمين كما هو" ليس "تقييم التعبير إلى اليمين ، وتحويله إلى سلسلة وإرسال قيمته"

على سبيل المثال ، إذا كان لديك هذا:

--% @'
echo my native command
'@

ستترجم إلى:

cmd.exe /c "@'"
echo my native command
'@

باستثناء أنك ستحصل على خطأ في المحلل اللغوي لأن '@ سيكون مجرد بداية لسلسلة واحدة ثابتة سلسلة مقتبسة تحتوي على @ .

أعتقد أنك ربما تتخيل التنفيذ بشكل مختلف بحيث يكون تقريبًا نفس الشيء مثل عرض السعر ins ، لكن ما سبق هو العرض الحالي الذي تتم مناقشته مقابل --% .

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

cmd /c --% @'
echo my native command
'@

أكرر:

في الوقت الحالي ، استخدام & مع -٪ غير معترف به / غير محدد وعلى هذا النحو لن يقدم تغييرًا فاصلًا إذا قررنا تمكين هذا السيناريو ومنحه سلوكًا محددًا لإصلاح المشكلات التي تتم مناقشتها هنا .

اسمح لي بتوضيح ذلك بشكل أوضح: اسمح لسلاسل هنا باتباع --% عند استخدامها مع &

هاه هذا أمر كبير - نعم فاتني ذلك ، آسفoising.

حول هذه الفكرة ، أعتقد أنه سيكون محيرًا بعض الشيء أن يكون لديك --% يعني التوقف عن التحليل في بعض السياقات و "القيام بعمل أفضل في ربط الحجة الأصلية" في سياقات أخرى (وبالمثل مع جعلها تعمل مثل Invoke-NativeShell إذا كان هذا ما تعنيه بدلاً من ذلك).

شكرًا لك على التعمق في re exec ،TSlivede. اسمحوا لي أن أحاول أن ألخص ، وبالتالي آمل أن أغلق هذا الظل ؛ ينطبق على كل من Linux و macOS:

لا توجد وظيفة نظام (أو مكتبة) تسمى exec على نظام Unix ، ولا يوجد سوى _family_ من الوظائف ذات الصلة مع اسم exec (معظمها كبادئة).

  • وظائف _system_ ( man section 2 ) ، execve في قلبها ، _fail_ عندما تحاول تنفيذ نص برمجي أقل من shebang.

  • من بين وظائف _library_ التي _بناء وظائف النظام_ ( man section 3 - man 3 exec ) ، فقط تلك التي تحتوي على p (لـ "المسار" ، أنا يفترض) أن يكون لديك احتياطي pass-to-the-system-shell (على سبيل المثال ، execlp ).

    • تطبيقات مكتبة جنو لهذه الوظائف تحتوي على كود ثابت /bin/sh ، كما أظهرTSlivede ، في حين أن تستخدم sh ، وتعتمد على sh لتكون في $env:PATH (على الرغم من الفضول أن الصفحة man تشير إلى /bin/sh ).

كما هو مذكور ، بالنسبة للتنفيذ المباشر ، فإن الصدفة الرئيسية التي تشبه POSIX ( bash ، dash ، ksh ، و zsh ) تعود إلى تنفيذ نصوص shebang-less _نفسهم_ ، مما يعني أنهم لا يستخدمون المتغيرات الاحتياطية بين وظائف المكتبة exec ؛ على النقيض من ذلك ، كان اختيار perl exec لوظيفته exec _builtins_ للأصداف الرئيسية التي تشبه POSIX تعتمد على الاحتياطيات ، باستثناء bash .

نظرًا لأن استخدام ملف نصي خلف الكواليس في نظام يونكس غير ضروري ، يمكننا وضع نفس الافتراضات حول مسار غلاف النظام مثل وظائف المكتبة الاحتياطية ، وأوصي /bin/sh أكثر من sh ، لـ الأمن والقدرة على التنبؤ:

على الرغم من مواصفات POSIX _not_ التي تفرض موقع sh (أي بالمعنى الدقيق للكلمة ، فإن وظائف مكتبة BSD هي الوظائف المتوافقة):

  • /bin/sh من الآمن افتراضه ، لأنه الموقع القياسي الفعلي ، لأسباب ليس أقلها أن كتابة غلاف Unix المحمول _ ضروري للإشارة إلى sh بمسارها الكامل ، بالنظر إلى أن خطوط shebang تدعم فقط _full ، الحرفية_ المسارات ( #!/bin/sh ).

  • بالمقابل ، الاعتماد على تحديد موقع sh عبر $env:PATH يمكن أن يكون مخاطرة أمنية ، نظرًا لأنه يمكن التلاعب بـ $env:PATH لاستدعاء sh .

تنطبق نفس المخاطر على تحديد موقع cmd.exe عبر $env:ComSpec بالمناسبة ، لذلك ربما تكون الطريقة الأفضل هي استدعاء دالة WinAPI GetSystemDirectory وإلحاق \cmd.exe بـ نتيجتها (نحتاج إلى احتياطي على أي حال ، إذا لم يتم تحديد $env:ComSpec ).

يمكن افتراض أن /bin/sh آمن ، لأنه الموقع القياسي الفعلي ، لأسباب ليس أقلها أن كتابة Unix shell _necessitates_ تشير إلى sh بمسارها الكامل ، بالنظر إلى أن خطوط shebang تدعم فقط _full، literal_ المسارات ( #!/bin/sh ).

عادة تقول #!/usr/bin/env sh (باستثناء نصوص النظام).

  • عادةً ، أنت لا _ لا _: ينتج عن googling "#! / bin / sh" حوالي 3900000 مطابقة ، ينتج "#! / usr / bin / env sh" حوالي 34100 تطابق.

  • عادةً ، لا يجب عليك: أن تستهدف بشكل متوقع _the النظام shell ، /bin/sh ، وليس أيًا من الأداة المساعدة sh تأتي أولاً في $env:PATH .

السبب الوحيد لاستهداف ملف تنفيذي باسم sh هو الاستهداف المنقول لأقل قاسم مشترك-افتراض-POSIX-features-only _system_ shell ، أي /bin/sh .

عادةً ، أنت لا _ لا _: ينتج عن googling "#! / bin / sh" حوالي 3900000 مطابقة ، ينتج "#! / usr / bin / env sh" حوالي 34100 تطابق.

لا توجد طريقة لتقييد بحث الويب على البرامج النصية للمستخدم ، خاصة وأن العديد من البرامج النصية للمستخدم لم يتم تمييزها على الإطلاق بأنها قابلة للتنفيذ ، وحتى لو كانت كذلك ، فقد يعتمدون على execlp ؛ ولكن حتى لو ذكرت معظم البرامج النصية للمستخدم ذلك ، فلا يجب أن نأخذ كلمة _customary_ على أنها _normal_. البرامج النصية التي سيتم تشغيلها بواسطة PowerShell هي برامج نصية للمستخدم ؛ عندما يريد المستخدمون صدفة ، فإنهم يتصلون بـ sh ، وليس /bin/sh ، إلا إذا كانوا مصابين بجنون العظمة.

oising

تمرير سطر أوامر shell الأصلي _ كسلسلة واحدة_ (بأي شكل سلسلة (-الحرف) هو الأسهل) ، و _ فقط_ كسلسلة واحدة (باستثناء وسيطات سطر الأوامر الإضافية المدعومة على Unix ( فقط) التي تمت مناقشتها أعلاه ) - على افتراض أنك توافق على ذلك - تبدو وكأنها أرضية مشتركة.

يعد تمرير سطر الأوامر كسلسلة واحدة شرطًا أساسيًا لـ:

  • القدرة على دمج مثل هذه المكالمة في خط أنابيب _PowerShell_.
  • القدرة على دمج متغيرات PowerShell والتعبير_ في سطر أوامر shell الأصلي.

تمرير سلسلة واحدة هو _تعبير مفاهيمي مباشر_ لما ستفعله المكالمة ؛ على النقيض من ذلك ، فإن محاولة الدمج بطريقة أو بأخرى بشكل مباشر لبناء جملة لقشرة مختلفة مباشرة في PowerShell مع وسيطات _individual_ (اختياريًا) تجلب مشاكل غير قابلة للحل تؤدي إلى حل وسط مربك مع قيود أساسية ، والتي تجسدها بالفعل --%


على الرغم من أنك قد تجادل بأنه ليس من المهم إذن ما إذا كنا نختار _ مشغل_ أو _cmdlet_ لتمرير سطر الأوامر المكون من سلسلة واحدة إلى (باستثناء أسئلة _discoverability_) ، فإن لدي مخاوف مفاهيمية حول استخدام كلا & و --% (مسبوقًا بـ & ):

  • القلق بشأن & : إذا احتجنا إلى تمرير سلسلة - مقتبسة - تحتوي على سطر الأوامر ، فنحن نعمل بفاعلية في وضع _expression_ ، بينما يشير & حاليًا إلى الوضع _argument_ (مما يعني: _الحجج الفردية ، الاقتباس عند الضرورة فقط). لذلك ، فإن تورط & أمر محير.

  • القلق re --% يتعلق بأصل Windows فقط والدلالات المشوشة لـ --% كرمز إيقاف التحليل ؛ سيكون الأمر محيرًا بشكل خاص إذا كان --% كرمز إيقاف التحليل يعمل في وضع _argument_ (على سبيل المثال
    & /bin/ls --% dir1 dir2 ) ، بينما & --% يعمل في وضع _expression_ (على سبيل المثال & --% '/bin/ls dir1 dir2 >out.txt' )


اسمحوا لي أن أعود خطوة إلى الوراء وفحص --% ، رمز إيقاف التحليل ، كما هو مطبق حاليًا:

كانت محاولة لحل مشكلتين غير مرتبطين في النهاية (Windows فقط في ذلك الوقت):

  • (أ) حالة استخدام تنطبق أيضًا على الأنظمة الأساسية الأخرى: اسمح لي بإعادة استخدام _أسطر الأوامر_ المكتوبة مقابل cmd.exe / الغلاف الأصلي كما هو ، لذلك لا يتعين علي تكييفها مع بناء جملة PowerShell.

  • (ب) مشكلة Windows فقط دائمًا: اسمح لي باستدعاء _rogue CLI_ (أي استدعاء لتطبيق وحدة تحكم خارجي واحد) يتطلب أسلوبًا محددًا جدًا للاقتباس لا يمكن أن توفره إعادة الاقتباس العام من PowerShell وراء الكواليس ، بالسماح لي بصياغة سطر الأوامر الذي تم تمريره في النهاية إلى WinAPI لمثل هذه CLIs _verbatim_. (لقصر بيان المشكلة على هذا يفترض أن إعادة اقتباس PowerShell تعمل بشكل صحيح بشكل عام ، وهو ما لم يحدث أبدًا - وهذا هو موضوع # 1995).

تم تنفيذ --% كمحاولات تضخم مشوشة لحل لكل من (أ) و (ب) ، وانتهى الأمر بحل أي من المشكلة بشكل صحيح:

  • تم الإعلان عنها كحل لـ (أ) ، ولكن في الواقع لها قيود شديدة ، لأن ميزة cmd exe التي تحاكيها هي توسيع %...% -style environment-variable المراجع_:

    • إنه يدعم فقط الأمر _single_ cmd ، بالنظر إلى أن |
      && و || ، على الرغم من عدم تنفيذها في ذلك الوقت) إنهاء ضمنيًا جزء pass-to- cmd .

    • A _single_ & - وهو cmd s فاصل متعدد الأوامر - _ هو_ تم تمريره ، ولكن هذا أيضًا _ لم ينتج عنه دعم متعدد الأوامر ، لأنه - منذ cmd isn t متضمن بالفعل - يتم تمرير & _verbatim إلى البرنامج المستهدف_ ؛ على سبيل المثال
      echoArgs.exe --% a & b لا يردد صدى a ثم يستدعي b ، ويمرر الوسائط الحرفية a ، & ، و b إلى echoArgs .

    • لم يتم تكريم حرف الهروب cmd ( ^ ) في الوسائط غير المقتبسة.

    • وكنتيجة طبيعية ، يتم توسيع الرموز المميزة %...% التي تشير إلى متغيرات البيئة الحالية _invariably _؛ محاولة لمنع ذلك عبر ^ لا تعمل بشكل صحيح (على سبيل المثال
      echoArgs.exe Don't expand %^USERNAME% ، الذي في cmd يمنع التوسيع _ و يزيل ^ _ ، يحتفظ بـ ^ عند الاتصال من PowerShell كـ echoArgs.exe --% Don't expand %^USERNAME%

  • كحل لـ (ب) ، فقد فشل أيضًا:

    • تمامًا كما هو الحال في (أ) الاستخدام ، لا توجد إمكانية لدمج متغيرات وتعبيرات PowerShell_ في الأمر - إلا إذا قمت بتعريف _aux أولاً بشكل محرج. متغير البيئة _ الذي تشير إليه بعد ذلك عبر %...% بعد --% ؛ على سبيل المثال
      $env:FOO='foo'; echoArgs.exe --% %FOO%!

الحل المناسب لـ (أ) سيكون Invoke-NativeShell / ins ، كما تمت مناقشته هنا.

كان الحل المناسب لـ (ب) هو:

  • دعم --% كخاص فقط مثل الوسيطة _first_
  • ومثلما هو الحال مع ins ، يتطلب اتباعه _ بسلسلة واحدة_ تشكل سطر الأوامر التمريري _ ككل _ ، مرة أخرى مع القدرة على دمج متغيرات وتعبيرات _PowerShell_ عن طريق الاستيفاء للسلسلة (أو طرق أخرى لبناء السلسلة)
  • على سبيل المثال ، msiexec --% "/i installer.msi INSTALLLOCATION=`"$loc`"" ، مع احتواء $loc على 'c:\foo\bar none' ، سيؤدي ذلك إلى تمرير سطر الأوامر الحرفي /i installer.msi INSTALLLOCATION="c:\foo\bar none" ، مما يفي بالمتطلبات غير القياسية لـ msiexec أنه في الوسيطات <prop>=<value> فقط الجزء <value> يتم اقتباسه مرتين.

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

@ mklement0 شكرا لك على الصبر والرد المدروس (كالعادة.)

لذلك ، أنا أتفق تمامًا مع ؛

كان الحل المناسب لـ (ب) هو:

  • الدعم -٪ خاص فقط كالوسيطة الأولى
  • وكما هو الحال مع الوظائف الإضافية ، تتطلب أن تتبعها سلسلة واحدة تشكل سطر أوامر المرور ككل ،> - مرة أخرى مع القدرة على دمج متغيرات وتعبيرات PowerShell عن طريق الاستيفاء السلاسل (أو طرق أخرى بناء الخيط)

    • على سبيل المثال msiexec -٪ "/ i installer.msi INSTALLLOCATION = "$loc " "، مع $ loc الذي يحتوي على 'c: foobar none' ، سينتج عنه سطر أوامر حرفي / i installer.msi INSTALLLOCATION =" c: foobar لا شيء "يتم تمريره ، مما يلبي متطلبات msiexec غير القياسية التي في=الحجج فقطيكون الجزء مزدوج الاقتباس.

هذا ما كنت أحاول شرحه كحل عام لكل من (أ) و (ب) ، باستثناء أنني ما زلت لا أفهم حقًا أن (أ) يجب أن يوجد كمشكلة مستقلة يجب حلها؟ ما أعاني منه حقًا هو إذا تم تنفيذ (ب) _ على وجه التحديد _ مقابل & ، فلماذا لا يغطي هذا (أ) أيضًا؟ على سبيل المثال ، ما الذي يعطيه ins ... يعطيه & cmd --% ... ؟ ولن يكون تغييرًا جذريًا بخلاف عدم السماح لـ & بتمرير --% كحجة (وهو ما يبدو مستبعدًا بشكل يبعث على السخرية.) أو أيا كان. دع المتصل يقرر.

استعرضت لجنة PowerShell @ / بوويرشيل هذا:

  • ستكون هذه ميزة تجريبية للحصول على تعليقات فعلية حول الاستخدام ؛ ما زلنا منفتحين على سيجيل الفعلي ؛ نرجئ /bin/sh مقابل /bin/env sh لمراجعة العلاقات العامة
  • سنمضي قدمًا مع --% كمعامل جديد خصيصًا لسيناريو "stackoverflow" حيث يقوم المستخدم بقص ولصق سطر أوامر في PowerShell ويجب أن يعمل فقط (مع العامل الجديد الذي يسبقه بالطبع )
  • أمر cmdlet Invoke-NativeShell منفصل عن هذا الاقتراح ويمكن نشره من قبل المجتمع في PowerShellGallery ؛ أيضًا ، لا يؤدي طلب سلسلة هنا إلى حل مشكلة تجربة المستخدم دون معرفة مسبقًا بلفها كسلسلة هنا
  • لا نريد إجراء تغيير فاصل لمحول --% حيث قد يعتمد المستخدمون الحاليون على هذا السلوك
  • يجب على المستخدمين الذين يحتاجون إلى سلوك دفق مثل التبديل --% الاستمرار في استخدام هذا المفتاح والهروب من الأحرف الخاصة عند الضرورة
  • لا تزال هناك مشكلة اكتشاف للمستخدمين لمعرفة --% (أو أي حل)
  • لا نقوم حاليًا بإجراء تغيير على PSReadLine لتعديل المحتوى الذي تم لصقه كسلسلة هنا تحاول التنبؤ بقصد المستخدم
  • نحن لا نبحث عن حلول متعددة تسمح بسيناريوهات هنا سلسلة مقابل غير هنا (توسيع) ؛ على سبيل المثال ، & --% مقابل --%

أريد أيضًا أن أضيف أنه ، على الرغم من @ SteveL-MSFT وأنا أغلقت # 1995 في نفس الوقت الذي افتتح فيه هذا ، لم يكن هدفنا حقًا توصيل هذا كحل نهائي لهذه المشكلة.

أرى أن فوائد هذه الميزة المعينة أكثر أهمية بكثير من التأثير # 1995. أعتقد أن هناك الكثير من أمثلة StackOverflow وأمثلة المستندات للأدوات غير المستنيرة التي لا تعتمد على PS والتي يرغب الناس في قصها / لصقها (بما فيهم أنا).

هناك أيضًا رغبة في توفير الهروب المناسب داخل لغة PowerShell الخاصة ، لكنني لا أرى الأشخاص يصلون إلى # 1995 في البرية بشكل جماعي (لكنني سأوضح المزيد حول هذا الأمر هناك).

  • سنمضي قدمًا مع --% كمعامل جديد

آسف لسحب هذا ، وأنا لا أبحث عن مناقشة إضافية ، ولكن أي نوع من المشغل؟ (أنا مهتم بشكل أساسي بالصياغة.)

$a = --% find . -iname *$pdf -print0 | xargs -0 ls -ltr

من يحصل على الغليون؟ ماذا يحدث لـ $ ؟ مماثل لـ & ، && ، و || .

ما هي الظروف ، إن وجدت ، هل يمكن استخدام --% في أنبوب PS للمضي قدمًا؟

شكر.

آسف لسحب هذا ، وأنا لا أبحث عن مناقشة إضافية ، ولكن أي نوع من المشغل؟ (أنا مهتم بشكل أساسي بالصياغة.)

من الحكمة أنه من المحتمل ألا يكون مشغلًا تقنيًا ولكنه من نوع AST الخاص به. إذا تم تنفيذه كمشغل ، فسيكون عامل تشغيل أحادي.

$a = --% find . -iname *$pdf -print0 | xargs -0 ls -ltr

من يحصل على الغليون؟ ماذا يحدث لـ $ ؟ مماثل لـ & ، && ، و || .

سيتم إرسال السلسلة find . -iname *$pdf -print0 | xargs -0 ls -ltr كما هي إلى الصدفة الأصلية. لا يزال يتم ملء $a على الرغم من ذلك ، لذا يمكنك في خط الأنابيب التالي أن يتم نقله إلى شيء ما.

ما هي الظروف ، إن وجدت ، هل يمكن استخدام --% في أنبوب PS للمضي قدمًا؟

إذا كانت ~ في أول فتحة لعنصر الأمر ~ فهي في بداية الجملة ، على الأرجح لا. هذا هو أحد سحوبات بناء الجملة الجديد. إذا لم يكن ~ في الفتحة الأولى ~ في البداية ، فسيستمر في العمل كما هو الحال اليوم.

(@ daxian-dbw @ SteveL-MSFT إذا كان أي من ذلك خاطئ ، يرجى تصحيحه ❤️)

SeeminglyScience هو بالضبط الحق

إذا كانت في فتحة عنصر الأمر الأولى ، فمن المحتمل ألا تكون كذلك. هذا هو أحد سحوبات بناء الجملة الجديد. إذا لم يكن في الفتحة الأولى ، فسيستمر في العمل كما هو الحال اليوم.

قد يكون من الصعب تمرير مخرجات الأمر upstream إلى الأمر الأصلي الذي سيتم استدعاؤه بواسطة --% . --% بشكل أساسي بتسليم السلسلة كما هي إلى غلاف أصلي ، مثل bash ، لكن الإخراج من أمر upstream لا يمكن تغذيته فقط إلى bash ، لكن يجب تغذيته الأمر الأصلي نفسه ، مثل find .

أعتقد أن سلوك البث لا يعتبر اعتبارًا لهذه الميزة لأنها خاصة بسيناريو "StackOverflow". لذلك أعتقد أنه من الأفضل أن نجعل فقط --% بيانًا خاصًا ، بحيث يكون من الواضح أنه لن يعمل مع خطوط أنابيب PowerShell_.

آه ، علمت أن هناك سببًا لخطأ "فتحة عنصر الأوامر". قصدته في بداية البيان. سوف أصلحها ، شكرا!

لا يمكن تغذية الإخراج من أمر upstream فقط إلى bash

هل يعني _upstream_ _us_؟ أعتقد أنه يمكن أن يفعل: 'ls' | bash . ليس شيئًا ذكيًا بشكل غريب ولكنه ممكن.

كان يناقش مع jpsnover حول هذا واقترح shebang #! ليكون sigil. في هذه الحالة ، ما عليك سوى كتابة:

#!/bin/sh ls | grep foo
#!sh | grep foo

(حيث تفترض الحالة الثانية أن sh موجود في المسار). في هذه الحالة، يتعين علينا أن نقرر إذا تحديد قذيفة مطلوب او اذا كان لتشغيل دائما أنه في ظل قذيفة الافتراضي، لذلك في هذا المثال، sh بدء مرتين. ومع ذلك ، هناك مشكلة في هذا بسبب كيفية عمل ملفات shebang اليوم. إنهم يعملون في PowerShell لأنه يتم تجاهل shebang كتعليق. إذا قررنا تجاهل السطر الأول في البرنامج النصي إذا كان تعليقًا ، فلا يزال لدينا مشكلة في الغلاف التفاعلي حيث تكون كل مجموعة جديدة من الأسطر نصًا جديدًا ولا توجد طريقة اليوم لتحديد ما إذا كان هذا البرنامج النصي يتم تشغيله نصي أو تفاعلي.

قد يكون البديل هو استعارة صيغة التخفيض:

powershell ```bash ls | grep foo ```

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

في هذه الحالة ، من المحتمل أن يعمل هذا:

powershell $a = ```bash ls | grep foo ``` | select-string bar

@ SteveL-MSFT Markdown Syntax له معنى كبير. إذا كنا قادرين على التحديد. أنواع أخرى مثل بيثون أو ربما بالامتداد؟

و shebang #! من شأنه أن يتدخل في التعليقات الموجودة.

يبدو أن هذا الأمر معقد للغاية بالنسبة لي ، سواء للتعامل معه في التحليل أو بالنسبة للمستخدمين لاستخدامه.

ونعم ، لسنا بحاجة إلى الخلط بين الأشخاص وبين الأسطر التي _يجب_ أن تكون تعليقات لا تتحول إلى تعليقات. #Requires يتفوق بالفعل على نوع غريب ، سيشوش كامل على shebang مستخدمي Windows في أحسن الأحوال ، وربما مستخدمي Linux أيضًا.

أنا شخصياً أفضل عدم مزج هذه الميزة مع shebang ، إنها محيرة في رأيي.
أيضًا ، إذا بدأنا في استخدام بناء جملة كتلة التعليمات البرمجية ، فهذه مسألة وقت فقط لكي يطلب الأشخاص تشغيل رمز لغة تعسفي مباشرةً في PowerShell. لا أعتقد أننا نريد أن نسير بهذه الطريقة ...

أيضًا ، إذا بدأنا في استخدام بناء جملة كتلة التعليمات البرمجية ، فهذه مسألة وقت فقط لكي يطلب الأشخاص تشغيل رمز لغة تعسفي مباشرةً في PowerShell.

لن أتوقف أبدًا حرفيًا عن طلب C # على الرغم من أنني أعلم أنها فكرة سيئة.

لا تقدم صيغة markdown تعليمات برمجية لغة عشوائية لأن النص المضمن سيعمل في عملية تابعة. يمكنك وضع رمز لغة عشوائي داخل @' الآن ولن يحدث شيء سيء.

في مناقشة الفريق وأيضًا مع Jeffrey ، يجب ألا نكون ضد الأشخاص الذين يرغبون في تشغيل لغات أخرى في برنامج PowerShell النصي. كما لاحظ @ yecril71pl ، نحن لا ندعم اللغات الأخرى بشكل مباشر ولكننا نعتمد على عملية مختلفة لتفسير وتنفيذ هذا الرمز. السيناريو هنا هو أن المستخدم يرى كتلة من نص بايثون أو باش ويريد فقط استخدامه كما هو داخل نص PowerShell الخاص به. لا يوجد شيء يتطلب من الناس القيام بذلك. يمكنهم أن يقرروا نقل هذا البرنامج النصي الآخر إلى PowerShell إذا كانوا يفضلون ذلك. يوفر هذا فقط خيارًا للمستخدمين ليتمكنوا من القص واللصق في PowerShell لإنجاز المهام.

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

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

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

في مناقشة الفريق وأيضًا مع Jeffrey ، يجب ألا نكون ضد الأشخاص الذين يرغبون في تشغيل لغات أخرى في برنامج PowerShell النصي.

100٪ تمامًا ، لكن هذا لا يعني أنه يجب تضمينها مباشرةً في اللغة.

كما لاحظ @ yecril71pl ، نحن لا ندعم اللغات الأخرى بشكل مباشر ولكننا نعتمد على عملية مختلفة لتفسير وتنفيذ هذا الرمز. السيناريو هنا هو أن المستخدم يرى كتلة من نص بايثون أو باش ويريد فقط استخدامه كما هو داخل نص PowerShell الخاص به.

يمكن أن يتم ذلك بالفعل باستخدام سلاسل هنا ، أليس كذلك؟ هل يمكنك التوسع قليلاً في الفوائد التي يوفرها هذا على الطرق الحالية؟

أيضا لماذا تتوقف عند بايثون وباش؟ لماذا لا تستخدم C # و CIL و C ++؟

لا يوجد شيء يتطلب من الناس القيام بذلك. يمكنهم أن يقرروا نقل هذا البرنامج النصي الآخر إلى PowerShell إذا كانوا يفضلون ذلك. يوفر هذا فقط خيارًا للمستخدمين ليتمكنوا من القص واللصق في PowerShell لإنجاز المهام.

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


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

يمكن أن يتم ذلك بالفعل باستخدام سلاسل هنا ، أليس كذلك؟ هل يمكنك التوسع قليلاً في الفوائد التي يوفرها هذا على الطرق الحالية؟

سيتمكن محرر الكود العالمي من اكتشافها وتزيينها بشكل مناسب ، بينما لا يوجد شيء يمكن القيام به باستخدام @' لأن المحرر ليس لديه فكرة عما بداخله.

أيضا لماذا تتوقف عند بايثون وباش؟ لماذا لا تستخدم C # و CIL و C ++؟

لأنهم ليسوا لغات البرمجة؟

سيتمكن محرر الكود العالمي من اكتشافها وتزيينها بشكل مناسب ، بينما لا يوجد شيء يمكن القيام به باستخدام @' لأن المحرر ليس لديه فكرة عما بداخله.

يستطيع المحرر معرفة أن bash -c @' يحتوي على bash بنفس سهولة سور الكود. كما أن الجزء الصعب ليس في تحديد اللغة التي يمثلها جزء من الكود ، بل إنه يخلط بين خوادم اللغة ومحددات بناء الجملة. الطريقة الوحيدة التي ستعمل بها بدون استثمار الوقت والجهد الكبير ستكون في الأساس جعلها كما لو كانت هنا سلسلة.

لأنهم ليسوا لغات البرمجة؟

يحتوي كل من C # و C ++ على مجموعات فرعية موجهة للبرنامج النصي. حتى لو لم يفعلوا ذلك ، فإن "لغة البرمجة النصية" ذاتية بدون تعريف حقيقي. إنه ليس مفيدًا كحد نهائي لما يمكن وما لا يتم اعتباره للتضمين.

يحتوي كل من C # و C ++ على مجموعات فرعية موجهة للبرنامج النصي. حتى لو لم يفعلوا ذلك ، فإن "لغة البرمجة النصية" ذاتية بدون تعريف حقيقي.

اللغة هي لغة برمجة نصية (قائمة بذاتها) عندما تتصل عادةً بـ interpet options… script arguments… ولا تترك هذه المكالمة شيئًا باستثناء ما كان من المفترض تركه ، باستثناء الأشياء المؤقتة والخاصة بالمترجم الفوري. وهذا يعني أيضًا أنه يتطلب عادةً نسخة من المترجم الفوري للتشغيل. توجد لغات برمجة نصية مضمنة لا يمكنك تشغيلها بهذه الطريقة.

تضمين التغريدة

يمكن أن يتم ذلك بالفعل باستخدام سلاسل هنا ، أليس كذلك؟ هل يمكنك التوسع قليلاً في الفوائد التي يوفرها هذا على الطرق الحالية؟

يمكن للأشخاص استخدام سلاسل هنا اليوم أو يمكنهم الهروب من جميع الحجج التي تم تمريرها إلى الأوامر الأصلية إذا كان بإمكانهم معرفة كيفية فهمها بشكل صحيح. الهدف هنا هو جعل الأمر أبسط للمستخدمين الجدد لسيناريوهات القص واللصق (Stackoverflow).

أيضا لماذا تتوقف عند بايثون وباش؟ لماذا لا تستخدم C # و CIL و C ++؟

السيناريوهات التي يتم دعمها هنا عبارة عن كتلة نصية تم تمريرها إلى أمر أصلي. يمكن دعم أي لغة إذا كانت تدعم اصطلاح الاستدعاء هذا. لا يوجد اقتراح لإنشاء ملف مصدر مؤقت وتجميعه.

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

ليس هناك توقع بأن تحصل على ألوان مختلطة في تركيب اللغة. أي نص متداخل من لغة أخرى سيكون فقط رتيبًا.

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

يختلف التنفيذ المقترح عن الإصدار الأصلي ، ولكن المشكلة هي نفسها وهي سيناريو القص واللصق و "العمل فقط".

يمكن للأشخاص استخدام سلاسل هنا اليوم أو يمكنهم الهروب من جميع الحجج التي تم تمريرها إلى الأوامر الأصلية إذا كان بإمكانهم معرفة كيفية فهمها بشكل صحيح. الهدف هنا هو جعل الأمر أبسط للمستخدمين الجدد لسيناريوهات القص واللصق (Stackoverflow).

صحيح ولكن كيف هو أسهل في الواقع؟ أفهم أنها ذاتية ولكن هذه لا تبدو مختلفة بالنسبة لي:

~~~ بوويرشيل
$ a = `` باش
تجد . -iname * $ pdf -print0 | xargs -0 ls -ltr

~~~

vs

```powershell
$a = bash -c @'
   find . -iname *$pdf -print0 | xargs -0 ls -ltr
'@

يبدو أنها متشابهة تقريبًا باستثناء أن الأخير أكثر وضوحًا بشكل ملحوظ فيما سيحدث.

السيناريوهات التي يتم دعمها هنا عبارة عن كتلة نصية تم تمريرها إلى أمر أصلي. يمكن دعم أي لغة إذا كانت تدعم اصطلاح الاستدعاء هذا. لا يوجد اقتراح لإنشاء ملف مصدر مؤقت وتجميعه.

حسنًا ، لن يحتاج C # إلى ملف مصدر مؤقت. ربما لا CIL أيضًا (لا توجد فكرة عن C ++). في كلتا الحالتين ، على الرغم من أن سياج الكود هو مجرد سكر نحوي لاستدعاء ملف تنفيذي (مثل bash / python / cmd) أمر محير بالنسبة لي. أسوار الكود تعني دعم اللغة imo.

ليس هناك توقع بأن تحصل على ألوان مختلطة في تركيب اللغة. أي نص متداخل من لغة أخرى سيكون فقط رتيبًا.

سيظل كابوسًا لمحللي tmLanguage. بالكاد يمكنهم التعامل مع النحو الذي يتوقعونه من أجهزة الصراف الآلي. أكثر من ذلك ، إذا كان هذا هو الحال ، فلا أفهم سبب اختلافها عن سلسلة هنا.

يختلف التنفيذ المقترح عن الإصدار الأصلي ، ولكن المشكلة هي نفسها وهي سيناريو القص واللصق و "العمل فقط".

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

حسنًا ، لن يحتاج C # إلى ملف مصدر مؤقت. ربما لا CIL أيضًا (لا توجد فكرة عن C ++). في كلتا الحالتين ، على الرغم من أن سياج الكود هو مجرد سكر نحوي لاستدعاء ملف تنفيذي (مثل bash / python / cmd) أمر محير بالنسبة لي. أسوار الكود تعني دعم اللغة imo.

أريد فقط أن أردد تعليق SeeminglyScience على هذا. يمكننا تشغيل البرنامج النصي C # بدون استخدام الترجمة مع المكتبة Microsoft.CodeAnalysis.CSharp.Scripting . هذا ما تستخدمه dotnet-Interactive في نواة C # Jupyter. لذلك قد لا يكون من غير المعقول أن يطلب المستخدمون البرمجة بلغة C # أو حتى دعم البرمجة النصية لـ F # بمثل هذه البنية.

يمكنك القول أن بناء جملة الكود في PowerShell مخصص لاستدعاء أمر أصلي ، والذي يسمح نظريًا بهذا:

    ```c:\mypath\MyArbitraryExe
        args to my arbitrary executable
    ```

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

الذي يسمح نظريًا بذلك

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

تضع النص في الداخل ، وليس الوسيطات ، والبرنامج النصي مكافئ لدفق الإدخال

النص هو حجة bash / cmd / python.

أيضًا ، إذا كان هذا يهدف إلى توفير دعم SO ، فلا ينبغي السماح بالمسارات الكاملة.

ثم قم بتبديله لهذا المثال:

~ بوويرشيل$ a = ipconfig /all ~

أو قم بإضافة exe التعسفي إلى المسار أولاً.

تضع النص في الداخل ، وليس الوسيطات ، والبرنامج النصي مكافئ لدفق الإدخال

النص هو حجة bash / cmd / python.

لا يسمح أي منهم بتمرير النص كحجة موضعية. CMD لا يسمح حتى بملف دفعي.

أيضًا ، إذا كان هذا يهدف إلى توفير دعم SO ، فلا ينبغي السماح بالمسارات الكاملة.

ثم قم بتبديله لهذا المثال:

$ a = `` ipconfig
/الكل

هذا لن ينجح.

يبدو أننا سنجري عددًا هائلاً من الحالات الخاصة على أساس تعسفي للغاية حتى تنجح فكرة تخفيض السعر.

أيضًا ، السبب الرئيسي وراء دعم ذلك في Markdown هو إبراز بناء الجملة. سيكون هذا طلبًا دائمًا إذا أضفنا شيئًا كهذا إلى اللغة.

هذا ليس حلا فعالا.

كان يناقش مع jpsnover حول هذا واقترح shebang #! ليكون sigil

فقط لإضافة سنتي ، أعتقد أنه من الخطأ إعادة هذه المناقشة بعد الإعلان عن حل. وأنا شخصيا لا أحب كلا من بناء الجملة shebang و markdown (وكلاهما يكسر التغييرات).

لا أمانع في إعادة بدء المناقشات إذا توصل شخص ما إلى شيء أفضل بشكل واضح. في الواقع ، من الأفضل القيام بذلك الآن من بعد شحن الميزة. لا أعتقد أن #! أو أسلوب التخفيض هو حل أفضل لتزويد سلسلة سطر أوامر "un-PowerShell-adulated" إلى ملف exe أصلي. ربما أحتاج فقط لمحاولة التعود عليها ولكن رد فعلي الأولي هو ... أممم ، eew.

_ إذا علمنا (و PowerShell) أننا ندير ملفًا تنفيذيًا أصليًا ، فلماذا نحتاج إلى "استدعاء عامل التشغيل الأصلي" على الإطلاق؟ _

إذا قام PowerShell بتحليل سلسلة إدخال وحصل على CommandAst ، فسيقوم PowerShell باكتشاف الأمر.
إذا كان الأمر أمرًا أصليًا ، فإن PowerShell يحول ast إلى NativeCommandProcessor.
يمكننا تنفيذ (NativeCommandProcessor تجريبي جديد) للحالة التي ستعيد تحليل مدى Ast (أي سلسلة الإدخال) بحيث نحصل على الاسم / المسار الأصلي القابل للتنفيذ وبقية السلسلة كوسيطة أو وسيطات بواسطة قواعد نظام التشغيل.

إذا أراد المستخدم نسخ ولصق من shell ، فعليه كتابة "cmd"أو" bash"- سيعمل هذا بدون تعديل.
إذا أراد المستخدم نسخ ولصق سطر أوامر أصليسيعمل أيضًا مثل g++ timer.cpp @conanbuildinfo.args -o timer --std=c++11 .

إذا أراد المستخدم نسخ ولصق من shell

لدينا Get-/Set-Clipboard لذلك.

للحالة التي ستعيد تحليل نطاق Ast (أي سلسلة الإدخال) بحيث يتم الحصول على الاسم / المسار الأصلي القابل للتنفيذ وبقية السلسلة كوسيطة أو وسيطات وفقًا لقواعد نظام التشغيل.

تفكيري هنا هو أنك تفعل هذا إما:

  • تحليل الأمر AST بشكل غير فعال ، فقط لإعادة تقسيم المدى لاحقًا كسلسلة ورمي AST الأصلي بعيدًا ، أو
  • تأخذ AST وتحاول إعادة تعيينها إلى سلسلة (بالطريقة التي يعمل بها NativeCommandProcessor الحالي) ، ولكن عند القيام بذلك ستضيع الأشياء

لذا بدلاً من ذلك ، نحتاج إلى الحفاظ على السلسلة من البداية. الآن ، أعتقد أنه يمكن القول إن PowerShell لديه بالفعل ثلاثة أنواع من الرموز المميزة للسلسلة ، ولكن يبدو أن الطلب الرئيسي في هذه المناقشة لا يريد الهروب من الأشياء. يجب أن تكون أي سلسلة قادرة على الهروب من فاصلها ، لكن الحل الذي تمت مناقشته هناك يبدو أنه يستخدم سطرًا جديدًا باعتباره فاصلًا ولا يكون قادرًا على الهروب من الأسطر الجديدة (هناك دائمًا فاصلة منقوطة).

أنا لست ملتزمًا تمامًا بفاصل سطر جديد فقط ، ولكن يبدو أنه الحل الوحيد لعدم الرغبة في الهروب من أي شيء. في الأساس ، من شأن ذلك أن يجعل "عامل الاتصال الأصلي" يرمز بشكل مشابه لكيفية تعليق السطر اليوم - من المشغل إلى نهاية السطر هي السلسلة التي تم تمريرها إلى "shell الأصلي".

وبالتالي:

--% ps -o pid,args -C bash | awk '/running_script/ { print $1 }'

سوف يرمز إلى:

--% ps -o pid,args -C bash | awk '/running_script/ { print $1 }'
|-||-----------------------------------------------------------|
 |                                  \
Native call operator        Invocation to be passed to native shell

(لاحظ أننا نرسل المسافة مباشرةً بعد --% إلى الغلاف الأصلي ، حيث تبدأ السلسلة فورًا بعد --% )

ثم يتم تغليف هذا الرمز في AST بسيط للغاية ، مثل:

// We need to carefully work out what AST this inherits from
// This syntax has almost no interoperability with PowerShell by design,
// so can't implement fields like redirections or backgrounding faithfully.
// But in order to participate in pipelines and similar, would need to extend a more concrete class
public class NativeCallInvocationAst : StatementAst
{
    public string NativeInvocation { get; }
}

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

بينما يبدو كل ذلك قابلاً للتنفيذ ، فإن بعض الأسئلة في ذهني هي:

  • هل الغلاف الأصلي قابل للتكوين؟ إذا لم يكن كذلك ، فكيف نبرر ذلك؟ إذا كان الأمر كذلك ، فهل يجب أن يكون صريحًا كجزء من بناء الجملة (مما يعقد بناء الجملة) ، أم يتم تنفيذه كمتغير تفضيل (مما يجعل اكتشافه وإدارته أكثر صعوبة)؟
  • هل مثل هذا التطبيق سيكون قابلاً للاكتشاف ولن يربك الناس؟ هل سيتفهم المستخدمون مدى ضآلة أداء PowerShell هنا ، أو ما يحدث عندما يستخدمون سلاسل | أو & أو حتى سلاسل؟
  • كم عدد السيناريوهات التي ستتم خدمتها بواسطة سلسلة حرفية مكونة من سطر واحد هنا؟ هل سنقوم بتنفيذ هذا فقط لنكتشف أن الكثير من الناس يريدون استدعاءات متعددة الخطوط؟ هل الحاجة إلى تجنب القيام بشيء مثل الهروب من اقتباس واحد كبيرة بما يكفي لإضافة هذه القيود؟
  • يبدو هذا وكأنه سيناريو محدد للغاية لبناء جملة لغة جديدة بالكامل. إذا كنا ننشئ تركيب جملة حرفيًا جديدًا ، فلماذا نقرنها مباشرة بمفهوم الاستدعاء الأصلي؟ إذا كنا ننشئ آلية استدعاء جديدة ، فلماذا نربطها مباشرة بمفهوم الأصداف الأخرى؟ تُؤلف البنية الجيدة والبنى اللغوية الجيدة ، من الناحيتين النحوية والوظيفية ، وحاول ألا تفرط في استخدام اللغة نفسها (بدلاً من توفير منصة من العناصر للمستخدم لتجميعها كبرنامج خاص بهم) - هل تتوافق صيغة المكالمة الأصلية المقترحة مع الشريط لبناء جملة ابتدائي جديد ليتم تأليفها في برامج؟ هل هناك نهج بديل أفضل يمكننا اتباعه يحل هذه المشكلة بطريقة بسيطة ، ولكن لا يزال يسمح لنا بالحفاظ على اللبنات الأساسية غير مترابطة بحيث يمكن تكوينها لحل المشكلات الأخرى؟
  • هل ستقوم القذائف الأخرى أو اللغات الأخرى بتنفيذ هذا أم أنها بالفعل؟ على مستوى نحوي أم على أي مستوى آخر؟ إذا كان الأمر كذلك ، فكيف؟

تفكيري هنا هو أن تفعل هذا أنت أيضًا

rjmholt CommandAst له خاصية المدى مع سلسلة الإدخال. إعادة التحليل بسيطة مثل التقسيم حسب المساحة الأولى على Windows أو التقسيم بمسافات على Unix. لذلك أتوقع أننا لم نفقد شيئًا في السلسلة وأن نحصل على أداء جيد.

ومع ذلك ، يتم تنفيذ ذلك ، أعتقد أننا بحاجة إلى مجموعة من حالات الاستخدام لاختبارها. اسمحوا لي أن "أقترح" ما يلي:

  • حالة الاستخدام 1: أريد استدعاء exe حرفيًا واحدًا (بدون استيفاء) للعمل دون معرفة قواعد الاقتباس / الهروب ، على سبيل المثال: g++ timer.cpp @conanbuildinfo.args -o timer --std=c++11 . الحل الحالي لهذا هو معرفة ما يجب اقتباسه مثل: g++ timer.cpp '@conanbuildinfo.args' -o timer --std=c++11 قد يتضمن المثال الأكثر تعقيدًا سطور أوامر تمتد عبر أسطر متعددة على سبيل المثال:
tar -cvpzf /share/Recovery/Snapshots/$(hostname)_$(date +%Y%m%d).tar.gz \
    --exclude=/proc \
    --exclude=/lost+found 

الحل الحالي (تبديل العلامة الخلفية بـ \ ) على سبيل المثال:

tar -cvpzf /share/Recovery/Snapshots/$(hostname)_$(date +%Y%m%d).tar.gz `
    --exclude=/proc `
    --exclude=/lost+found
  • حالة الاستخدام 1 أ: أريد استدعاء exe واحدًا مع الاستيفاء PS للعمل على سبيل المثال: g++ $CppFile @conanbuildinfo.args -o timer --std=c++11 . عمل حول الحالي لهذا هو لمعرفة ما اقتبس (مفرد أو مزدوج) وماذا الهروب e..g: g++ $CppFile '@conanbuildinfo.args' -o timer --std=c++11 A أكثر تعقيدا سبيل المثال قد تتضمن أسطر الأوامر التي تمتد خطوط متعددة مثل:
tar -cvpzf "/share/Recovery/Snapshots/${ComputerName}_`$(date +%Y%m%d).tar.gz" \
    --exclude=/proc \
    --exclude=/lost+found 

الحل الحالي ، أول علامة اقتباس مزدوجة ، استبدل العلامة الخلفية بـ \ واهرب من $ في بداية `$ (date + ...).

  • حالة الاستخدام 2: أريد تنفيذ أمر حرفي متدفق في غلاف آخر ، على سبيل المثال: ps -o pid,args -C bash | awk '/running_script/ { print $1 }' و wsl ls $foo && echo $PWD . _ لست متأكدًا مما إذا كان هذا يحتاج إلى حالة استخدام منفصلة عن الحالة السابقة. _ الحل الحالي هو اقتباس أمر bash ، على سبيل المثال: bash -c 'ps -o pid,args -C bash | awk ''/-bash/ { print $1 }''' . قد تتضمن حالة الاستخدام هذه سلاسل متعددة الأسطر أيضًا على سبيل المثال:
ps -o pid,args -C bash | \
awk '/running_script/ { print $1 }'
  • حالة الاستخدام 2 أ: أرغب في تنفيذ أمر منبثق في غلاف آخر مع بعض الإقحام PS - هل هذه حالة استخدام؟

  • حالة الاستخدام 3: أحتاج إلى npm run $scriptName لمواصلة العمل ، أي المتغيرات الداخلية . (قد يكون هذا ضمنيًا ولا يلزم ذكره).

هناك سؤال حول ما إذا كان يجب أن تكون هناك حالات استخدام لـ interpolating strings أي g++ $CppFile @conanbuildinfo.args -o timer --std=c++11 أم أننا فقط نلعب على ذلك ونقول أن قواعد الهروب الحالية تغطي هذا؟

من المحتمل ألا تكون هذه حالات الاستخدام الصحيحة (أو جميعها) ، لكنني أعتقد أنه سيكون من المفيد توثيق حالات الاستخدام والقدرة على الرجوع إليها عند مناقشة هذه الميزة وإلا فمن السهل أن تضيع في كيفية معالجة الميزة فعليًا (أو لا) ) حالات استخدام العميل.

أيضًا ، يبدو لي أن حالة الاستخدام الثانية تتطلب "استدعاء القشرة". لست متأكدًا من أن الشخص الأول يفعل ذلك. يبدو أنه يمكن استدعاء exe مباشرة.

rkeithhill هل يمكنك إضافة الحلول الحالية

oising ، أنا أيضًا أقدر استجابتك المدروسة.

ما الذي يمنحه ins ... والذي لا يمنحه & cmd --% ... ؟

--% في شكله الحالي ، _parameter_ (الرمز) - الذي أفترض أننا نريد الاحتفاظ بسلوكه - لا يمكن استخدامه مقابل cmd /c --% ، لأنه لا يدعم _multi-command_ cmd سطر أوامر ^ كحرف هروب.) ، بالنظر إلى أن أول | مسعّر سيتم تفسيره على أنه مشغل أنابيب _PowerShell's_ وأن & يتم تمريره حرفيًا.
ينطبق الأمر نفسه على نظام التشغيل Unix ، حيث يكون --% عديم الفائدة بشكل عام ، ومع sh -c يفشل تمامًا ، لأن sh يتوقع سطر الأوامر كوسيطة _single_ (على سبيل المثال ، sh -c --% echo hi ينتج سطرًا فارغًا ، لأنه يتم تنفيذ echo وحده كأمر).

ins ، مع مطلبه لتحديد سطر الأوامر التمريري بتمريره _ كسلسلة واحدة_ يحل هذه المشاكل ، وكما هو مذكور ، يسمح أيضًا باستخدام استيفاء السلسلة لدمج قيم المتغير والتعبير _PowerShell_.

ويقودنا هذا الأخير إلى سبب اعتبار البيان_المقترح --% _ شارع النهاية_ :

  • لا يوجد مسار انتقالي من تنفيذ سطر أوامر موجود مسبقًا كما هو تمامًا لدمج قيم المتغير والتعبير _PowerShell_ فيه.

    • الطريقة الوحيدة - الغامضة والمرهقة - لتحقيق ذلك هي تحديد _ متغيرات البيئة المساعدة_ التي تخزن قيم PowerShell المهمة والتي يمكنك الرجوع إليها بعد ذلك (قذيفة مناسبة مع %...% أو $... ) في سطر الأوامر الأصلي.
  • لديك الإحراج لعدم قدرتك على دمج بيان --% في خط أنابيب PowerShell أكبر.

    • لاحظ أن هناك أسبابًا مشروعة _non_- قص ولصق لاستدعاء الصدفة الأصلية ، حيث قد تتوقع هذا التكامل ؛ على وجه التحديد ، يتطلب تمرير بيانات _raw بايت _ عبر خط أنابيب (وسيط) وإرسال _ سلاسل بدون سطر جديد لاحق _ استخدام الأنبوب الأصلي - راجع إجابة SO هذه للحصول على مثال واقعي.
  • هناك أيضًا الإحراج المتمثل في أن المعلمة --% _parameter_ --% _statement_ يعمل على Unix أيضًا ، فلماذا لا --% _parameter_ ؟ (على سبيل المثال ،
    /bin/echo --% 'hi "noon"' ينتج حرفيا 'hi noon' (بدلاً من المتوقع hi "noon" ) ، بسبب echo تلقي وسيطتين ، حرفيا 'hi و noon' ، مع الاحتفاظ بعلامات الاقتباس الفردية كبيانات وعلامات اقتباس مزدوجة).


ins ، كبديل مقترح لكشف --% ، سيكون من الناحية المثالية مجرد غلاف للراحة_ حول cmd /c و sh -c ، لكنه في الواقع _ مطلوب_:

  • على الأقل _ مؤقتًا_ على Unix ، طالما لم يتم إصلاح 1995 # ، لأن استدعاء sh -c '...' مباشرة حاليًا لا يمرر الوسيطات التي تتضمن " المضمنة بشكل صحيح.

  • _غير متغير_ على Windows ، لأنك تحتاج إلى تمرير سطر الأوامر _as-is_ إلى cmd عبر المعلمة lpCommandLine الخاصة بـ CreateProcess (والتي لا تستطيع المعلمة --% القيام بها بسبب قصرها على أمر _one_) ؛ وبدلاً من ذلك ، فإن محاولة تمرير سطر الأوامر كسلسلة مفردة _ محاطة بـ "..." بشكل عام مرة أخرى لا تعمل بقوة بسبب # 1995.


يمكن تجنب مشاكل تمرير _argument_ من خلال توفير سطر الأوامر لتنفيذ _via stdin_ (والذي يمكن ويجب أن يدعمه أيضًا ins ) ، أي إلى _pipe_ سطر الأوامر / نص البرنامج إلى shell القابل للتنفيذ:

  • في Unix ، يعمل هذا بشكل جيد ، لأن تمرير الرمز عبر _stdin_ إلى sh هو في الأساس نفس تمرير ملف _script_ للتنفيذ (تمامًا مثل sh -c '<code>' is ):
PSonUnix> @'
echo '{ "foo": "bar" }' | cat -n
'@ | sh

     1  { "foo": "bar" }
  • للأسف ، على نظام التشغيل Windows cmd لا يتعامل مع مثل هذا الإدخال بشكل جيد: فهو يطبع شعاره ويردد كل أمر قبل التنفيذ ، جنبًا إلى جنب مع سلسلة المطالبة:
PSonWin> 'date /t & ver' | cmd

Microsoft Windows [Version 10.0.18363.836]
(c) 2019 Microsoft Corporation. All rights reserved.

C:\Users\jdoe>date /t & ver
Sun 07/26/2020

Microsoft Windows [Version 10.0.18363.836]

C:\Users\jdoe>

للأسف ، يُظهر PowerShell نفسه سلوكًا غير مفيد بالمثل: انظر # 3223


تمامًا مثل sh وجميع الأصداف الشبيهة بـ POSIX ( dash ، bash ، ksh ، zsh ) ، معظم لغات البرمجة النصية _do_ بشكل صحيح دعم إدخال stdin-as-script ، مثل python و node و ruby و perl .

PS> 'print("hi")' | python

hi

لدمج قيم المتغير والتعبير _PowerShell_ ، لديك مرة أخرى خيار استخدام استيفاء السلسلة / التسلسل:

PS> $foo = 'bar'; "print(`"$foo`")" | python

bar

أو استخدام ميزة تمرير الحجة للمترجم الفوري:

PS> @'
import sys
print(sys.argv[1])
'@ | python - bar

bar

آمل أن يوضح ما سبق أن هناك _لا حاجة_ إلى بناء جملة خاص على الإطلاق - لا بيان --% ولا بيان #! ولا كتل كود Markdown - وكلها مرة أخرى تفتقر إلى القدرة على دمج القيم من برنامج PowerShell النصي.

بالنسبة إلى قابلية تكوين الغلاف الأصلي للاستخدام: من أجل إمكانية التنبؤ ، لا أعتقد أنه يجب علينا تقديم واحدة ؛ يمكن للمستخدمين الذين يرغبون في استهداف قشرة مختلفة توجيه سطر الأوامر إلى الملف القابل للتنفيذ الخاص بالصدفة أو بمجرد إصلاح 1995 # ، قم بتمريره كوسيطة.

  • هناك تباين قابل للنقاش وهو استهداف /bin/bash (مع تراجع (غير مرجح) إلى /bin/sh ) - بينما يأمل المرء أن تعتمد سطور الأوامر المنشورة على ميزات POSIX الإلزامية فقط ، وسطر الأوامر مع Bash-isms (الميزات غير POSIX التي لا يُتوقع أن تدعمها جميع تطبيقات /bin/sh ) من المحتمل أن تكون متوفرة ، نظرًا لانتشار bash .

تضمين التغريدة

أرى أن فوائد هذه الميزة المعينة أكثر أهمية بكثير من التأثير # 1995.

أجد أنه من المحير للعقل أننا نبذل الكثير من الجهد الذي نبذله في جعل ميزة القص واللصق هذه - في المقام الأول من أجل الراحة التفاعلية_ - مواطن من الدرجة الأولى (محرج ومحدود الميزات) ، في حين أن عجز PowerShell الأساسي عن المرور فارغًا الوسائط والوسيطات باستخدام أحرف مضمنة " .

لكنني لا أرى الناس يصلون إلى # 1995 في البرية بشكل جماعي

أنا أفعل ، وللأسباب التي ناقشتها سابقًا - سترى المزيد والمزيد_.

مرة أخرى ، أود أن أزعم أن القشرة التي تقوم بما يلي ، كما يفعل PowerShell حاليًا ، لديها مشكلة خطيرة :

# On Unix
PS> /bin/echo '{ "foo": "bar" }'

{ foo: bar }

rjmholt CommandAst له خاصية المدى مع سلسلة الإدخال. إعادة التحليل بسيطة مثل التقسيم حسب المساحة الأولى على Windows أو التقسيم بمسافات على Unix. لذلك أتوقع أننا لم نفقد شيئًا في السلسلة وأن نحصل على أداء جيد.

نعم ، أنا أفهم القرعة هناك ، وربما تكون تخصيصات AST في هذا السيناريو ليست مروعة (على الرغم من أنني أجادل بأن اللغة لا ينبغي أن تولد مخصصات غير ضرورية لبناء جملة بسيط). لكن كل ما عليك فعله هو تخيل إدخال يراه bash / cmd كسلسلة ولا يبدأ PowerShell في حل المشكلات:

لا يتم التحليل باستخدام PowerShell الحالي:

--% my_command "\" "

التوزيعات ، لكن التقسيم على مسافات يعطي نتيجة خاطئة:

--% my_command "\"    "\"

(يجب أن نرسل 4 مسافات في السلسلة ، لكن PowerShell يرى سلسلتين منفصلتين في مصفوفة)

rjmholt ، كل الأسئلة الرائعة في أسفل تعليقك أعلاه ، والتي توحي لي مرة أخرى أن الإجابة الصحيحة هي: لا حاجة إلى بناء جملة خاص.

لقد تناولت السؤال حول ماهية shell الأصلي القابل للتنفيذ الذي يجب استخدامه في تعليقي السابق ، ولكن بالنسبة إلى:

هل ستقوم القذائف الأخرى أو اللغات الأخرى بتنفيذ هذا أم أنها بالفعل؟ على مستوى نحوي أم على أي مستوى آخر؟ إذا كان الأمر كذلك ، فكيف؟

لست على علم بأي لغة أخرى قامت بذلك على مستوى بناء الجملة دون استخدام محددات صريحة والسماح بـ _ التداخل_.
على سبيل المثال ، يمتلك perl `...` لتشغيل أوامر shell ، لذا يمكنك تشغيل الأمر التالي من برنامج نصي على Unix ، على سبيل المثال:
my $foo='/'; print `ls $foo | cat -n`

الجوانب الرئيسية هي استخدام المحددات الصريحة والقدرة على دمج القيم من المتصل - وكلاهما مفقود من الاقتراح الحالي لبيان --% .

كما ذكرنا سابقًا ، يمكننا _يمكننا_ استخدام هذا الأسلوب لـ _ مشغل _ جديد (أو نوع من بناء الجملة القائم على المحددات ، بشكل اختياري) ، لكنني لا أعتقد أن هذا يستحق ذلك ، نظرًا لذلك
ins "ls $foo | cat -n" (أو مع متغير هنا) سيفي بالغرض ، دون إثقال اللغة بتعقيد إضافي.

perl حلاً (مناسبًا) على مستوى البنية _ لأنه ليس في حد ذاته shell_ ولكنه يريد إجراء مكالمات shell بأكبر قدر ممكن من الراحة.

على النقيض من ذلك ، نحن _ نحن_ a shell (أيضًا) ، ونقدم استدعاءات على غرار shell _direct_ ، دون أي بناء جملة إضافي (وإن كان معيبًا حاليًا - راجع # 1995).
يبدو أن توفير صيغة خاصة لجعل استدعاءات أصداف مختلفة سهلة بقدر الإمكان غير ضروري.

تضمين التغريدة

_ إذا علمنا (و PowerShell) أننا ندير ملفًا تنفيذيًا أصليًا ، فلماذا نحتاج إلى "استدعاء عامل التشغيل الأصلي" على الإطلاق؟ _

إذا قام PowerShell بتحليل سلسلة إدخال وحصل على CommandAst ، فسيقوم PowerShell باكتشاف الأمر.
إذا كان الأمر أمرًا أصليًا ، فإن PowerShell يحول ast إلى NativeCommandProcessor.
يمكننا تنفيذ (NativeCommandProcessor تجريبي جديد) للحالة التي ستعيد تحليل مدى Ast (أي سلسلة الإدخال) بحيث نحصل على الاسم / المسار الأصلي القابل للتنفيذ وبقية السلسلة كوسيطة أو وسيطات بواسطة قواعد نظام التشغيل.

إذا أراد المستخدم نسخ ولصق من shell ، فعليه كتابة "cmd" أو "bash" - فهذا سيعمل بدون تحرير.
إذا أراد المستخدم النسخ واللصق ، فسيعمل سطر الأوامر الأصلي أيضًا مثل g++ timer.cpp @conanbuildinfo.args -o timer --std=c++11 .

لكن انتظر ألا تتمكن أبدًا من استخدام أي بناء جملة PowerShell مع الأوامر الأصلية إذا فعلنا كل ذلك؟ لذا مثل sc.exe query $serviceName سيمرر $serviceName كسلسلة حرفية؟

لكن انتظر ألا تتمكن أبدًا من استخدام أي بناء جملة PowerShell مع الأوامر الأصلية إذا فعلنا كل ذلك؟ إذن ، مثل sc.exe query $serviceName سيمرر $serviceName كسلسلة حرفية؟

الخيار --% غير مخصص لتلبية هذه الحاجة.

sc.exe query $serviceName تتم معالجته بواسطة &"<cmd>"

الخيار --% غير مخصص لتلبية هذه الحاجة.

sc.exe query $serviceName تتم معالجته بواسطة &"<cmd>"

نعم بالتأكيد ، لا أعتقد أن هذا ما يشير إليه @ iSazonov . أنا أقرأ ذلك كما لو أنهم يقترحون تغييرًا عامًا لكيفية عمل ربط المعلمات للأوامر الأصلية.

نعم بالتأكيد ، لا أعتقد أن هذا ما يشير إليه @ iSazonov . أنا أقرأ ذلك كما لو أنهم يقترحون تغييرًا عامًا لكيفية عمل ربط المعلمات للأوامر الأصلية.

يا رب لا آمل.

يا رب لا آمل.

أحيانًا عندما تقوم بالعصف الذهني للملخص ، من السهل أن تنسى ما هو واضح. أعني أن نكون منصفين ، فقد قرأناها جميعًا وبدأنا على الفور في التفكير في التنفيذ دون أن ندرك مقدار كسرها.

أو أفتقد شيئًا واضحًا وهذا ليس هو المقترح على الإطلاق 😁

essentialexch ،

sc.exe query $serviceName تتم معالجته بواسطة &"<cmd>"

& "<cmd>" يعمل فقط إذا تم تقييم <cmd> إلى مجرد أمر _name أو path_ ، _ لا يتضمن الوسيطات_ - يجب تمرير الوسائط بشكل منفصل ، بشكل فردي - ولا تحتاج في حد ذاتها إلى "...." الاقتباس من المراجع المتغيرة ليتم توسيعها (على سبيل المثال ،
$exe = 'findstr'; & "where.exe $exe" فشل حسب التصميم؛ يجب أن يكون & "where.exe" $exe (علامات الاقتباس المزدوجة اختيارية هنا ؛ إذا تم حذفها ، فإن & تكون اختيارية أيضًا))

نعم بالتأكيد ، لا أعتقد أن هذا ما يشير إليه @ iSazonov . أنا أقرأ ذلك كما لو أنهم يقترحون تغييرًا عامًا لكيفية عمل ربط المعلمات للأوامر الأصلية.

اقتراحي هو إصلاح # 1995 (مع كسر التغيير) بأبسط ما يمكن. من سبب لا يعمل الاستيفاء. السبب أنه ليس اقتراحًا نهائيًا - إنه عرض توضيحي لكيفية تنفيذ الإصلاح في دقائق. وتوضح بشكل أساسي أننا لا نحتاج إلى عامل تشغيل محلي للاتصال على الإطلاق كما أشار

التوزيعات ، لكن التقسيم على مسافات يعطي نتيجة خاطئة:

rjmholt نعم ، لكن أعتقد أنك
الطفل الأول من CommandAst هو StringConstantExpressionAst مع الأمر الأصلي مثل BareWord. يمكننا قطع الكلمة المجردة من CommandAst Extent والحصول على قائمة المعلمات دون تغيير ast-s. ولكن يمكننا إضافة ast جديدة للاحتفاظ بقائمة المعلمات أيضًا.
أقضي وقتًا في التفسير لأنني أرغب أدناه في تلخيص المناقشة وأشعر أننا سنحتاج إلى تنفيذ بعض التحسينات التي تبدو معقدة ولكني أشعر أنه يمكن تنفيذها بشكل بسيط و __ مع إلغاء الاشتراك السهل للتوافق مع الإصدارات السابقة__


أعتقد أن نية @ SteveL-MSFT من الاقتراح الأولي كانت لتجنب تغيير جذري.
أتفق مع TSlivede و @ mklement0 في أن هذه المناقشة أظهرت أن بناء الجملة الجديد غير ضروري لأنه لا يحل جميع المشكلات الأساسية مثل # 1995 و # 12975. من ناحية أخرى ، فإنه يضيف تعقيدًا للغة ، بينما نريد ، على العكس من ذلك ، _تبسيط_ العمل مع التطبيقات المحلية.

__الطريقة الوحيدة للمضي قدمًا هي إجراء تغيير فاصل أو أكثر .__ (بعد ذلك ، قد يكون عامل تشغيل جديد أو أمر cmdlet مفيدًا في بعض السيناريوهات أيضًا.)


يجب أن نبدأ بتلخيص حالات الاستخدام وتوقعات المستخدم.
شاهد مشاركة rkeithhill الرائعة أعلاه

  1. يريد المستخدمون تمكين / تعطيل الاستيفاء.
    يحتوي PowerShell بالفعل على سلاسل / سلاسل هنا بعلامات اقتباس مفردة ومزدوجة.
    هدفنا هو فهم كيفية تطبيق / تحسين / تحسين.
  2. يريد المستخدمون تشغيل أي ملف تنفيذي أو قذيفة

    • أي أمر قابل للتنفيذ - يبدأ الأمر باسم التطبيق ويتبع الوسائط

      • مع / بدون الاستيفاء

      • على خط واحد / على خط متعدد

    • من المحتمل أن تكون shell حالة خاصة لأن الوسيطة (الحجج) عبارة عن _script_

      • في سيناريو النسخ واللصق ، لا يريد المستخدمون الاستيفاء ويريدون سطرًا واحدًا ومتعددًا

      • في سيناريو البرنامج النصي ، يريد المستخدمون تمكين / تعطيل الاستيفاء ويريدون سطرًا واحدًا ومتعددًا

    أفكار:
    هذا يجعلنا نعتقد أن سلوك سيناريو النسخ واللصق يجب أن يكون هو الوضع الافتراضي.
    تعتمد عوامل إنهاء الخط على الملف القابل للتنفيذ (في bash ، `في PowerShell). هذا يجعلنا نعتقد أن:
    (1) يجب ذكر القشرة بشكل صريح على أنها قابلة للتنفيذ ،
    (2) ربما يجب استدعاء أي ملف تنفيذي يحتوي على أسطر متعددة عن طريق غلاف أو يتعين علينا إجراء تحليل خاص (لإزالة أداة إنهاء وبناء قائمة وسيطة تعود إلى مشكلة الهروب)
    (3) يمكننا معالجة سيناريو لصق النسخ في PSReadline. يمكنه تحويل المخزن المؤقت إلى أمر PowerShell الصحيح.

  3. يريد المستخدمون سطرًا واحدًا ومتعدد الأسطر.

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

لا أريد أن أكتب المزيد لأن TSlivede و @ mklement0 يمكنهما تحديث الإصدارات القديمة ) ، وتعداد جميع حالات الاستخدام (بدءًا من

أريد فقط أن أضيف أنه يمكننا التفكير في أوامر cmdlets جديدة لتبسيط عمليات اعتماد المستخدم مثل Invoke-Shell (Invoke-NativeShell) ، و Test-Arguments (مثل echoargs.exe لإظهار أن التطبيق الأصلي يحصل على المساعدة للمستخدمين ويظهرها) ، و Convert-Arguments ( لتحويل مدخلات المستخدم إلى وسيطات تم تجاوزها الصحيحة).

ملاحظة: كما أوضحت أعلاه ، يمكن بسهولة إلغاء الاشتراك في سلوك سطر واحد للتوافق مع الإصدارات السابقة في وقت التشغيل.

تعتمد عوامل إنهاء الخط على الملف القابل للتنفيذ (في bash ، `في PowerShell).

\ ليس فاصل سطر في bash .

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

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

حتى لو كان مجرد افتراض افتراضي ، فأنا لا أرى كيف يكون مفيدًا.

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

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

أعتقد أن الشيء الذي افتقده هو كيف يمكنك تبديل هذا السلوك سريعًا دون طلب ذلك صراحة (مثل عامل الاتصال الأصلي).

تضمين التغريدة

_ إذا علمنا (و PowerShell) أننا ندير ملفًا تنفيذيًا أصليًا ، فلماذا نحتاج إلى "استدعاء عامل التشغيل الأصلي" على الإطلاق؟ _

إذا قام PowerShell بتحليل سلسلة إدخال وحصل على CommandAst ، فسيقوم PowerShell باكتشاف الأمر.
إذا كان الأمر أمرًا أصليًا ، فإن PowerShell يحول ast إلى NativeCommandProcessor.
يمكننا تنفيذ (NativeCommandProcessor تجريبي جديد) للحالة التي ستعيد تحليل مدى Ast (أي سلسلة الإدخال) بحيث نحصل على الاسم / المسار الأصلي القابل للتنفيذ وبقية السلسلة كوسيطة أو وسيطات بواسطة قواعد نظام التشغيل.

إذا أراد المستخدم نسخ ولصق من shell ، فعليه كتابة "cmd" أو "bash" - فهذا سيعمل بدون تحرير.
إذا أراد المستخدم النسخ واللصق ، فسيعمل سطر الأوامر الأصلي أيضًا مثل g++ timer.cpp @conanbuildinfo.args -o timer --std=c++11 .

أريد أن أؤكد ما تقصده بذلك: هل تقترح تجاهل جميع قواعد بوويرشيل بشكل أساسي ، عند استدعاء الملفات التنفيذية الخارجية؟

على وجه التحديد: هل تقترح ذلك الجري على سبيل المثال

/bin/echo (1..5)

في بوويرشيل لن يتم طرح 1 2 3 4 5 لكن يجب أن ينتج بدلاً من ذلك (1..5) ؟

إذا كان هذا هو ما تقترحه بالفعل ، فلا بد أن أقول: أعتقد أن هذه فكرة رهيبة.

هذا لا يبسط الأشياء (تتصرف الملفات التنفيذية الخارجية الآن بشكل مختلف من الناحية التركيبية عن أوامر cmdlets الداخلية) وليس عليها أيضًا أن تفعل أي شيء مع # 1995 IMHO ...

تضمين التغريدة
من فوق :

  • هل ستقوم القذائف الأخرى أو اللغات الأخرى بتنفيذ هذا أم أنها بالفعل؟ على مستوى نحوي أم على أي مستوى آخر؟ إذا كان الأمر كذلك ، فكيف؟

الشيء الوحيد الذي يتبادر إلى ذهني هو مشغل ipythons ! :

تشغيل !ps -'fax' || true في نواتج ipython:

  261 pts/0    Sl     0:00          \_ /usr/bin/python /usr/bin/ipython
  311 pts/0    S      0:00              \_ /bin/bash -c ps -'fax' || true
  312 pts/0    R      0:00                  \_ ps -fax

( لا تعرض ps علامات الاقتباس حول الوسيطات ، ولكن ps -'fax' || true يُعطى بالفعل كوسيطة واحدة لـ bash)

ومع ذلك ، لا تزال هذه الميزة تسمح باستيفاء متغيرات بايثون في هذا الأمر ( {pyvar} ).

وعلى غرار @ mklement0 الصورة سبيل المثال ، ipython الأدوات الوحيدة هذا

لأنها ليست في حد ذاتها صدفة

إذا كان ipython يسمح فقط ببناء Python ، فلن يكون مفيدًا جدًا كصدفة ، لذلك يسمحون لهذا التركيب بإعادة توجيه الأوامر إلى bash لتكون قابلة للاستخدام كصدفة. PowerShell على المطالبات ناحية أخرى أن تكون قذيفة (حتى يتم حلها # 1995، وأنا لا أقول أنه هو قذيفة)، لذلك سيكون من الغريب جدا أن أضيف جملة خاص لاستدعاء قذائف أخرى.

إذا تم تنفيذ شيء من هذا القبيل لأي سبب من الأسباب (آمل ألا يتم ذلك) ، أقترح استخدام ! بدلاً من --% كـ "مشغل call shell".

! شيء قد يخمنه الناس (لأنهم يعرفون ! لهذا الغرض من ipython (أو من وضع الأمر vim أو من less أو من ftp ) )

من ناحية أخرى ، يصعب كتابة --% ، ومن غير المحتمل أن يتم تخمينها ، والأهم من ذلك: إن الاستخدام الحالي لـ --% له في رأيي القليل جدًا من القواسم المشتركة مع "تمرير الأشياء إلى غلاف آخر" سلوك. يحاكي --% عنصرًا واحدًا بالضبط من بناء جملة cmd: استبدال المتغير (وحتى هذا ليس تمامًا). لا يدعم escape char ^ ، ولا يسمح بإعادة التوجيه إلى الملفات ، وما إلى ذلك. الشيء الوحيد المفيد إلى حد ما بخصوص --% هو القدرة على تمرير المحتوى الحرفي إلى lpCommandLine - لكن هذا شيء لا يجيده "مشغل الاتصال" المقترح.

هناك اختلاف آخر (سبق ذكره) بين "عامل تشغيل الاتصال" المقترح و --% : أحدهما ينتهي عند الأنابيب ، والآخر لا ينتهي - مربكًا جدًا للمستخدمين الجدد. من ناحية أخرى ، يقوم ! بإعادة توجيه | إلى الغلاف في جميع التطبيقات التي اختبرتها حتى الآن (ipython ، vim ، less ، ed ، إلخ).

HELP about_Logical_Operators -S

نعم ، يعد ! بحد ذاته مشكلة لأنه عامل نفي منطقي في اللغة.

راجع للشغل أحد العروض البديلة كان &! - نوع من عامل التشغيل "call native / shell".

أتمنى أن يكون TSlivede قد شدد على جزء "آمل ألا يكون" أكثر عندما قال "إذا حدث شيء كهذا لأي سبب من الأسباب (آمل ألا يتم)"

  • لا يوجد عامل تشغيل / عبارة _ مع وسيطات فردية_ يمكنه حل مشكلة I-want-to-use-PowerShell-القيم في-the-native-command-line بشكل نظيف ، بالنظر إلى أن $ يُستخدم كمتغير sigil في _both_ قذائف PowerShell و POSIX.

  • لا يوجد عامل تشغيل / عبارة _ بدون محددات صريحة حول سطر الأوامر الأصلي بالكامل_ يمكنه حل مشكلة نهاية سطر الأوامر where-does-the-native-command-end (التي قد تهتم بها أو لا تهتم بها).

@ PowerShell / بوويرشيل-جنة ناقشت هذا اليوم. في هذه المرحلة ، لا يبدو أن هناك اتفاقًا على بيان المشكلة الأولي ولا تصميم حول كيفية حلها ، لذلك لا نعتقد أنه يمكننا إدخال هذا في 7.1 مع تصميم مستقر.

@ PowerShell / بوويرشيل-جنة ناقشت هذا اليوم. في هذه المرحلة ، لا يبدو أن هناك اتفاقًا على بيان المشكلة الأولي ولا تصميم حول كيفية حلها ، لذلك لا نعتقد أنه يمكننا إدخال هذا في 7.1 مع تصميم مستقر.

182 تعليقات!

كان هناك بعض النقاش الرائع حول هذا! سأستمر في مراقبة أي تعليقات جديدة حول هذه المسألة. ما زلنا نشجع المجتمع على تنفيذ أمر cmdlet من النوع Invoke-NativeCommand المنشور على PSGallery بشكل مستقل عن هذه المشكلة.

أعتقد أنه من المؤسف ، عندما كان لديك حل وسط ولكنه مفيد للغاية على https://github.com/PowerShell/PowerShell/issues/13068#issuecomment -662732627 ، لإسقاط هذا. أعلم أنك تريد الإجماع ، لكن في بعض الأحيان يكون التسوية هي أفضل ما يمكن أن يحدث. لا ، هذا ليس مثاليًا ، لكن حل SO أحادي الخط سيكون مفيدًا للغاية. على الأقل في رأي هذا الشخص.

essentialexch لنكون واضحين ، ليس لدينا إجماع داخل فريق PowerShell

بما أن هذا مؤجل ماذا عن تنفيذ المساعدين

يمكننا التفكير في أوامر cmdlets الجديدة لتبسيط عمليات اعتماد المستخدم مثل Invoke-Shell (Invoke-NativeShell) ، و Test-Arguments (مثل echoargs.exe لإظهار أن التطبيق الأصلي يحصل على مساعدة للمستخدمين ويظهرها) ، و Convert-Arguments (لتحويل مدخلات المستخدم إلى الحجج الهاربة الصحيحة).

أعتقد أن حجج الاختبار يمكن أن تكون مفيدة للغاية.

لقد قمت للتو بنشر وحدة ، Native ، ( Install-Module Native -Scope CurrentUser ) والتي أدعوكم جميعًا لتجربتها والتي سأستخدم أوامرها أدناه ؛ حالات الاستخدام الرقمية المشار إليها مأخوذة من تعليق أعلاه .

إذا أردنا في أي وقت إزالة الضباب المفاهيمي ، أعتقد أننا بحاجة إلى تأطير حالات الاستخدامات بشكل مختلف.
_ لا أحد منهم يتطلب أي تغييرات في التحليل_.

حالة الاستخدام [استدعاء shell الأصلي]:

تريد تنفيذ _individ command_ (حالة الاستخدام 1) أو سطر أوامر _multi-command بأكمله _ (حالة الاستخدام 2) _ مكتوبًا من أجل shell الأصلي للنظام الأساسي _ (هذه المشكلة):

  • نظرًا لأنك تستخدم صيغة قشرة مختلفة ، فأنت تقوم بتمرير الأمر (سطر) _كسلسلة واحدة_ إلى الصدفة الهدف ، من أجل _it_ لإجراء التحليل ؛ يوفر استيفاء سلسلة PowerShell القدرة على تضمين قيم PowerShell في السلسلة التي تم تمريرها (حالة الاستخدام 2 أ).
  • يغطي ins ( Invoke-NativeShell ) حالات الاستخدامات هذه.
# Use case 1: Single executable call with line continuation, on Unix.
@'
tar -cvpzf /share/Recovery/Snapshots/$(hostname)_$(date +%Y%m%d).tar.gz \
    --exclude=/proc \
    --exclude=/lost+found 
'@ | ins

# Use case 2: Entire Bash command line (also with line continuation)
@'
ps -o pid,args | awk \
  '/pwsh/ { print $1 }'
'@ | ins

# Use case 2a: Entire Bash command line (also with line continuation) with string interpolation.
# Note the double-quoted here-string and the need to escape the $ that is for Bash as `$
$fields = 'pid,args'
@"
ps -o $fields | awk \
  '/pwsh/ { print `$1 }'
"@ | ins

# Alternative to use case 2a: pass the PowerShell value *as a pass-through argument*,
# which allows passing the script verbatim.
# Bash sees the pass-through arguments as $1, ... (note that the `awk` $1 is unrelated).
@'
ps -o $1 | awk \
  '/pwsh/ { print $1 }'
'@ | ins - 'pid,args'

إن بناء الجملة هنا ليس هو الأكثر ملاءمة (ومن هنا جاء اقتراح تنفيذ متغير مضمّن - راجع # 13204) ، لكنك لا تستخدمه ؛ للأوامر الحرفية ، يمكنك استخدام '...' ، والذي يتطلب فقط _doubling_ تضمين ' ، إذا كان موجودًا.

إليك أيضًا بديل معقول لـ "عامل تشغيل StackOverflow" :

إذا قمت بوضع التالية PSReadLine معالج رئيسي في الخاص بك $PROFILE الملف، عليك أن تكون قادرا على استخدام البديل، ضد لسقالة دعوة إلى ins مع حرفيا سلسلة هنا التي يتم لصق نص الحافظة الحالي فيها.أدخل يرسل المكالمة.

# Scaffolds an ins (Invoke-NativeShell) call with a verbatim here-string
# and pastes the text on the clipboard into the here-string.
Set-PSReadLineKeyHandler 'alt+v' -ScriptBlock {
  [Microsoft.PowerShell.PSConsoleReadLine]::Insert("@'`n`n'@ | ins ")
  foreach ($i in 1..10) { [Microsoft.PowerShell.PSConsoleReadLine]::BackwardChar() }
  # Comment the following statement out if you don't want to paste from the clipboard.
  [Microsoft.PowerShell.PSConsoleReadLine]::Insert((Get-Clipboard))
}

حالة الاستخدام [اتصال مباشر قابل للتنفيذ]:

تريد استدعاء ملف تنفيذي خارجي واحد باستخدام صيغة _PowerShell_ ، مع _حجج فردية_ (استخدام حالتي 1 أ و 3).

  • هذا هو التفويض الأساسي لأي قذيفة ، ومن الأهمية بمكان أن تعمل بقوة.

    • يجب أن تكون قادرًا على الاعتماد على قدرة PowerShell على المرور عبر أي وسيطات تنتج من _its_ parsing _as-is_ إلى الهدف القابل للتنفيذ. هذا ليس هو الحال حاليا - انظر # 1995 .
  • يتطلب منك فهم بناء جملة _PowerShell's_ و _its_ الوسيطات الوصفية.

    • يجب أن تدرك أنه يتم استخدام ` كحرف هروب ولمتابعة السطر.
    • يجب أن تدرك أن PowerShell يحتوي على أحرف أولية إضافية تتطلب الاقتباس / الهروب للاستخدام الحرفي ؛ هذه (لاحظ أن @ يمثل مشكلة فقط كأول حرف للحجة.):

      • للأصداف التي تشبه POSIX (على سبيل المثال ، Bash): @ { } `$ ، إذا كنت تريد منع التوسيع المسبق بواسطة PowerShell)
      • مقابل cmd.exe : ( ) @ { } # `
      • بشكل فردي ` -إلغاء مثل هذه الأحرف. يكفي (على سبيل المثال ، printf %s `@list.txt ).

بينما ننتظر رقم 1995 حتى يتم إصلاحه ، تعمل الوظيفة ie (لـ i nvoke (خارجي) e xecutable) على ملء الفراغ ، ببساطة عن طريق إرسال مكالمة مباشرة ؛ على سبيل المثال ، بدلاً من المكالمة التالية:

# This command is currently broken, because the '{ "name": "foo" }' argument isn't properly passed.
curl.exe -u jdoe  'https://api.github.com/user/repos' -d '{ "name": "foo" }'

يمكنك استخدام ما يلي:

# OK, thanks to `ie`
ie curl.exe -u jdoe  'https://api.github.com/user/repos' -d '{ "name": "foo" }'

تأتي الوحدة النمطية Native مع شيء يشبه echoArgs.exe ، الأمر dbea ( Debug-ExecutableArguments ) ؛ عينة الإخراج على Windows:

# Note the missing first argument, the missing " chars., and the erroneous argument boundaries.
PS> dbea '' 'a&b' '3" of snow' 'Nat "King" Cole' 'c:\temp 1\' 'a \" b'
7 argument(s) received (enclosed in <...> for delineation):

  <a&b>
  <3 of snow Nat>
  <King>
  <Cole c:\temp>
  <1\ a>
  <">
  <b>

Command line (helper executable omitted):

  a&b 3" of snow "Nat "King" Cole" "c:\temp 1\\" "a \" b"

باستخدام رمز التبديل -UseIe ( -ie ) ، يمكنك إخبار dbea لتمرير الوسيطات عبر ie ، مما يدل على أنه يحل المشاكل:

# OK, thanks to -UseIe
PS> dbea -UseIe '' 'a&b' '3" of snow' 'Nat "King" Cole' 'c:\temp 1\' 'a \" b'
6 argument(s) received (enclosed in <...> for delineation):

  <>
  <a&b>
  <3" of snow>
  <Nat "King" Cole>
  <c:\temp 1\>
  <a \" b>

Command line (helper executable omitted):

  "" a&b "3\" of snow" "Nat \"King\" Cole" "c:\temp 1\\" "a \\\" b"

ملاحظة: بمجرد إصلاح 1995 # ، لم يعد مطلوبًا ie ؛ من أجل التوافق إلى الأمام ، تم تصميم ie لاكتشاف الإصلاح وتأجيله تلقائيًا ؛ أي بمجرد أن يتم الإصلاح ، سيتوقف ie عن تطبيق الحلول وسيتصرف بشكل فعال مثل مكالمة مباشرة / & .

حالة الاستخدام [استدعاء مباشر قابل للتنفيذ لـ Windows مخادع]:

هناك مشكلتان رئيسيتان تظهران في _Windows فقط_:

  • أنت تستدعي ملف تنفيذي "خادع" له متطلبات اقتباس تختلف عن أكثر الاصطلاحات استخدامًا ؛ على سبيل المثال ، يتطلب الأمر msiexec.exe و msdeploy.exe أن يتم اقتباس prop="<value with spaces>" بهذه الطريقة بالضبط - الاقتباس حول الجزء _value_ - على الرغم من "prop=<value with spaces>" - اقتباس من الكل الحجة - _يجب_ أن تكون متكافئة (هذا الأخير هو ما يفعله PowerShell - بشكل مبرر - وراء الكواليس).

  • أنت تستدعي _ ملف دفعي _ مع _ وسيطة لا تحتوي على مسافات ، ولكنها تحتوي على أحرف أولية cmd.exe مثل & أو ^ أو | ؛ على سبيل المثال:

    • .\someBatchFile.cmd 'http://example.org/a&b'
    • PowerShell - بشكل مبرر - يمرر http://example.org/a&b _unquoted_ (نظرًا لعدم وجود مسافة بيضاء مضمنة) ، لكن هذا يكسر استدعاء ملف الدُفعات ، لأن cmd.exe - بشكل غير معقول - تخضع الوسائط التي تم تمريرها إلى ملف دفعي إلى نفس حكم الإعراب الذي سيتم تطبيقه داخل cmd.exe بدلاً من قبولها كحرفية.

    • ملاحظة: أثناء استخدام الملفات الدفعية _directly_ للتنفيذ الوظيفي ربما يتضاءل ، فإن استخدامها كنقاط إدخال CLI لا يزال شائعًا جدًا ، مثل Azure az CLI ، والذي يتم تنفيذه كملف دفعي az.cmd .

ملاحظة: يتعامل ie تلقائيًا مع هذه السيناريوهات لملفات الدُفعات و msiexec.exe و msdeploy.exe ، لذلك لن تكون هناك حاجة لبذل جهد إضافي للمكالمات _ most_ ؛ ومع ذلك ، من المستحيل توقع _all_ الملفات التنفيذية "المارقة".

هناك طريقتان لحل هذا:

  • بالنظر إلى أن cmd.exe ، بعد تطبيق تفسيره الخاص على الوسيطات في سطر الأوامر ، _ يفعل_ الاحتفاظ بالاقتباس كما هو محدد ، يمكنك التفويض إلى ins call على Windows:

    • ins '.\someBatchFile.cmd "http://example.org/a&b"'
    • إذا كنت تستخدم سلسلة _expandable_ ، فهذا يمكّنك مرة أخرى من تضمين قيم PowerShell في سلسلة الأوامر.

      • $url = 'http://example.org/a&b'; ins ".\someBatchFile.cmd `"$url`""

  • بدلاً من ذلك ، استخدم التنفيذ الحالي --% ، لكن احذر من حدوده:

    • .\someBatchFile.cmd --% "http://example.org/a&b"'
    • بالنظر إلى كيفية تنفيذ --% ، فإن الطريقة الوحيدة لتضمين قيم PowerShell هي - بشكل محرج - تحديد _aux. متغير البيئة_ وقم بالرجوع إليها باستخدام بناء الجملة %...% :

      • $env:url = 'http://example.org/a&b'; .\someBatchFile.cmd --% "%url%"


معالجة الأخطاء

سيؤدي https://github.com/PowerShell/PowerShell-RFC/pull/88 المعلق إلى تكامل أفضل لمعالجة الأخطاء مع الملفات التنفيذية الخارجية (الأصلية).

في غضون ذلك ، تأتي الوحدة النمطية Native مع ميزتين للاشتراك المخصص للتعامل مع

  • ins يدعم -e / -ErrorOnFailure التبديل، الذي يلقي خطأ إذا $LASTEXITCODE هو غير صفرية بعد استدعاء قذيفة الأم.

  • iee هي دالة مجمعة لـ ie والتي تتسبب في حدوث خطأ بشكل مماثل إذا كان $LASTEXITCODE غير صفري بعد استدعاء الملف التنفيذي الخارجي.

هناك العديد من التفاصيل الدقيقة للأوامر التي تأتي مع الوحدة النمطية.
نأمل أن تغطي المساعدة المستندة إلى التعليقات الشاملة إلى حد ما هذه المعلومات بشكل كافٍ.

إذا أردنا في أي وقت إزالة الضباب المفاهيمي ، أعتقد أننا بحاجة إلى تأطير حالات الاستخدامات بشكل مختلف.

عظيم! ما نشرته سابقًا كان فقط لجعل الناس يفكرون في إنشاء حالات استخدام أكثر وأفضل.

يجب أن أوضح بعض الجوانب المهمة لـ ins ( Invoke-NativeShell ) التي تختلف عما اقترحته سابقًا ؛ كان الهدف هو حساب الانتشار الشامل لـ bash وتوفير CLI متسق عبر الأنظمة الأساسية.

  • في Unix ، قررت الاتصال بـ /bin/bash بدلاً من /bin/sh ، نظرًا لانتشار Bash في كل مكان ، ولكن يمكنك الاشتراك في استخدام /bin/sh مع -UseSh ( -sh ) ( /bin/sh يعمل أيضًا كبديل في حالة عدم وجود /bin/bash ).

    • من أجل الحصول على تجربة متسقة عبر نماذج الاستدعاء والأنظمة الأساسية ، قمت بإخفاء القدرة على تعيين $0 ، اسم الاستدعاء ؛ أي أن أي وسيطات تمريرية تبدأ بـ $1 ، وهو ما يتوافق مع كيفية تمرير الوسائط عند تمرير البرنامج النصي من خط الأنابيب ، وعلى الأرجح ما يتوقعه المستخدمون:
# Script as argument
PSonUnix> ins 'echo $# arguments; echo "[$1] [$2]"' one two
2 arguments
[one] [two]

# Script via pipeline; note the "-" to signal that the script is piped.
PSonUnix> 'echo $# arguments; echo "[$1] [$2]"' | ins - one two
2 arguments
[one] [two]

# As an aside: script as argument, with pipeline input *as data*:
PSonUnix> 'one', 'two' | ins 'cat -n'
     1  one
     2  two
  • على نظام التشغيل Windows ، كان علي استخدام ملف دفعي مؤقت خلف الكواليس لأسباب فنية ، لكنني أعتقد أن استخدام صيغة الملف الدفعي هو في النهاية الخيار الأفضل على أي حال ( %%i بدلاً من %i for متغيرات الحلقة ، والقدرة على الهروب من % كـ %% ).

    • يتيح استخدام ملف دفعي أيضًا دعم الوسائط التمريرية ، كما هو الحال في نظام التشغيل Unix:
# Script as argument
PSonWin> ins 'echo [%1] [%2]' one two
[one] [two]

# Script via pipeline; note the "-" to signal that the script is piped.
PSonWin> 'echo [%1] [%2]' | ins - one two
[one] [two]
هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات