gpt4 book ai didi

powershell - 用于更改从 powershell 中运行的目录的批处理文件不执行任何操作

转载 作者:行者123 更新时间:2023-12-02 23:07:49 24 4
gpt4 key购买 nike

我的 PATH 上有一个小的“dev.bat”批处理文件,我运行它以切换到我的开发项目目录 W:\ .这在 CMD 中可以正常工作,但在 PowerShell(或 PWSH)中运行时则不行。

从 PowerShell 运行 .bat 文件没有其他问题。

PS C:\> type C:\dev.bat
W:
CD W:\dev
PS C:\> dev.bat

me@computer C:\
> W:

me@computer W:\dev
> CD W:\dev

PS C:\> echo "Why did dev.bat not change directory??"
Why did dev.bat not change directory??

PS C:\> W:
PS W:\>

不, cmd /c dev.bat没什么区别。

最佳答案

从 PowerShell 运行时,批处理文件总是在 ( cmd.exe ) 子进程中运行 [1] ,鉴于 PowerShell 本身不理解批处理语言。

更改子进程中的工作目录仅限于该子进程(及其自己的子进程),并且对调用进程没有影响; 子进程无法更改调用进程的工作目录 .

您唯一的选择是:

  • 让您的批处理文件回显(打印)所需的工作目录
  • 在 PowerShell 中捕获该路径并将其传递给 Set-Location

  • 如果您不想更改批处理文件,请使用以下解决方法:
    Set-Location -LiteralPath (cmd /c 'dev.bat >NUL && cd')

    # Or if you want to use the 'cd' alias for Set-Location and
    # are confident that path never has "[" characters in it (so that
    # it can't be mistaken for a wildcard expression):
    cd (cmd /c 'dev.bat >NUL && cd')

    如果根本不需要涉及批处理文件,而您只想要 创建更改到预定义位置(工作目录)的自定义函数的便捷方法 ,将以下函数放入您的 $PROFILE文件:
    # Helper function to place in $PROFILE, which generates custom quick-cd
    # functions, based on a function name and target directory path.
    function New-QuickCD ($Name, $LiteralPath) {
    $funcDef = @"
    function global:$Name { Push-Location -LiteralPath "$LiteralPath" } # quick-CD function
    "@
    Invoke-Expression $funcDef # define in current session too
    $funcDef >> $PROFILE # append to $PROFILE
    }

    备注 :
  • 生成的函数使用 Push-Location而不是 Set-Location使用 Pop-Location 可以轻松返回到之前的位置( popd )。
  • 为方便起见,生成的函数也通过 Invoke-Expression 在当前 session 中定义。 [2] 在创建时,因此您不必重新加载(点源)$PROFILE或打开一个新 session ,然后才能调用新生成的函数。
  • 盲目追加到$PROFILE>>意味着如果你重新定义一个函数,新的定义会生效,但过时的前一个会留在文件中,需要手动清理;评论 # quick-CD function放置在每个生成的函数之后是为了促进这一点 - 有关更复杂的 New-QuickCD 版本,请参见底部部分。更新旧的定义到位。
  • 您可以通过多种方式使该函数更加健壮和方便:强制使用参数、验证路径是否存在(默认情况下)、将路径解析为绝对路径 - 再次参见底部部分。

  • 例如,创建一个名为 dev 的函数切换到 W:\dev ,然后你会打电话:
    # Generate function 'dev', which switches to 'W:\dev', 
    # append it to your $PROFILE file, and also define it in this session:
    New-QuickCD dev W:\dev

    # Call it:
    dev # changes the current location to W:\dev; use 'popd' to return.

    更坚固、更灵活 New-QuickCD功能:

    它在上述版本的基础上改进如下:
  • 它使参数成为强制性的。
  • 它验证目标目录路径是否存在。
  • 它定义了支持 -PrintOnly 的函数。 switch 只打印函数的目标目录,而不更改它。
  • 它首先将相对路径解析为绝对路径,以便您可以运行 New-QuickCD foo .定义一个切换到当前位置绝对路径的函数。
  • 当你重新定义一个函数时,之前的定义会自动更新:
  • 为了启用此功能 $PROFILE整体重写,使用 >重定向运算符。
  • 要删除函数,您仍然必须编辑 $PROFILE手动。
  • 它带有基于评论的帮助;运行 help New-QuickCD -Examples , 例如。
  • function New-QuickCD {
    <#
    .SYNOPSIS
    Creates a custom quick-CD function.

    .DESCRIPTION
    Creates a custom quick-CD function and appends it your $PROFILE file.

    Such a function changes to a fixed location (directory) stored inside the
    function, specified at creation time to allow for quickly changing to
    frequently used directories using a short name.

    For convenience, a newly created function is also defined for the running
    session (not just for all future sessions).

    The quick-CD functions use Push-Location to change location, which
    enables you to easily return to the previously active location with
    Pop-Location (popd).

    To determine what location a given quick-CD function *would* change to,
    invoke it with the -PrintOnly switch.

    .PARAMETER FunctionName
    The name of the quick-CD function to define.

    .PARAMETER DirectoryPath
    The literal path of the directory the quick-CD function should change to.
    If given a relative path, it is resolved to an absolute one first.
    For convenience, you may specify a *file* path, in which case that file's
    parent path is used.

    .NOTES
    Your $PROFILE file is recreated every time you use this function, using the
    > redirection operator, so as to support updating functions in place.

    To *remove* a quick-CD function, edit $PROFILE manually.

    .EXAMPLE
    New-QuickCD dev W:\dev

    Adds a 'dev' function to $PROFILE, which on invocation changes the current
    location to W:\dev
    * Call just 'dev' to change to W:\dev. Use popd to return to the previous
    location.
    * Call 'dev -PrintOnly' to print what location function 'dev' *would*
    change to.

    .EXAMPLE
    New-QuickCD proj .

    Adds a 'proj' function to $PROFILE, which on invocation changes to the
    the location that is current at the time of calling New-QuickCd.

    #>
    param(
    [Parameter(Mandatory)] [string] $FunctionName,
    [Parameter(Mandatory)] [string] $DirectoryPath
    )

    Set-StrictMode -Version 1; $ErrorActionPreference = 'Stop'

    # Resolve the path to a full path. Fail if it doesn't exist.
    $fullPath = (Resolve-Path -ErrorAction Stop -LiteralPath $DirectoryPath).Path
    # As a courtesy, if the path is a *file*, we use its parent path instead.
    if (Test-Path -PathType Leaf $fullPath) {
    $fullPath = [IO.Path]::GetDirectoryName($fullPath)
    }

    # Define a comment that identifies the functions we add to $PROFILE as
    # quick-CD functions.
    $idComment = '<# quick-CD function generated with New-QuickCD #>'

    # Generate the new function's source code...
    # * on a *single line*, which enables easy filtering when updating $PROFILE below
    # * with a distinctive comment at the end of the line that identifies the
    # function as a quick-CD function.
    # * with the global: scope specifier, which makes it easier to call the
    # same definition with Invok-Expression to make the function available in the
    # current session too.
    $newFuncDef = @"
    $idComment function global:$FunctionName { param([switch] `$PrintOnly) if (`$PrintOnly) { "$fullPath" } else { Push-Location -LiteralPath "$fullPath" } }
    "@
    # ... define it in the current session (doing this *before* updating $PROFILE ensures early exit if the function name is invalid)
    Invoke-Expression $newFuncDef
    # ... and update $PROFILE:
    # Get the current content of $PROFILE
    [string] $currentProfileContent = if (Test-Path -LiteralPath $PROFILE) { Get-Content -Raw -LiteralPath $PROFILE }
    # Try to replace an existing definition.
    $newProfileContent = $currentProfileContent -replace ('(?m)^{0} function global:{1} .+$' -f [regex]::Escape($idComment), [regex]::Escape($FunctionName)), $newFuncDef
    if (-not $currentProfileContent -or $newProfileContent -ceq $currentProfileContent) { # Profile didn't exist or nothing was replaced -> we must append the new definition.
    $newProfileContent = $newProfileContent.TrimEnd() + [Environment]::NewLine * 2 + $newFuncDef
    }
    # Write the file.
    $newProfileContent > $PROFILE

    }

    [1] 相比之下,批处理文件在从 cmd.exe 调用时在进程内运行,类似于 PowerShell 如何运行其 *.ps1正在处理的脚本。
    另一方面,类似 POSIX 的 shell,例如 Bash,默认情况下在子进程中运行它们的脚本,除非使用采购( .source )

    [2] 虽然这是对 Invoke-Expression 的安全使用,它 should generally be avoided .

    关于powershell - 用于更改从 powershell 中运行的目录的批处理文件不执行任何操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55707051/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com