我想测试我正在编写的一个 powershell 脚本,其中包含一个我不想实际发生的带有副作用的命令。
在 bash 中,我可以写
> DO_OR_ECHO=$([ "$MY_DEBUG_FLAG" ] && echo 'echo' || echo)
> $DO_OR_ECHO my_dangerous_command args
但尝试在 powershell 中执行类似的构造似乎不起作用,即使我对其进行了硬编码也是如此。
> $DO_OR_ECHO='echo'
> $DO_OR_ECHO my_dangerous_command args
Unexpected token 'my_dangerous_command' in expression or statement.
我做错了什么?有更好的方法吗?我想要一个基于 bool 值的构造,它要么执行命令,要么简单地打印它(以便我可以看到会被执行的内容)。
最佳答案
使用函数:
function doOrEcho() {
$cmdLine = $Args
if ($MY_DEBUG_FLAG) { # echo
"$cmdLine"
} else { # execute
# Split into command (excecutable) and arguments
$cmd, $cmdArgs = $cmdLine
if ($cmdArgs) {
& $cmd $cmdArgs
} else {
& $cmd
}
}
}
然后按如下方式调用它:
doOrEcho my_dangerous_command args
限制:
仅适用于调用外部程序,不适用于 PowerShell cmdlet 或函数。
- 将数组 (
$cmdArgs
) 的元素作为单个 参数传递给外部程序是一项名为 splatting 的 PowerShell 技术。 ;见this answer了解更多信息,其中还指出了一般警告,即空字符串不能按原样作为参数传递,无论是直接传递还是作为用于展开的数组的一部分传递。
- 将数组 (
在您的 Bash 解决方案中,回显命令不会反射(reflect)扩展参数的原始和/或必要引用,所以参数边界可能会丢失。
为了演示它(在 PowerShell Core 中调用 ls
Unix 实用程序):
# Default behavior: *execute* the command.
PS> doOrEcho ls -1 $HOME
# ... listing of files in $HOME folder, 1 item per line.
# With debug flag set: only *echo* the command, with arguments *expanded*
PS> $MY_DEBUG_FLAG = $true; doOrEcho ls -1 $HOME
ls -1 /home/jdoe # e.g.
Kory Gill指出 PowerShell 有 -WhatIf
common parameter其目的是在不实际执行操作的情况下预览操作。
但是,-WhatIf
不是手头任务的正确解决方案:
只有 cmdlet 和高级函数可以实现此参数(基于 PowerShell 提供的功能)- 这样做比上面的简单函数需要更多的努力。
-WhatIf
背后的意图是显示命令将对哪些数据 进行操作/它将对系统,而上述函数背后的意图是回显命令本身。- 例如,
Remove-Item foo.txt -WhatIf
会显示如下内容:
假设:在目标“C:\tmp\foo.txt”上执行“删除文件”操作。
- 例如,
虽然在这个用例中您在技术上仍然可以使用
-WhatIf
,但是您必须临时使用-WhatIf
来打开回显 (doOrEcho -WhatIf ...
) 或将$WhatIfPreference
首选项变量设置为$true
- 但这样做会影响所有 在设置变量时支持-WhatIf
的 cmdlet 和函数;此外,-WhatIf
输出是冗长的,如上所示。
可以说,PowerShell 的通用命令调用 cmdlet Invoke-Command
应该像上面的函数一样支持 -WhatIf
,但它不支持。
关于当我的命令的第一个词是一个被扩展的变量时 Powershell 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55066054/