Как я могу найти исходный путь выполнения скрипта? [дубликат]
этот вопрос уже есть ответ здесь:
Я хочу быть в состоянии сказать, какой путь мой сценарий выполнения был запущен.
Это часто не будет $pwd.
Мне нужно вызвать другие скрипты, которые находятся в a структура папок относительно моего скрипта, и хотя я мог бы жестко кодировать пути, это неприятно и немного больно в шее при попытке продвижения от "dev" до "test" до "production".
7 ответов:
вездесущий скрипт, первоначально опубликованный Джеффри До Смерти команды PowerShell (задано в Скайлер) и вариации, опубликованные Китом Седирком и Эбгрином, все страдают от серьезного недостатка-сообщает Ли код, что вы ожидаете, зависит от того, где вы его называете!
мой код ниже преодолевает эту проблему путем простой ссылки скрипт объем вместо родитель область применения:
function Get-ScriptDirectory { Split-Path $script:MyInvocation.MyCommand.Path }
чтобы проиллюстрировать проблему, я создал тестовый автомобиль, который оценивает целевое выражение четырьмя различными способами. (Заключенные в квадратные скобки термины являются ключом к следующей таблице результатов.)
- встроенный код [inline]
- встроенная функция, т. е. функция в основной программе [встроенная функция]
- функция с точечным источником, т. е. та же функция перемещается в отдельный файл. ps1 [dot source]
- функции модуля, т. е. та же функция перекочевала в отдельную .psm1 file [module]
последние два столбца показывают результат использования script scope (т. е. $script:) или с родительской областью (с-scope 1). Результат "скрипт" означает, что вызов правильно сообщил местоположение скрипта. Результат "модуль" означает, что вызов сообщил о местоположении модуля, содержащего функцию, а не сценарий, который вызвал функцию; это указывает на недостаток обеих функций, которые вы не удается поместить функцию в модуль.
отложив вопрос модуля в сторону замечательное наблюдение из таблицы является то, что использование подхода родительской области чаще всего не удается (на самом деле, в два раза чаще, чем это удается).
наконец, вот тестовый автомобиль:
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, но вполне может быть, что script scope не существовал в PowerShell 1, в то время как Джеффри Сновер опубликовал свой пример.
Я был удивлен, когда, хотя я обнаружил, что его пример кода распространился далеко и широко в интернете, он сразу же потерпел неудачу, когда я попробовал его! Но это было потому, что я использовал его иначе, чем пример Snover (я назвал его не в script-top, а изнутри другой функции (мой " вложенный дважды" образец.))
обновление 2011.09.12
вы можете прочитать об этом с другими советами и трюками по модулям в моей только что опубликованной статье Simple-Talk.com: далее вниз по кроличьей норе: модули PowerShell и инкапсуляция.
вы отметили свой вопрос для Powershell версии 1.0, однако, если у вас есть доступ к Powershell версии 3.0, вы знаете, что есть
$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
надеюсь, что это помогает !
Седрик
Это одна из тех странностей (на мой взгляд по крайней мере) в ПС. Я уверен, что для этого есть вполне веская причина, но мне все еще кажется странным. Итак:
Если вы находитесь в скрипте, но не в функции, то $myInvocation.InvocationName даст вам полный путь, включая имя скрипта. Если вы находитесь в скрипте и внутри функции, то $myInvocation.ScriptName даст вам то же самое.
спасибо msorens! Это действительно помогло мне с моим пользовательским модулем. В случае, если кто-то заинтересован в создании своих собственных, вот как мой структурирована.
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.пс1
function Get-ScriptDirectory { Split-Path $script:MyInvocation.MyCommand.Path } try { Export-ModuleMember -Function "*-*" } catch{}
try / 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