【问题标题】:How to escape square brackets in file paths with Invoke-WebRequest's -OutFile parameter如何使用 Invoke-WebRequest 的 -OutFile 参数转义文件路径中的方括号
【发布时间】:2019-04-26 14:22:37
【问题描述】:

当您在文件名中包含类似 [1] 的内容时,如 File[1].txtInvoke-WebRequest-OutFile 参数一起使用时,您会收到错误 Cannot perform operation because the wildcard path File[1].txt did not resolve to a file.

这是由here 记录的行为引起的。

对于其他 cmdlet,您可以使用 -LiteralPath 强制按字面意思执行路径,但在这种情况下,这不是一个选项。

我尝试使用 ` 或 \ 转义 [] 字符,但仍然出现相同的错误。

为了简化测试,您可以使用Out-FileTest-Path 等重现相同的问题。

#Fails
Out-File -FilePath "file[1].txt"
Out-File -FilePath "file`[1`].txt"
Out-File -FilePath "file\[1\].txt"

#Succeeds
Out-File -LiteralPath "file[1].txt"

#Fails
Test-Path -Path "file[1].txt"

#Succeeds
Test-Path -LiteralPath "file[1].txt"

如何对-Path-FilePath-OutFile 等中用于表示通配符的字符进行转义,以便它们像-LiteralPath 指定的字符串一样起作用,因为-LiteralPath 不是可通过Invoke-WebRequest获得?

【问题讨论】:

  • 在文件周围使用单引号并用反引号转义方括号:Test-Path -Path 'file`[1`].txt'

标签: powershell escaping glob


【解决方案1】:
  • 不幸的是,Invoke-WebRequestInvoke-RestMethod 尚不支持
    -LiteralPath,正如您所说,但 linked GitHub issue 表明将来会添加支持。

  • 转义 [] 字符为 `[`] 以便在解释为通配符表达式时字面上处理它们-Path (-FilePath) 不幸的是,由于底部讨论的 错误,目前只有 一半 有效:

    • 执行转义确保-Path 参数接受路径(命令不再中断)...

    • ...但是在文件的 creation 中,错误地将 escaped 表示用作 literal 文件名 - 见底部.

解决方法感谢hashbrown 帮助简化它。

  • Invoke-RestMethod / Invoke-WebRequest 保存到一个临时文件...
  • ...然后重命名(移动)临时文件到所需的输出文件路径。
# Literal output file path.
$outFile = '.\file[1].txt'

# Simulate a call to Invoke-RestMethod / Invoke-WebRequest -OutFile. 
# Save to a *temporary file*, created on demand - such
# a temporary file path can be assumed to never contain '[' or ']'
'hi' |  Out-File -FilePath ($tempFile = New-TemporaryFile)

# Rename (move) the temporary file to the desired target path.
Move-Item -Force -LiteralPath $tempFile -Destination $outFile

在 Windows PowerShell v4- 中,使用 [IO.Path]::GetTempfileName() 代替 New-TemporaryFile


转义 [literal] 路径以用作通配符模式:

使用以下任何一种字符串文字表示,最终会产生具有逐字内容file`[1`].txt的相同字符串,当解释为通配符表达式时,是 转义 相当于文字字符串file[1].txt:

  • 'file`[1`].txt'
  • "file``[1``].txt"
  • file``[1``].txt

要以编程方式创建此转义,请使用:

$literalName = 'file[1].txt'
$escapedName = [WildcardPattern]::Escape($literalName) # -> 'file`[1`].txt'

重要的是目标 cmdlet 将 [] 视为 `-在传递给它们的 -Path (-FilePath) 参数中转义,以便逐字处理。

如果您使用 "..." 引用或 unquoted 参数(其行为通常就像包含在 "..." 中一样),PowerShell 的 string 解析会妨碍: ` 也用作可扩展字符串 ("...") 中的转义字符,因此为了通过 `,您必须将其自身转义,如 ``。 p>

  • 否则,`[ 内的 "..." 会变成 [ - ` 被“吃掉” - 因为 `[ 是从 "..." 的角度转义的 [,并且转义了不需要转义的角色变成了那个角色;简而言之:"file`[1`].txt"file`[1`].txt 都变成了普通的file[1].txt,就好像你从未使用过`

相比之下,` 字符在'...' 引用的字符串中逐字使用,不需要转义。


许多带有-Path 的 cmdlet 的文件创建行为存在缺陷:

上面提到的 bug - 在文件 creation 上,escaped 表示被错误地用作文字文件名 - 影响 大多数 cmdlet,不幸的是:也就是说,它们在创建文件时意外保留转义模式中的`字符,因此通过指定-Path 'file[1].txt',您最终会得到一个字面上名为file`[1`].txt 的文件。

幸运的是,大多数 cmdlet确实支持-LiteralPath,所以无论如何使用-LiteralPath file[1].txt 是更好的选择,并且可以避免这个错误。

一些受影响的 cmdlet:

  • Invoke-WebRequestInvoke-RestMethod

  • Out-File,因此还有重定向运算符>>>,它们在后台有效地调用Out-File

  • 请注意,Set-ContentAdd-Content不会出现此问题。

  • 所有(?)Export-* cmdlet。

  • 其他?

该错误已在GitHub issue #9475 中报告。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-10
    • 2020-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-16
    相关资源
    最近更新 更多