كيف يمكنني العثور على المسار المصدر للبرنامج النصي المنفذ؟[ينسخ]

StackOverflow https://stackoverflow.com/questions/801967

  •  03-07-2019
  •  | 
  •  

سؤال

هذا السؤال لديه بالفعل إجابة هنا:

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

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

هل كانت مفيدة؟

المحلول

تم نشر النص في كل مكان في الأصل بواسطة جيفري سنوفر من فريق PowerShell (الوارد في إجابة سكايلر) والاختلافات التي نشرها Keith Cedirc وEBGreen، جميعها تعاني من عيب خطير--يعتمد ما إذا كان الكود يُبلغ عما تتوقعه على المكان الذي تسميه به!

يتغلب الكود الخاص بي أدناه على هذه المشكلة بمجرد الرجوع النصي نطاق بدلا من الأبوين نِطَاق:

function Get-ScriptDirectory
{
    Split-Path $script:MyInvocation.MyCommand.Path
}

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

  1. كود مضمن [مضمن]
  2. وظيفة مضمنة، أيوظيفة في البرنامج الرئيسي [وظيفة مضمنة]
  3. وظيفة مصدر نقطة، أي.تم نقل نفس الوظيفة إلى ملف .ps1 منفصل [مصدر نقطة]
  4. وظيفة الوحدة، أيتم نقل نفس الوظيفة إلى ملف .psm1 منفصل [الوحدة النمطية]

يعرض العمودان الأخيران نتيجة استخدام نطاق البرنامج النصي (أي.$script :) أو مع النطاق الأصلي (مع -النطاق 1).نتيجة "البرنامج النصي" تعني أن الاستدعاء أبلغ بشكل صحيح عن موقع البرنامج النصي.نتيجة "الوحدة النمطية" تعني أن الاستدعاء أبلغ عن موقع الوحدة التي تحتوي على الوظيفة بدلاً من البرنامج النصي الذي يسمى الوظيفة؛يشير هذا إلى عيب كلتا الوظيفتين حيث لا يمكنك وضع الوظيفة في وحدة نمطية.

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

table of input combinations

وأخيراً هذه هي السيارة التجريبية:

function DoubleNested()
{
    "=== DOUBLE NESTED ==="
    NestCall
}

function NestCall()
{
    "=== NESTED ==="
    "top level:"
    Split-Path $script:MyInvocation.MyCommand.Path
    #$foo = (Get-Variable MyInvocation -Scope 1).Value
    #Split-Path $foo.MyCommand.Path
    "immediate func call"
    Get-ScriptDirectory1
    "dot-source call"
    Get-ScriptDirectory2
    "module call"
    Get-ScriptDirectory3
}

function Get-ScriptDirectory1
{
    Split-Path $script:MyInvocation.MyCommand.Path
    # $Invocation = (Get-Variable MyInvocation -Scope 1).Value
    # Split-Path $Invocation.MyCommand.Path
}

. .\ScriptDirFinder.ps1
Import-Module ScriptDirFinder -force

"top level:"
Split-Path $script:MyInvocation.MyCommand.Path
#$foo = (Get-Variable MyInvocation -Scope 1).Value
#Split-Path $foo.MyCommand.Path

"immediate func call"
Get-ScriptDirectory1
"dot-source call"
Get-ScriptDirectory2
"module call"
Get-ScriptDirectory3

NestCall
DoubleNested

محتويات ScriptDirFinder.ps1:

function Get-ScriptDirectory2
{
    Split-Path $script:MyInvocation.MyCommand.Path
#   $Invocation = (Get-Variable MyInvocation -Scope 1).Value
#   Split-Path $Invocation.MyCommand.Path
}

محتويات ScriptDirFinder.psm1:

function Get-ScriptDirectory3
{
    Split-Path $script:MyInvocation.MyCommand.Path
#   $Invocation = (Get-Variable MyInvocation -Scope 1).Value
#   Split-Path $Invocation.MyCommand.Path
}

لست على دراية بما تم تقديمه في PowerShell 2، ولكن من المحتمل جدًا أن نطاق البرنامج النصي لم يكن موجودًا في PowerShell 1، في الوقت الذي نشر فيه Jeffrey Snover مثاله.

لقد فوجئت عندما وجدت مثال الكود الخاص به منتشرًا على نطاق واسع على الويب، لكنه فشل على الفور عندما جربته!ولكن كان ذلك لأنني استخدمته بشكل مختلف عن مثال Snover (لم أسميه في أعلى البرنامج النصي ولكن من داخل وظيفة أخرى (مثالي "المتداخل مرتين").)

تحديث 2011.09.12

يمكنك أن تقرأ عن هذا من خلال النصائح والحيل الأخرى حول الوحدات النمطية في مقالتي المنشورة للتو على موقع Simple-Talk.com:مزيد من أسفل حفرة الأرنب:وحدات PowerShell والتغليف.

نصائح أخرى

لقد قمت بوضع علامة على سؤالك الخاص بالإصدار 1.0 من Powershell، ومع ذلك، إذا كان لديك حق الوصول إلى الإصدار 3.0 من Powershell، فأنت تعرف أنه لديك $PSCommandPathو$PSScriptRootمما يجعل الحصول على مسار البرنامج النصي أسهل قليلاً.يرجى الرجوع إلى قسم "ميزات البرنامج النصي الأخرى" في هذه الصفحة لمزيد من المعلومات.

لقد كنا نستخدم كودًا مثل هذا في معظم نصوصنا لعدة سنوات دون أي مشاكل:

#--------------------------------------------------------------------
# Dot source support scripts
#--------------------------------------------------------------------
$ScriptPath = $MyInvocation.MyCommand.Path
$ScriptDir  = Split-Path -Parent $ScriptPath
. $ScriptDir\BuildVars.ps1
. $ScriptDir\LibraryBuildUtils.ps1
. $ScriptDir\BuildReportUtils.ps1

لقد واجهت نفس المشكلة مؤخرًا.المقالة التالية ساعدتني في حل المشكلة: http://blogs.msdn.com/powershell/archive/2007/06/19/get-scriptdirectory.aspx

إذا لم تكن مهتمًا بكيفية عمله، فإليك كل التعليمات البرمجية التي تحتاجها في المقالة:

function Get-ScriptDirectory
{
$Invocation = (Get-Variable MyInvocation -Scope 1).Value
Split-Path $Invocation.MyCommand.Path
}

وبعد ذلك تحصل على المسار بمجرد القيام بما يلي:

$path = Get-ScriptDirectory

أعتقد أنه يمكنك العثور على مسار البرنامج النصي قيد التشغيل باستخدام

$MyInvocation.MyCommand.Path

نأمل أن يساعد!

سيدريك

هذه واحدة من تلك الشذوذات (في رأيي على الأقل) في PS.أنا متأكد من أن هناك سببًا وجيهًا لذلك، لكنه لا يزال يبدو غريبًا بالنسبة لي.لذا:

إذا كنت في برنامج نصي ولكن ليس في وظيفة، فسوف يمنحك $myInvocation.InvocationName المسار الكامل بما في ذلك اسم البرنامج النصي.إذا كنت في برنامج نصي وداخل وظيفة، فسوف يمنحك $myInvocation.ScriptName نفس الشيء.

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

MyModule (folder)
 - MyModule.psd1 (help New-ModuleManifest)
 - MyScriptFile.ps1 (ps1 files are easy to test)

ثم يمكنك الرجوع إلى MyScriptFile.ps1 في MyModule.psd1.سيؤدي الرجوع إلى .ps1 في صفيف NestedModules إلى وضع الوظائف في حالة جلسة الوحدة النمطية بدلاً من حالة الجلسة العامة.(كيفية كتابة بيان الوحدة النمطية)

NestedModules = @('.\MyScriptFile.ps1','.\MyOtherScriptFile.ps1')

محتوى MyScriptFile.ps1

function Get-ScriptDirectory {
    Split-Path $script:MyInvocation.MyCommand.Path
}

try {
    Export-ModuleMember -Function "*-*"
}
catch{}

تقوم أداة المحاولة/الالتقاط بإخفاء الخطأ من Export-ModuleMember عند تشغيل MyScriptFile.ps1

انسخ ال MyModule الدليل إلى أحد المسارات الموجودة هنا $env:PSModulePath

PS C:\>Import-Module MyModule
PS C:\>Get-Command -Module MyModule

CommandType     Name                                               ModuleName                                                                                                                                                
-----------     ----                                               ----------                                                                                                                                                
Function        Get-ScriptDirectory                                MyModule  
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top