首页 > 解决方案 > 如何创建运行命令的函数?

问题描述

所以我想做的是重新创建一个与我在 Bash 中使用的类似的函数,但在 Powershell 中:

yell() { echo "$0: $*" >&2; }
die() { yell "$*"; exit 111; }
try() { "$@" || die "FAILED: $*"; }

我目前最感兴趣的部分是这里的 try() 函数。本质上它的作用是允许我用这个函数包装一个命令并让它管理退出代码。效果是这样的:

try doSomething -args

如果doSomething以非零值退出,它会将命令输出到 stderr 并停止脚本执行。

我意识到 Powershell 有一个可用于中止脚本的错误操作,但它似乎只适用于命令行开关。我需要一些可以在整个脚本中使用的东西。我还希望避免大量冗长的 try/catch 逻辑使脚本变得混乱,因此需要像 try/yell/die 这样优雅的东西。这样,我可以单独在这个函数中编写处理,并使用它来调用我想要处理的任何内容。

我发现$MyInvocation并认为这可能是进入的方式,但我似乎无法找到从函数中实际执行它的方法。例如:

function run() {
    $MyInvocation # ?? what do??
}

run doSomething -args

我想我可以自己弄清楚其余的,我只是不太清楚如何编写这个包装函数。有任何想法吗?

更新

所以我做了一些俗气的事情,我对命令进行了子串化,并对Invoke-Expression剩下的内容做了一个,它似乎有效。感觉超级hacky,所以我仍然对想法持开放态度:

function attempt() {
    $thisCommand = $MyInvocation.Line.Trim()
    Write-Output $thisCommand
    Invoke-Expression $thisCommand.Substring(8)
    if($LASTEXITCODE -ne 0) { 
        throw "Command failed $thisCommand" 
        exit 111
    }
}

attempt doSomething -args

标签: linuxpowershell-corepowershell-v6.0

解决方案


如果您希望函数运行任意命令并在该命令失败时抛出错误,您可以执行以下操作:

function Test-Command {
    try {
        $cmd, $params = $args
        $params = @($params)
        $global:LastExitCode = 0
        $output = & $cmd @params 2>&1
        if ($global:LastExitCode -ne 0) {
            throw $output
        }
        $output
    } catch {
        throw $_
    }
}

分解:

$cmd, $params = $args获取自动变量 $args(传递给函数的参数数组)并将其第一个元素分配给变量$cmd,其余元素分配给变量$params

$params = @($params)确保$params包含一个数组(下一步需要),即使变量为空或仅包含一个值。

& $cmd @params使用call 操作符 调用命令,&同时喷出参数。不要使用Invoke-Expression. _

重定向运算符2>&1错误输出与正常输出合并,以便在变量 中捕获两个输出流$output

如果$cmdPowerShell cmdlet错误将引发异常,该异常会被try语句捕获。try然后将跳过块中的其余代码。但是请注意,并非所有由 PowerShell cmdlet 引发的错误都会自动终止错误(例如,请参阅脚本专家博客上的“PowerShell 中的错误处理简介” )。要将非终止错误转换为终止错误,您需要设置$ErrorActionPreference = 'Stop'(并在完成后将其重置为其原始值)。

如果$cmd外部命令错误不会抛出异常,但自动变量$LastExitCode会更新为命令的退出代码。返回非零退出代码的命令将触发if条件并导致引发自定义异常,使用命令输出作为异常消息。然后该异常也被该try语句捕获。块中的其余代码try再次被跳过。

$global:LastExitCode = 0$LastExitCode在每次运行之前重置变量。这是必要的,因为只有外部命令会返回退出代码,而 PowerShell cmdlet 不会。由于$LastExitCode保留了当前会话中最后一次运行的外部命令的退出代码,因此不重置变量会影响在外部命令之后运行的 PowerShell cmdlet 的状态检测。

try仅当命令既不引发异常也不返回非零退出代码时,才会到达块中的最后一行,它回显捕获的命令输出。

任何捕获的异常都在catch块中处理,它只是将异常传递给函数的调用者。当然,您也可以输出错误并退出,而不是抛出。


推荐阅读