PowerShell在多个提示功能和作用域之间切换

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

我发现了以下我不理解的行为。我的$profile中有一些功能(具体来说,它们会更改prompt,因此会更改function prmopt { }),这些设置会更改我的提示,并且在启动控制台时,如果我将功能(. PromptCustom)来源完全生效,新的提示将接管。但是,我不希望我的$profile太大,所以我将五个或五个左右不同的提示移到了模块中,但是当我尝试对其中的任何一个进行点源处理时,什么也没发生。它们只是输出提示内容,但not会接管默认的prompt

目标是能够具有根据需要在提示之间切换的多种功能(即,不是一个适用于每个控制台的提示,我只需将function prompt放在我的$profile中)。当我将遵循以下模板的功能移动到模块时,它们全部中断,因此我想知道这是否是一个范围问题,以及如何实现在模块中具有多个提示功能的目标,我可以在这些功能之间进行切换而不是被迫将它们保留在我的$profile中? (编辑:正如@ mklement0所指出的那样更新这个问题,因为它实际上是关于必需的目标的,即提示我可以在两者之间进行切换)。

这里是我的提示函数之一,如果在我的$profile中定义了此函数,则该函数将作为默认提示perfectly接管,但是如果将其放入模块中则不执行任何操作:

function PromptShortenPath {
    # https://stackoverflow.com/questions/1338453/custom-powershell-prompts
    function shorten-path([string] $path) {
        $loc = $path.Replace($HOME, '~')
        # remove prefix for UNC paths
        $loc = $loc -replace '^[^:]+::', ''
        # make path shorter like tabs in Vim,
        # handle paths starting with \\ and . correctly
        return ($loc -replace '\\(\.?)([^\\])[^\\]*(?=\\)','\$1$2')
    }
    function prompt {
        # our theme
        $cdelim = [ConsoleColor]::DarkCyan
        $chost = [ConsoleColor]::Green
        $cloc = [ConsoleColor]::Cyan

        write-host "$([char]0x0A7) " -n -f $cloc
        write-host ([net.dns]::GetHostName()) -n -f $chost
        write-host ' {' -n -f $cdelim
        write-host (shorten-path (pwd).Path) -n -f $cloc
        write-host '}' -n -f $cdelim
        return ' '
    }

    if ($MyInvocation.InvocationName -eq "PromptShortenPath") {
        "`nWarning: Must dotsource '$($MyInvocation.MyCommand)' or it will not be applied to this session.`n`n   . $($MyInvocation.MyCommand)`n"
    } else {
        . prompt 
    }
}
powershell scope prompt
2个回答
0
投票

[Scepticalist's helpful answer为激活prompt功能导入时提供有效的解决方案。

您问题中用于激活功能[[按需]的方法],以后通过点源提供其中prompt功能为嵌套]的功能>,如果该功能是从从模块,如下所述;有关解决方案,请参见底部。关于

您尝试了什么

. prompt

这不是函数prompt

定义

的点源,而是运行采购范围中的函数。
    实际上,它(无意义地)打印(一次,作为输出)提示字符串应该是什么,并使函数局部变量在调用者的范围内徘徊。
  • 因此,通过[[嵌套
  • prompt函数内的PromptShortenPath函数定义,点源

    that在调用者的作用域自动中定义了prompt函数,以及shorten-path函数[1]

      如果PromptShortenPath函数在
    • 模块外部]中定义,则点源表示

      sourcing

    范围是调用者的当前范围

    ,它在此处定义了嵌套函数,并且随着新prompt函数的出现,交互式提示字符串也按预期更改。相反,如果在[[在模块内部]中定义了PromptShortenPath函数,则点源表示它的源范围是
  • 源模块
  • ,这意味着

    调用者的] >当前作用域为不受影响

    ,并且从不看到嵌套的shorten-pathprompt函数-因此,交互式提示字符串确实发生了[[not更改。
    这需要重复:点源化function(与script相对)在
      scope原始域
    的当前范围内运行该函数,而不是
  • caller's] >当前范围;也就是说,从模块中点播函数总是会在那个模块的当前作用域中运行它,该作用域与caller's范围不同,并且与之无关(除非调用者碰巧是顶级作用域)在同一模块中)。
  • 相反,Scepticalist的解决方案,通过使模块的shorten-pathprompt函数top-level函数隐式地(导出并)将它们都通过Import-Module导入到调用者的作用域中,并再次,新的prompt函数在调用者作用域中的出现会更改交互式提示字符串。也可用于模块的替代方法:

    最简单的解决方案是使用范围说明符global:定义嵌套函数,该说明符直接在全局范围中定义它,而不管哪个范围包含定义。作为有益的副作用,您不必再在调用时点源提示激活功能。


    # Use a dynamic module to simulate importing the `Set-Prompt` function # from a (regular, persisted) module. $null = New-Module { function Set-Prompt { Function shorten-path([string] $path) { $loc = $path.Replace($HOME, '~') # remove prefix for UNC paths $loc = $loc -replace '^[^:]+::', '' # make path shorter like tabs in Vim, # handle paths starting with \\ and . correctly return ($loc -replace '\\(\.?)([^\\])[^\\]*(?=\\)','\$1$2') } # Note the `global:` prefix. Function global:prompt { # our theme $cdelim = [ConsoleColor]::DarkCyan $chost = [ConsoleColor]::Green $cloc = [ConsoleColor]::Cyan write-host "$([char]0x0A7) " -n -f $cloc write-host ([net.dns]::GetHostName()) -n -f $chost write-host ' {' -n -f $cdelim write-host (shorten-path (pwd).Path) -n -f $cloc write-host '}' -n -f $cdelim return ' ' } } } # Now that Set-Prompt is imported, invoke it as you would # any function, and the embedded `prompt` function will take effect. Set-Prompt

    [1]请注意,虽然shorten-path原则上遵循PowerShell的名词-动词命名约定,但shorten不在approved verbs列表中。


    如果删除外部功能,并在模块路径中以相同名称另存为modulename.psm1,则在文件夹中:

    Function shorten-path([string] $path) { $loc = $path.Replace($HOME, '~') # remove prefix for UNC paths $loc = $loc -replace '^[^:]+::', '' # make path shorter like tabs in Vim, # handle paths starting with \\ and . correctly return ($loc -replace '\\(\.?)([^\\])[^\\]*(?=\\)','\$1$2') } Function prompt { # our theme $cdelim = [ConsoleColor]::DarkCyan $chost = [ConsoleColor]::Green $cloc = [ConsoleColor]::Cyan write-host "$([char]0x0A7) " -n -f $cloc write-host ([net.dns]::GetHostName()) -n -f $chost write-host ' {' -n -f $cdelim write-host (shorten-path (pwd).Path) -n -f $cloc write-host '}' -n -f $cdelim return ' ' } . prompt
    现在:
    Import-Module modulename

    0
    投票
    Import-Module modulename
    © www.soinside.com 2019 - 2024. All rights reserved.