批处理文件中的 CD 命令在 PowerShell 中不起作用

问题描述 投票:0回答:2

这是我的批处理文件:

CD c:/
PAUSE

在 Windows PowerShell 中运行时,我得到以下输出:

PS C:\some\path\here> .\myscript.bat

C:\some\path\here>CD c:/

c:\>PAUSE
Press any key to continue . . .
PS C:\some\path\here>

程序终止后,我又回到了开始的地方!

同时,在cmd中运行时:

C:\some\path\here>.\myscript.bat

C:\some\path\here>CD c:/

c:\>PAUSE
Press any key to continue . . .

c:\>

我得到了我想要的行为,程序结束后我仍保留在

C:\
目录中。

为什么会出现这种情况?我怎样才能在 PowerShell 中获得这种行为?

powershell batch-file cmd
2个回答
1
投票
  • 从 PowerShell

     运行批处理文件(
    *.cmd
    *.bat必然涉及
    cmd.exe
    子进程
    。 (PowerShell 本身不理解批处理文件,只有批处理文件解释器
    cmd.exe
    可以理解;作为单独的可执行文件,它总是在子进程中运行。)

  • 子进程从根本上不能设置其父进程的工作目录(也不能修改其环境变量)。因此,无论批处理文件设置为其工作目录如何,对 PowerShell 调用者都没有影响。

  • 因此,更改调用者的工作目录只能通过运行in-process的代码实现。

    • cmd.exe
      和PowerShell都运行它们的脚本文件 - 分别是批处理文件(
      *.cmd
      *.bat
      )和PowerShell脚本(
      *.ps1
      ) - in-process,使脚本文件能够更改进程的工作全局目录会话在其本机 shell 中 - 这是您从 cmd.exe
       会话
      调用批处理文件时看到的内容。

    • 在PowerShell中,您可以创建一个与批处理文件(在本例中)内容相同的*.ps1

      文件
      ,并调用它(例如.\myscript.ps1
      更改PowerShell会话的工作目录。

  • 相反,如果您想将工作目录更改范围(限制)到给定的脚本文件,以便在退出脚本时恢复原始工作目录:

    • cmd.exe

       中,您可以通过将批处理文件代码包含在 
      setlocal
      endlocal
       语句中来实现此目的(后者通常被省略,因为它在退出批处理文件时隐含),这不仅恢复了原始状态工作目录,还有原始环境变量。

    • PowerShell 提供

      没有类似机制,[1],因此必须手动保存和恢复之前的状态

      • 要恢复以前的工作目录(位置),必须使用以下习惯用法:

        $oldPwd = $PWD try { # ... script code that changes the working dir. goes here } finally { Set-Location -LiteralPath $oldPwd }
        
        
      • 也就是说,正是由于这个原因,

        Set-Location

         (cd
        ) 调用
        最好在 PowerShell 脚本中避免


[1] 但是,PowerShell 默认情况下将脚本中定义的范围shell 变量(以及其他定义,例如函数)定义到该脚本。 Shell 变量(例如 $foo

)是 PowerShell 特定的变量,与 
环境 变量(在 PowerShell 中以前缀 $env:
 引用)不同;修改后者确实会在全局进程中生效(并影响任何继承它们副本的子进程),并且 - 与批处理文件不同 - 没有作用域机制。
请注意,
cmd.exe
 使得 shell 变量和环境变量之间没有区别:定义的任何变量都是隐式环境变量。 

那是因为 *.bat 文件是

0
投票
,这有点奇怪。您可以通过将其保存到 *.bat 文件来轻松测试它,例如 testenv.bat

@set var=inside @echo %var%

然后像这样运行一下,观察脚本修改了外部环境
echo %var%
testenv.bat
echo %var%

最后一个命令打印出
inside
,这对大多数人来说是意想不到的

包括 PowerShell 在内的大多数其他 shell 中的正确行为是在子 shell 中运行脚本,除非使用显式 

source

/.

 命令
。 PowerShell 中的等效项也是
dot
source 运算符,因此如果您运行 *.ps1 脚本,则像这样运行 . path\to\your\script.ps1

但是您正在 PowerShell 中运行 *.bat 脚本,因此显然您不能这样做,因为它适用于完全不同的 shell。简而言之:你不能那样做。子 shell 永远无法更改父 shell 的环境,这就是
为什么 cd 始终是所有 shell 中的内置命令

© www.soinside.com 2019 - 2024. All rights reserved.