Как я могу найти исходный путь к исполняемому скрипту?[дубликат]
-
03-07-2019 - |
Вопрос
На этот вопрос уже есть ответ здесь:
Я хочу иметь возможность определить, по какому пути был запущен мой исполняемый скрипт.
Часто это не будет $ pwd.
Мне нужно вызвать другие скрипты, которые находятся в структуре папок относительно моего скрипта, и хотя я мог бы жестко закодировать пути, это и неприятно, и немного затруднительно при попытке перейти от "dev" к "test" к "production".
Решение
Вездесущий скрипт, первоначально опубликованный Джеффри Сновер из команды PowerShell (приведено в Ответ Скайлер) и вариации, опубликованные Китом Седирком и Эбгрином, все страдают серьезным недостатком--сообщает ли код то, что вы ожидаете, зависит от того, где вы его вызываете!
Мой приведенный ниже код решает эту проблему, просто ссылаясь сценарий область применения вместо родитель область применения:
function Get-ScriptDirectory
{
Split-Path $script:MyInvocation.MyCommand.Path
}
Чтобы проиллюстрировать проблему, я создал тестовое средство, которое оценивает целевое выражение четырьмя различными способами.(Термины, заключенные в квадратные скобки, являются ключами к следующей таблице результатов.)
- встроенный код [inline]
- встроенная функция, т.е.функция в основной программе [встроенная функция]
- Функция с точечным источником, т.е.та же функция перенесена в отдельный файл .ps1 [точечный исходный код]
- Модульная функция, т.е.та же функция перенесена в отдельный файл .psm1 [модуль]
Последние два столбца показывают результат использования области действия скрипта (т. е.$script:) или с родительской областью (с -scope 1).Результат "script" означает, что вызов правильно сообщил о местоположении скрипта.Результат "module" означает, что вызов сообщил о местоположении модуля, содержащего функцию, а не скрипта, который вызвал функцию;это указывает на недостаток обеих функций, заключающийся в том, что вы не можете поместить функцию в модуль.
Оставляя проблему с модулем в стороне, замечательное наблюдение из таблицы заключается в том, что использование подхода родительской области в большинстве случаев приводит к сбою (на самом деле, в два раза чаще, чем это удается).
Наконец, вот тестовый автомобиль:
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 (я вызвал его не в начале скрипта, а изнутри другой функции (мой пример "вложенный дважды").)
Обновление 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
Надеюсь, это поможет !
Cédric
Это одна из тех странностей (по крайней мере, на мой взгляд) в 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{}
Функция try/ catch скрывает ошибку из Export-ModuleMember при запуске MyScriptFile.ps1
Скопируйте Мой модуль перейдите по одному из путей, найденных здесь $env:PSModulePath
PS C:\>Import-Module MyModule
PS C:\>Get-Command -Module MyModule
CommandType Name ModuleName
----------- ---- ----------
Function Get-ScriptDirectory MyModule