如何转义以下正则表达式,使其在 PowerShell 中可用?

How to escape the following regex, so its usable in PowerShell?

据我所知,在 PowerShell 中没有办法使用变量中指定的参数执行 exe,并将 exe 的 return 指向变量。因此,我目前正在编写一个小函数来实现这一点。但是现在我卡在了用 & 调用时必须单独传递参数的地步。 (这不是所有程序都需要的,但是如果将所有参数作为字符串传递到变量中,某些程序会导致问题)因此我想使用拆分将传递给我的函数的参数写入数组。然后在我的exe调用中传递带有参数的数组。

为此,我有以下正则表达式:

[^\s"']+|"([^"]*)"|'([^']*)'

此正则表达式允许在传递参数时考虑单引号和双引号,并且不拆分其中包含空格的文本。

但遗憾的是,我完全不知道如何最好地转义此正则表达式,以免它在 PowerShell 脚本中造成任何问题。

这里还是我的功能,让它更容易理解: 该函数使用 $Arguments 中的参数执行在 $Path 参数中传递的文件。在执行之前,我尝试用正则表达式拆分 $Arguments 。作为函数的 return,您将获得一个带有 ExitCode 的对象和已执行文件的输出。在这里您可以看到我的尝试,但是引号导致以下代码出现问题。

function Invoke-Process ($Path,$Arguments){
    [PsObject[]] $ReturnValue = @()
    $Params=$Arguments -split([regex]::escape([^\s"']+|"([^"]*)"|'([^']*)'))
    $ExCode = 0
    try {
        $ProcOutput = & $Path $Params | out-string
    }catch{
        $ProcOutput = "Failed: $($_.Exception.Message)"
        $ExCode = 1
    }
    $ReturnValue += [PsObject]@{ ExitCode = $ExCode; Output = $ProcOutput}
    Return $ReturnValue
}

函数调用如下:

$ExePath = "C:\arcconf\arcconf.exe"
$ExeParams = "getconfig 1"
$Output = Invoke-Process $ExePath $ExeParams 

希望你能理解我的问题。我也对其他编写函数的方式持开放态度。

问候

您无需转义 - 该模式完全有效。

您只需要一个不会将引号视为特殊的字符串文字类型。为此,我建议逐字 here-string:

@'
This is a single-line string ' that " can have all sorts of verbatim quotation marks
'@

here-string 的限定符是 @' 作为前一行的最后一个标记,'@ 作为下一行的第一个标记(对于可扩展的 here-string, 使用 @""@).

尝试 运行 使用有效的示例输入:

$pattern = @'
[^\s"']+|"([^"]*)"|'([^']*)'
'@
'getconfig 1 "some string" unescaped stuff 123' |Select-String $pattern -AllMatches |ForEach-Object {$_.Matches.Value}

正如预期的那样,returns:

gesture
1
"some string"
unescaped
stuff
123

作为 here-string 的替代方案,最好的替代方案是常规的逐字字符串文字。你唯一需要转义的字符是',而转义序列只是连续两个'',所以你的源代码变成:

$pattern = '[^\s"'']+|"([^"]*)"|''([^'']*)'''

很好地回答了您的直接问题。

退一步:

there is no way in PowerShell to execute an exe with parameters specified in a variable and direct the return of the exe into a variable

否:PowerShell 支持这两种东西:

  • $output = someExternalProgram ... 捕获变量 $output 中外部程序的 stdout 输出;使用重定向 2>&1 也可以捕获 stderr 输出;使用 >$null2>$null 有选择地丢弃 stdout 或 stderr 输出 - 有关详细信息,请参阅 this answer

  • someExternalProgram $someVariable ... 将变量 $someVariable 的值作为参数传递给外部程序;如果 $someVariable 是值的 array(集合),每个元素 将作为单独的参数传递。除了变量引用,您还可以通过 (...) 使用命令或表达式的输出;例如,someExternalProgram (1 + 2)3 作为参数传递 - 有关详细信息,请参阅

    • 注意:默认情况下,数组的元素作为单独的参数传递只发生在外部程序;对于 PowerShell-native 命令,数组作为一个整体传递 ,作为单个参数 - 除非您明确使用 splatting, in which case you must pass @someVariable rather than $someVariable. For external programs, @someVariable is effectively the same as $someVariable. While array-based splatting also works for PowerShell-native commands, for passing positional arguments only, the typical and more robust and complete approach is to use hashtable-基于 splatting,其中明确标识了目标参数。

    • 无论您是否使用变量或文字值作为参数都适用的一般警告:至少 PowerShell 7.2.x,传递 empty-string 参数或带有嵌入 " 个字符的参数 到外部程序 已损坏 - 请参阅 this answer .

考虑到上述情况,您可以重写您的函数如下,这避免了对 - 最终脆弱 - regex 解析的需要:

function Invoke-Process {
  # Split the arguments into the executable name / path and all
  # remaining arguments.
  $exe, $passThruArgs = $args
  try {
    # Call the executable with the pass-through arguments.
    # and capture its *stdout* output.
    $output = & $exe @passThruArgs
    $exitCode = $LASTEXITCODE      # Save the process' exit code.
  } catch {
    # Note: Only If $exe is empty or isn't a valid executable name or path
    #       does a trappable statement-terminating error occur.
    #       By contrast, if the executable can be called in principle, NO
    #       trappable error occurs if the process exit code is nonzero.
    $exitCode = 127         # Use a special exit code
    $output = $_.ToString() # Use the exception message
  }
  # Construct and output a custom object containing
  # the captured stdout output and the process' exit code.
  [pscustomobject] @{
    ExitCode = $exitCode
    Output = $output
  }
}

调用示例:

Invoke-Process cmd /c 'echo hi!'

# Equivalent, using an array variable for the pass-through arguments.
$argsForCmd = '/c', 'echo hi!'
Invoke-Process cmd @argsForCmd

注:

  • 因为 Invoke-Process 是一个 PowerShell 命令, 为了传递数组,这里需要 splatting (@argsForCmd) 元素作为单独的参数,然后在函数内部反映在 automatic $args variable 变量中。

  • 自动$args变量仅在简单函数中可用,与advanced ones, which behave like cmdlets and therefore automatically support additional features, such as common parameters相反;要制作您的函数和高级函数,请将函数顶部的 $exe, $passThruArgs = $args 行替换为以下内容:

  [CmdletBinding()]
  param(
    [Parameter(Mandatory)]
    [string] $exe,
    [Parameter(ValueFromRemainingArguments)]
    [string[]] $passThruArgs
  )