【问题标题】:Powershell errors when the first word of my command is a variable that gets expanded当我的命令的第一个单词是扩展的变量时,Powershell 错误
【发布时间】:2019-03-08 15:12:21
【问题描述】:

我想测试一个我正在编写的 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.

我做错了什么?有更好的方法吗?我想要一个基于布尔值执行命令或简单打印命令的构造(以便我可以看到 将执行什么)。

【问题讨论】:

  • 不要尝试在 $Var 中运行 cmdlet,而只需使用 if 结构来测试触发器 $Var 的值。
  • 试试 'cmd /c echo'。
  • 您实际上想要完成什么?在 powershell 中可能有比依赖深奥的语法/行为更好的方法。
  • 看起来您缺少调用运算符 (&)
  • 我不想只使用 if ,因为我不想不运行它,我还希望回显 would 已经运行的内容。这也是为什么 $DO_OR_ECHO 和 my_dangerous_command 不会做我想做的事情的原因。

标签: powershell


【解决方案1】:

使用函数

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,其中还指出了一般警告,即 空字符串 不能按原样作为参数传递,无论是直接传递还是作为用于 splatting 的数组的一部分传递。李>
  • 与您的 Bash 解决方案一样,回显命令将反映扩展参数的原始和/或必要引用,因此可能会丢失参数边界。


为了演示它(在 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 会显示如下内容:
      What if: Performing operation "Remove File" on Target "C:\tmp\foo.txt".
  • 1234563到$true - 但这样做会影响所有 cmdlet 和在设置变量时支持-WhatIf 的函数;另外,-WhatIf 的输出很罗嗦,如上图。

可以说,PowerShell 的通用命令调用 cmdlet Invoke-Command 应该支持 -WhatIf,就像上面的函数一样,但它不支持。

【讨论】:

  • 为什么不使用 cmdletbinding 和支持 -whatif 在 powershell 中以更合适的方式执行此操作?这就是它存在的原因。
  • @KoryGill:值得一提的是-WhatIf,但它不是适合这项工作的工具 - 请参阅我的更新。
  • 散布论点不是更好的方法吗? 大概它处理适当地引用它们等,即& $cmd @cmdArgs
  • 良好的反馈,但不了解整体问题很难知道整体最佳设计。
  • @TheIncorrigible1:你说得对,这是更好的选择(答案已更新),尽管它确实只对--% 产生影响,而不是引用 - 请参阅底部我刚刚添加到答案中的部分。
猜你喜欢
  • 1970-01-01
  • 2018-08-22
  • 1970-01-01
  • 2021-08-12
  • 1970-01-01
  • 2014-01-28
  • 2013-09-29
  • 1970-01-01
  • 2020-12-03
相关资源
最近更新 更多