0

我想编写一个 PowerShell 脚本来选择 JFrog 服务连接,但该脚本的行为方式与我期望的不同。

当我jfrog config use手动运行命令时,它按预期工作:

PS C:\Users\rdepew> jfrog config use Dummy
[Info] Using server ID 'Dummy' (https://foo.jfrog.io/).
PS C:\Users\rdepew> $?
True

我希望能够使用始终返回 true 或 false 的 $? 来检测是否jfrog config use已成功执行。这个片段说明了我遇到的问题:

PS C:\Users\rdepew> if (jfrog config use Dummy) {
>>   Write-Host Dummy exists
>> } else {
>>   Write-Host Dummy doesnt exist but I dont believe it
>> }
[Info] Using server ID 'Dummy' (https://foo.jfrog.io/).
Dummy doesnt exist but I dont believe it

[Info] 行表明 JFrog 实际上正在使用服务器连接“Dummy”。我假设 $? 退出代码评估为真,就像在我的手动执行中一样。但我的 if/else 测试采用“if false”分支。为什么?

更多信息:如果我使用不存在的服务连接的名称,我会得到预期的行为:

PS C:\Users\rdepew> if (jfrog config use Bogus) {
>>   Write-Host Bogus exists
>> } else {
>>   Write-Host Bogus doesnt exist
>> }
[Error] Could not find a server with ID 'Bogus'.
Bogus doesnt exist

我不明白为什么 PSelse在 True 和 False 情况下都跳到该子句。

还有更多信息

感谢第一个答案和评论,我了解更多。我可以像这样重写我的代码段:

jfrog config add Dummy
if ($LASTEXITCODE=0) {
  etc.

但是我仍然对$感到困惑?行为。从命令行,$? 行为如下:

PS C:\Users\rdepew> jfrog config use Dummy
[Info] Using server ID 'Dummy' (https://foo.jfrog.io/).
PS C:\Users\rdepew> $?
True
PS C:\Users\rdepew> jfrog config use Bogus
[Error] Could not find a server with ID 'Bogus'.
PS C:\Users\rdepew> $?
False

...这是人们所期望的。

4

1 回答 1

2

在 PowerShell 中,如果先前的cmdlet完成且没有错误或出现任何错误,则$?返回。对于外部命令,它会返回.$true$false$LASTEXITCODE -eq 0

但是,当您将命令(外部或其他)作为条件放在if语句中时,它不会检查命令是否成功,而是检查结果的真实性。如果命令返回正确的$true$false布尔值,这很简单,否则,它将成功流上的输出转换为布尔值。除以下输出之外的任何输出的计算结果为$trueand, $null, 0, 空字符串和空数组的计算结果为$false

我不确定的是为什么这两个命令$true至少在作为if条件运行时都没有产生输出。编写代码的另一种方法是在jfrog外部运行if并检查结果$LASTEXITCODE

$output = jfrog config use Dummy

if ( $LASTEXITCODE -eq 0 ) {
  Write-Host "Dummy exists"
} else {
  Write-Host "Dummy doesnt exist but I dont believe it"
}

如果可以接受其他退出代码,请使用这个奇怪的技巧来检查多个值,而不必将多个 eval 链接$LASTEXITCODE在一起:

# I use this often when checking the result of MSIEXEC
if ( $LASTEXITCODE -in @(0, 3010) ) {
....
}

基本上,这只是说检查.$LASTEXITCODE右侧的数组中是否存在-in。您可以使用-notin来否定评估。运算符也是一种选择,-contains/-notcontains您只需要将操作数从-in/-notin.


经过一些额外的测试,并从几年前的工作中模糊地回忆起这个问题,我相信jfrog正在将所有内容都写到 STDERR 这将解释你的行为(你可以测试$var = jfrog blah blah blah并查看是否$var包含输出或者它是否仍然被写入控制台) .

如果您想缓解这种情况,例如,如果您想捕获输出,请将错误流(基本上是 STDERR)重定向到成功流(基本上是 STDOUT):

$output = jfrog blah blah blah 2>&1

但是,我仍然会依靠检查$LASTEXITCODE来检查失败,而不是输出或$?. 检查输出会导致此问题中出现类似问题,并且检查$?要求您注意将来对代码的更新,因为您可以很容易地在执行和结果评估之间滑动另一个命令。

我在这里对不同的输出流和重定向有一个全面的答案,你可能会觉得这很有用。

于 2021-09-13T18:40:25.807 回答