多个命令 (&&) Windows vs Linux
问题:Windows和Linux中多个命令(&&)的差异是如何产生的?有什么解决方法?
多年后,我来总结一下“Windows PowerShell”的行为,其最新且最终版本为v5.1:
- Bash的/cmd的&&和||控制运算符在PowerShell中没有等效的操作符,而且由于无法在PowerShell中定义自定义操作符,所以没有很好的解决方法。
- 可以使用单独的命令(在不同行或使用分号分隔)并通过自动变量$?来显式测试每个命令的成功状态。
- 对于外部程序,可以使用自动变量$LASTEXITCODE来代替,这是更好的选择,因为Windows PowerShell中的$?可能会产生错误的负面影响。
- PowerShell(Core)7+中已经实现了类似于Bash的&&和||操作符。
- PowerShell的-and和-or不能完全替代&&和||,因为它们只对命令的标准输出进行操作,并仅输出操作的布尔结果。
Windows PowerShell没有等效于Bash中的&&和||的操作符,但可以通过其他方法实现相似的功能。
解决方法:
- 对于多个命令的情况,可以使用分号分隔每个命令,并使用$?变量测试每个命令的成功状态。
- 对于外部程序,可以使用$LASTEXITCODE变量来代替$?变量,以避免可能出现的错误。
- PowerShell(Core)7+中已经实现了类似于Bash的&&和||操作符,可以直接使用这些操作符来实现多个命令的控制。
虽然PowerShell中的-and和-or操作符不能完全替代Bash中的&&和||,但可以通过以上方法解决多个命令的控制问题。
在Windows和Linux中,有时需要执行多个命令,并根据命令的执行结果来决定后续的操作。在Windows中,可以使用&&(与)和||(或)操作符来实现这一功能。然而,在Linux中,这些操作符的行为与Windows中不同,因此可能会导致问题。
问题的出现是因为在Windows中,命令的成功与失败是根据其输出来判断的。如果命令的输出为空或输出为假值(如0),则被视为命令失败;反之,如果命令的输出为真值,则被视为命令成功。而在Linux中,命令的成功与失败是根据命令的返回值来判断的。返回值为0表示命令成功,非0表示命令失败。
解决这个问题的方法是,在Windows中使用条件语句来判断命令的执行结果。可以将命令的执行结果赋值给一个变量,并通过条件语句来判断变量的值是否为真。根据变量的值来决定后续的操作。
以下是一个示例代码,演示了如何在Windows中模拟&&操作符的功能:
$a = '' $b = '' $c = 'hi' [void]( ($result = $a) -or ($result = $b) -or ($result = $c)) $result
输出结果为:
hi
在这个示例中,如果$a或$b为null,则将$c赋值给$result。通过使用条件语句和赋值表达式,可以实现类似于&&操作符的效果。
然而,需要注意的是,这种方法只能判断命令是否执行成功,而无法判断命令的输出是否为真值。如果一个命令执行成功但没有输出或输出为假值(如0),这种方法也会将其视为命令失败。
因此,为了准确地判断命令的执行结果,仍然建议在Windows中使用&&和||操作符来执行多个命令,并根据命令的返回值来决定后续的操作。在Linux中,则可以继续使用&&和||操作符,因为其行为与Windows中一致。
在Windows和Linux中,执行多个命令时,逻辑操作符的行为有所不同。在Bash(Linux)中,逻辑操作符将命令的整数退出码解释为true或false。而在PowerShell(Windows)中,逻辑操作符不会进行这样的解释。然而,可以通过创建一个函数来模拟Bash的行为。
以下是一个在PowerShell中创建相同行为的函数示例:
function Get-ExitBoolean($cmd) { & $cmd | Out-Null; $? }
其中,`$?`是一个布尔值,用于表示最后一个命令的执行结果。
接下来,我们可以使用两个批处理文件进行测试:
# pass.cmd exit
# fail.cmd exit /b 200
测试结果如下:
if (Get-ExitBoolean .\pass.cmd) { write pass } else { write fail } # 输出:pass if (Get-ExitBoolean .\fail.cmd) { write pass } else { write fail } # 输出:fail
为了在PowerShell中实现与Bash相同的逻辑操作符行为,可以先设置一个别名:
Set-Alias geb Get-ExitBoolean
然后进行测试:
(geb .\pass.cmd) -and (geb .\fail.cmd) # 输出:False (geb .\fail.cmd) -and (geb .\pass.cmd) # 输出:False (geb .\pass.cmd) -and (geb .\pass.cmd) # 输出:True (geb .\pass.cmd) -or (geb .\fail.cmd) # 输出:True
所以,PowerShell中没有内置的简单功能可以实现与Bash相同的行为。但是,PowerShell非常强大,可以通过自定义函数来实现类似的功能。
需要注意的是,`Get-ExitCodeBoolean()`函数不是`&&`或`||`的通用替代品,因为它会抑制正常输出,无法将其捕获到变量、文件或通过管道传递。Bash的`&&`和`||`控制操作符的美妙之处在于它们不会干扰输出流,只会对(不可见的)退出码进行操作,而这在PowerShell中(目前)无法实现。如果认为应该实现这样的功能,可以在此处投票:https://windowsserver.uservoice.com/forums/301869-powershell/suggestions/11087898-implement-the-and-operators-that-bash-has。
最后,需要澄清的是,Bash并不会将命令的退出码隐式转换为布尔值,因为Bash只知道字符串和32位整数。正确的表述应该是Bash在进行逻辑操作时,将整数退出码解释为true或false。
以上是关于在Windows和Linux中,执行多个命令时逻辑操作符行为差异的原因和解决方法的整理。