Как найти исходный путь к исполняемому скрипту? [дубликат]
этот вопрос уже есть ответ здесь:
Я хочу знать, с какого пути был запущен мой сценарий выполнения.
Это часто не будет $pwd.
Мне нужно вызывать другие скрипты, которые находятся в структура папок относительно моего скрипта, и хотя я мог бы жестко кодировать пути, это и неприятно, и немного больно в шее при попытке продвижения от "dev" до "test" до "production".
7 ответов
вездесущий скрипт первоначально разместил Джеффри До Смерти команды PowerShell (приведено в Скайлер) и вариации, опубликованные Китом Седирком и EBGreen, все страдают от серьезного недостатка-сообщает Ли код, что вы ожидаете, зависит от того, где вы его называете!
мой код ниже преодолевает эту проблему путем простой ссылки скрипт объем вместо родитель область применения:
function Get-ScriptDirectory
{
Split-Path $script:MyInvocation.MyCommand.Path
}
чтобы проиллюстрировать проблему, я создал тестовый автомобиль, который evalutes целевое выражение в четырех различных способов. (Заключенные в квадратные скобки термины являются ключами к следующей таблице результатов.)
- встроенный код [inline]
- встроенная функция, т. е. функция в основной программе [встроенная функция]
- функция точечного источника, т. е. та же функция перемещена в отдельную.ps1 файл [точечный источник]
- функции модуля, т. е. та же функция перешла в отдельную.файл psm1 [модуль]
последние два столбца показывают результат использования script scope (т. е. $script:) или родительской scope (with-scope 1). Результат "script" означает, что вызов правильно сообщил о местоположении скрипта. Результат "модуль" означает, что вызов сообщил о местоположении модуля, содержащего функцию, а не сценарий, который вызвал функцию; это указывает на недостаток обеих функций, которые вы не удается поместить функцию в модуль.
установка проблемы модуля в сторону замечательное наблюдение из таблицы заключается в том, что использование подхода родительской области в большинстве случаев не удается (на самом деле, в два раза чаще, чем это удается).
наконец, вот тестовое транспортное средство:
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.ps1
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