【问题标题】:What is the simplest way to make Alias in powershell?在powershell中制作别名的最简单方法是什么?
【发布时间】:2021-01-30 04:54:37
【问题描述】:

我想知道是否有任何简单的方法可以为 cmd 之类的 powershell 创建别名。 例如:在 cmd 中,doskey art=php artisan $* 其中$* 是可选的。目前,我在 powershell 中使用以下别名。

function runArtisanCommand
{
    param(
        [Parameter(Mandatory=$false, Position = 0, ValueFromRemainingArguments = $true)]
        $command
    )
    php artisan $command
}

Set-Alias art runArtisanCommand

这有点作用,但不要带标志。例如:我不能写art -hart route:list -c。在art -h 命令中,它打印php artisan 的输出并且根本不读取标志,但在art route:list -c 命令中,它会出错。

runArtisanCommand : Missing an argument for parameter 'command'. Specify a parameter of type 'System.Object' and try again.
At line:1 char:16
+ art route:list -c
+                ~~
    + CategoryInfo          : InvalidArgument: (:) [runArtisanCommand], ParameterBindingException
    + FullyQualifiedErrorId : MissingArgument,runArtisanCommand

我想要一个比这更简单的解决方案。提前致谢。

【问题讨论】:

  • function runArtisanCommand {& php artisan $args}
  • 作为 Mathias 给您的后续内容。您正在尝试为您的函数名称设置别名,这不是一回事。您可以直接在函数中设置别名。当然,别名是完整函数名的简称。函数动词-名词 { [CmdletBinding()] [Alias('vn')] 参数 ( )}。如果您只是按照 Mathias 向您展示的函数名称调用/运行您的函数,则不需要别名。要运行可执行文件,请参阅此处的选项:: • PowerShell: Running Executables
  • @postanote:如果您希望函数具有更长的名称,与短别名分开,请注意动词名词命名约定。但是使用Set-Alias 来定义别名本身并没有错——事实上,如果你不是目标函数的作者,你别无选择。此外,当您编写模块时,您可能希望将别名定义与函数定义分开以实现可维护性。
  • @postanote 虽然我很感激你在我的代码中指出一个问题并添加我之前不知道的信息 i:e "[Alias('xx')]",但我认为像 "除非代码导致错误或显着的性能差异,否则不应使用 that's not a thing”。像这样的短语可能会让初学者感到沮丧。我相信“先让它发挥作用,然后再遵循最佳实践”。 P.S:这是一个建议,而不是批评。 :)

标签: powershell terminal windows-10


【解决方案1】:

传递未知参数的最简单、最方便的方法是spatting automatic $args array - 作为@args - 在简单 函数或脚本中(既不使用[CmdletBinding()] 也不使用[Parameter()] 属性):

# Note: @args rather than $args makes the function work with named 
#       arguments for PowerShell commands too - see explanation below.
function runArtisanCommand { php artisan @args } 

# As in your question: Define alias 'art' for the function
# Note: Of course, you could directly name your *function* 'art'.
#       If you do want the function to have a longer name, consider one
#       that adheres to PowerShell's Verb-Noun naming convention, such as
#       'Invoke-ArtisanCommand'.
Set-Alias art runArtisanCommand

顺便说一句:由于目标可执行文件 php 既没有引用也没有基于变量或表达式指定,因此可以将其调用为-是;否则,您将需要 &call operator - 有关背景信息,请参阅 this answer


至于你尝试了什么

问题在于,使用-c 作为传递 参数只有在它前面加上-- 时才有效:

# OK, thanks to '--'
art -- route:list -c

-- 告诉 PowerShell 将所有剩余参数视为 未命名(位置)参数,而不是尝试将 -c 等标记解释为 参数名称

没有---c 被解释为引用您的-command 参数(您声明为$commandValueFromRemainingArguments = $true 的参数),因为PowerShell 允许您指定name prefixes 代替完整的参数名称,只要给定的前缀是明确的。

因为除[switch] 之外的任何类型的参数都需要关联的参数,所以-c(又名-command)失败并出现错误消息。

您可以通过命名参数来避免冲突,使其不会与任何传递参数发生冲突,例如将其命名为-_args(使用参数变量$_args) :

function runArtisanCommand
{
    param(
        # Note: `Mandatory = $false` and `Position = 0` are *implied*.
        [Parameter(ValueFromRemainingArguments)]
        $_args
    )
    php artisan @_args
}

但是,考虑到使用[Parameter()] 属性隐含地使您的函数成为advanced 函数,它也总是接受common parameters,例如-ErrorAction、@987654364 @, -Verbose... - 所有这些都可以通过明确的前缀/短别名传递;例如,-outv 代表 -OutVariable,或别名 -ea 代表 ErrorAction与他们的冲突无法避免

因此,诸如-e 之类的预期传递参数仍然 不起作用:

# FAILS, because -e ambiguously matches common parameters -ErrorAction 
# and -ErrorVariable.
PS> art router:list -e
Parameter cannot be processed because the parameter name 'e' is ambiguous.
Possible matches include: -ErrorAction -ErrorVariable.

同样,-- 是必需的:

# OK, thanks to '--'
art -- router:list -e

总结

  • 特别是对于包装对外部程序的调用的函数,例如php.exe,使用带有@args简单函数,如图所示在顶部,不仅更简单,而且更健壮。

  • 对于包装PowerShell命令的函数(带有显式声明的参数):

    • 带有@args简单 函数也可以工作,
    • 但如果您还希望支持制表符完成显示带有支持参数的syntax diagram,通过传递-?或通过Get-Help,考虑通过 PowerShell SDK 定义(总是高级代理(包装器)函数 - 见下文。

可选背景信息:PowerShell 中的传递参数

正如Mathias R. Jessen 指出的那样,将(未声明的)参数传递给函数或脚本通过传递给另一个命令的最简单方法是使用automatic $args variable ,它是传递给 simple 函数或脚本的所有参数的自动填充数组(不是advanced,通过使用[CmdletBinding()] 和/或[Parameter()] 属性) .

至于为什么应该使用@args而不是$args

  • 在包装函数中按原样使用$args 仅适用于传递位置 参数(那些不以参数名称为前缀的参数,例如*.txt),而不是命名的参数(例如,-Path *.txt)。

  • 如果最终的目标命令是一个外部程序(例如本例中的php.exe),这不是问题,因为PowerShell随后会处理所有 作为位置参数的参数(它无法知道目标程序的语法)。

  • 但是,如果最终调用 PowerShell 命令(带有正式声明的参数),则只有 splatting$args 数组 - 这在语法上意味着我们使用 @args - 支持传递 命名参数通过。[1]

因此,出于习惯,我建议始终在简单的包装函数中使用@args,这同样适用于外部程序。[2]

举一个Get-ChildItem的简单包装函数的例子:

# Simple wrapper function for Get-ChildItem that lists recursively
# and by relative path only.
function dirTree {
  # Use @args to make sure that named arguments are properly passed through.
  Get-ChildItem -Recurse -Name @args 
}

# Invoke it with a *named* argument passed through to Get-ChildItem
# If $args rather than @args were used inside the function, this call would fail.
dirTree -Filter *.txt

使用代理函数进行更复杂的传递处理:

@args 的使用很方便,但代价是支持以下

  • tab-completion,因为 tab-completion 仅适用于正式声明的参数(通常使用 param(...) 块)。

  • 显示带有支持参数的syntax diagram,通过传递-?,或通过Get-Help

为了克服这些限制,最终目标命令的参数声明必须重复在(然后是高级的)包装函数中;虽然这很麻烦,但 PowerShell 可以通过 PowerShell SDK 搭建所谓的代理(包装器)函数来自动化该过程 - 请参阅this answer

注意:

  • 对于-ErrorAction常用 参数,代理函数本身(自动)处理它们,但这对调用者没有影响。

  • 考虑到 PowerShell 不了解外部程序的语法,仅使用 PowerShell 命令 构建代理函数。

    • 但是,您可以手动复制外部目标程序的参数声明。

[1] 请注意,自动 $args 数组有内置的魔法来支持这一点;自定义 array 不支持通过 splatting 传递命名参数,而是需要使用 hash table,如上面链接的关于 splatting 的帮助主题中所述。

[2]其实只有@args还支持--%的正确解释,即stop-parsing symbol

【讨论】:

  • 感谢您提供详细信息。 @Mathias 评论解决了我的问题,但后来我切换到你的解决方案,并没有看到直接的区别,但所有的解释都有帮助。将您的答案标记为已接受,因为无法将 Mathias 评论标记为最佳,而您的答案也将解决问题。再次感谢您。
  • 谢谢,@Jerry555555。包装外部程序时,$args 而不是@args 可以正常工作,除非您需要使用--%。包装 PowerShell 命令时,只有 @args 可以正常工作。因此,答案推荐@args作为最佳整体解决方案。
猜你喜欢
  • 1970-01-01
  • 2021-12-09
  • 2010-11-01
  • 1970-01-01
  • 2014-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多