当我的命令的第一个单词是被扩展的变量时,Powershell错误

时间:2019-03-08 15:12:21

标签: powershell

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

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

1 个答案:

答案 0 :(得分:2)

使用函数

function doOrEcho() { 
  $cmdLine = $Args
  if ($MY_DEBUG_FLAG) { # echo
    "$cmdLine"
  } else {                # execute
    # Split into command (excecutable) and arguments
    $cmd, [string[]] $cmdArgs = $cmdLine
    if ($cmdArgs) {
      & $cmd @cmdArgs
    } else {
      & $cmd 
    }
  }                  
}

然后按如下所示调用它:

doOrEcho my_dangerous_command args

限制

  • 仅适用于对外部程序 的调用,不适用于PowerShell cmdlet或函数。

    • 有关将空字符串作为参数重新传递的警告,以及如何使用散点图来传递参数,请参见底部。
  • 与您的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的目的是显示命令将对哪些 data 进行操作/它将对系统进行哪些更改。上面功能的目的是回显命令本身

    • 例如,Remove-Item foo.txt -WhatIf将显示以下内容:
      What if: Performing operation "Remove File" on Target "C:\tmp\foo.txt".
  • 尽管从技术上讲,您仍然可以使用-WhatIf,但是您要么必须使用-WhatIf即席打开回显(doOrEcho -WhatIf ...)要么进行设置$WhatIfPreference的{​​{1}}首选项变量-但这样做会影响 all 所有cmdlet和在设置变量时支持$true的函数;另外,-WhatIf的输出比较罗word,如上所示。

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


可选阅读:散列/基于数组的参数传递给外部程序:

Splatting是一种技术,它允许您通过存储在变量中的哈希表或数组将参数传递给命令,然后用-WhatIf而不是@进行引用一个论点。

对于外部程序,只有 array 技术才有意义,并且-除了一个例外-您甚至可以按原样传递数组 -{以{1}}代替$-达到相同的效果。

该异常是特殊的停止解析符号 $argumentArray,它告诉PowerShell不要像往常一样解析其余的参数,而是按原样传递它们-未扩展,除了扩展@argumentArray样式的变量引用(例如%USERNAME%。

)。

只有喷溅语法(--%)才能识别cmd.exe符号。

但是,使用语法-@argumentArray--%-空字符串的参数(例如$argumentArray或{{1 }})不能正确传递 ,因为PowerShell会简单地删除,这会破坏命令。 但是,这种情况也会随着传递 direct 参数而发生,并且是Windows PowerShell v5.1 / PowerShell Core 6.2.0及更高版本中PowerShell的固有限制(请参见this GitHub issue)。

例如,以下命令从@argumentArray开始工作,但是由于参数为空而无法从PowerShell中断:

''