从另一个脚本调用powershell脚本的正确方法

ldioqlga  于 2023-11-18  发布在  Shell
关注(0)|答案(1)|浏览(137)

假设我在同一个文件夹中有以下powershell脚本:

mainFolder
 | - subFolder
 |    | - MainScript.ps1
 |    | - SubScript.ps1

字符串
我想从MainScript.ps1调用SubScript.ps1,经过一些试验和错误,我发现了两种方法。(注意,我可能会从控制台调用MainScript.ps1,当前工作目录与两个脚本所在的目录不同)
第一选项

Push-Location $PSScriptRoot
./SubScript param1 param2
Pop-Location $PSScriptRoot


二选项

& "$PSScriptRoot/SubScript.ps1" param1 param2


这两个选项是完全相等的,还是一个优先于另一个?还有其他更好的方法来调用另一个脚本吗?
正如问题所述,

lf5gs5x2

lf5gs5x21#

这两种选择是否完全相同?
否:第一种方法 * 会更改当前位置 *,而第二种方法不会。
也就是说,被调用的脚本可能会将不同的位置视为当前位置,从而改变它使用的任何相对路径的含义。
换句话说:

  • Push-Location/PopLocation技术仅在您必须确保脚本自身的位置(反映在自动$PSScriptRoot变量中)是当前位置时才是必要的且仅是可取的。
  • 否则,你确实必须基于$PSScriptRoot显式地形成完整的路径; Mathias指出,作为使用可扩展(插值)字符串"..."的替代方案,你可以使用Join-Path小字符串:
# Equivalent to:
#   & "$PSScriptRoot/SubScript.ps1" param1 param2
& (Join-Path $PSScriptRoot SubScript.ps1) param1 param2

字符串
如果您必须更改当前位置,则存在陷阱

*更改当前位置(无论是通过Push-Location还是Set-Location)**都是 session-global

  • 这与cmd.exe使用内部setlocal命令将批处理文件中当前目录的更改限制为该批处理文件的能力形成对比。在POSIX兼容的shell(如Bash)中,这个问题永远不会出现,因为shell脚本在独立的 * 子进程 * 中执行。
  • 因此,除非您通过Pop-Location(或使用Set-Location使用存储先前位置的变量)恢复先前位置,否则最终也会更改脚本的 caller 的当前位置(可能是交互式提示符)。
  • 问题是您的位置恢复Pop-Location/Set-Location命令 * 可能无法执行 *,例如当用户使用Ctrl-C中止脚本或发生致命(脚本终止)时。

您可以使用以下习惯用法来防止后者,该习惯用法利用try / catch / finally语句的finally块来确保Pop-Location/Set-Location被 * 始终 * 调用:

# Change to this script's location (directory).
# Normally, this shouldn't fail.
Push-Location -ErrorAction Stop -LiteralPath $PSScriptRoot

try {

  # Perform operations here that rely on the script's directory to be 
  # the current location.

  ./SubScript param1 param2

}
finally {

  # Ensure that the previous location is returned to,
  # even in case of a fatal error or the user having pressed Ctrl-C.
  Pop-Location

}


注意事项:

  • GitHub issue #20490是一种通过将-Location参数引入Invoke-Command小程序来封装上述内容的提议。

相关问题