Dot-Sourced 文件中的 PSScriptRoot 如何工作?

Pri*_*rid 4 powershell relative-path dot-source

假设我有 2 个文件A.ps1B.ps1,在此目录结构中:

--  root
 |
 |-- A.ps1
 |
 |--  subfolder
   |
   |-- B.ps1
Run Code Online (Sandbox Code Playgroud)

A.ps1:

Write-Host $PSScriptRoot
Run Code Online (Sandbox Code Playgroud)

B.ps1:

. "\root\A.ps1"
Run Code Online (Sandbox Code Playgroud)

现在,考虑到这一事实

点采购获取您指定的脚本并立即执行它,就像它位于原始脚本中的该位置一样

问题:如果我运行B.ps1,我期望结果是\root\subfolder,但它是\root,为什么?

如果A.ps1是点源到 中B.ps1,那么脚本的内容不应该直接在 中写入一样A.ps1运行吗?意思是,不应该像从 调用一样运行,从而评估为? 我什至通过包装一个函数并在点采购调用该函数来测试这一点。仍然产生相同的结果..B.ps1$PSScriptRootB.ps1\root\subfolderA.ps1B.ps1

点采购到底是如何运作的?

zet*_*t42 7

正如评论者指出的那样,$PSScriptRoot它独立于范围。来自文档(强调我的):

$PSScriptRoot包含执行
脚本的父目录 的完整路径。

Dot-Sourcing 并不真正在现场“包含”脚本(#include例如,与 C++ 的指令相反),PowerShell 仍然知道它正在运行不同的脚本。与调用脚本(显式使用调用运算符&或通过输入其路径来运行脚本)相比,唯一不同的是作用域

不过,有一种方法可以获取$PSScriptRoot调用脚本的。使用和/或属性将要点源的脚本转换为高级函数 cmdlet。这使得自动变量可用,它为您提供(除其他外)调用脚本的 。CmdletBinding()Parameter()$PSCmdlet$PSScriptRoot

ps1

# CmdletBinding is an attribute of param(), so that is required as well
[CmdletBinding()] param()

$PSScriptRoot                         # Outputs directory that contains A.ps1
$PSCmdlet.MyInvocation.PSScriptRoot   # Outputs directory of the invoking script
Run Code Online (Sandbox Code Playgroud)

  • 好的 :-)。作为个人风格,我只真正使用点源来定义函数,然后在我的主脚本中调用这些函数 - 我不喜欢点源脚本实际执行带有副作用的代码的想法,因为它使它变得更困难记住在哪里发生了什么(一旦你获得了多个功能,就把它变成一个模块)...... (2认同)