复制文件名中带有方括号 [ ] 的文件并使用 * 通配符

2024-03-28

我在 Windows 7 上使用 PowerShell,并编写一个脚本将一堆文件从一个文件夹结构复制到另一个文件夹结构。有点像编译。 PowerShellCopy-Itemcmdlet 认为方括号 [ ] 是某种通配符,并且由于某种原因我无法转义它们。

我不能使用-LiteralPath,因为我想使用星号 * 通配符,因为文件名中有一个日期作为文件名的一部分,并且日期会发生变化。日期用作版本号。

这个帖子 https://superuser.com/q/212808很有帮助,但是没有多少刻度(每个括号 2x 或 4x)可以逃脱方括号。

我没有收到错误; PowerShell 的行为就像我输入了错误的文件名一样。

这是我正在研究的具体行:

#to Fusion Server
Copy-item -Path $FSG\$SW\0.RoomView.Notes\starter\"[RoomView] Versions explained*.pdf" -Destination $FSG\$containerFolder\$rootFolder\"Fusion Server"\

这就是整个事情:

# Compiles the Fusion packet for distribution

###############################
###########Variables###########
###############################

#folder structure
$FSG = "F:\FSG"
$containerFolder = "Packet.Fusion for IT and AV Professionals"
$rootFolder      = "Fusion for IT and AV pros $(Get-Date -format “MM-dd-yyyy”)"
$subRoot1        = "Fusion Server"
$subRoot2        = "Scheduling Enhancement and Panels"
$subRoot2sub1    = "Scheduling Panels"
$subRoot3        = "SQL Server"

#source folders
$HW      = "0.Hardware"
$3SMDoc  = "0.Hardware\TPMC-3SM.Documentation"
$4SMDoc  = "0.Hardware\TPMC-4SM.Documentation"
$4SMDDoc = "0.Hardware\TPMC-4SM-FD.Documentation"
$730Doc  = "0.Hardware\TSW-730.Documentation"
$730OLH  = "0.Hardware\TSW-730.OLH"
$CENRVS  = "0.Hardware\CEN-RVS.Notes"

$ProjMgmt = "0.Project Management"

$SW            = "0.Software"
$RVLicensing   = "0.Software\0.RoomView.License"
$RVNotes       = "0.Software\0.RoomView.Notes"
$SQLLicensing  = "0.Software\database.SQL.Licensing"
$SQLNotes      = "0.Software\database.SQL.Notes"
$FRVMarketing  = "0.Software\Fusion RV.Marketing"
$FRVNetworking = "0.Software\Fusion RV.Networking"
$FRVNotes      = "0.Software\Fusion RV.Notes"


###############################
#create the directory structure
###############################

md -Path $FSG\$containerFolder -Name $rootFolder

cd $FSG\$containerFolder\$rootFolder
md "eControl and xPanels"
md "Fusion Server" #$subRoot1
md "Getting Started as a User"
md "Project Management"
md "RoomView Connected Displays"
md "Scheduling Enhancement and Panels" #$subRoot2
md "SQL Server" #$subRoot3

cd $FSG\$containerFolder\$rootFolder\$subRoot1
md "CEN-RVS"
md "Licenseing Information"
md "Networking"
md "Official Documentation"
md "Prerequisites, including powerShell script"
md "Product Info"
md "Requirements"
md "Tech Info"
md "Windows Authentication to Fusion RV"

cd $FSG\$containerFolder\$rootFolder\$subRoot2
md "Outlook Add-in"
md "Scheduling Panels" #$subRoot2sub1

cd $FSG\$containerFolder\$rootFolder\$subRoot2\$subRoot2sub1
md "TPMC-3SM"
md "TPMC-4SM"
md "TPMC-4SM-FD"
md "TSW-730"

cd $FSG\$containerFolder\$rootFolder\$subRoot3
md "Multi-database model only"
md "SQL Licensing"

cd $FSG\$containerFolder
#reset current folder


###############################
#copy the files
###############################

#Copy-Item -Path C:\fso\20110314.log -Destination c:\fsox\mylog.log

#To the root
Copy-item -Path $FSG\$ProjMgmt\starter\"Fusion Support Group Contact info*.pdf" -Destination $FSG\$containerFolder\$rootFolder\
Copy-item -Path $FSG\$containerFolder\"Fusion for IT and AV professionals release notes.txt" -Destination $FSG\$containerFolder\$rootFolder\

#to eControl and xPanels
Copy-item -Path $FSG\$SW\xpanel.Notes\starter\*.* -Destination $FSG\$containerFolder\$rootFolder\"eControl and xPanels"\

#to Fusion Server
Copy-item -Path $FSG\$SW\0.RoomView.Notes\starter\"[RoomView] Versions explained*.pdf" -Destination $FSG\$containerFolder\$rootFolder\"Fusion Server"\

我该怎么做才能转义方括号并仍然使用通配符文件名部分Copy-Item cmdlet?


在这种情况下,您必须使用带单引号的双反引号来转义括号。当您使用双引号字符串时,还可以使用四重反引号。

所以固定的代码行是:

Copy-item -Path $FSG\$SW\0.RoomView.Notes\starter\'``[RoomView``] Versions explained*.pdf' -Destination $FSG\$containerFolder\$rootFolder\'Fusion Server'\

关于文件路径和连线字符等的另一个好资源是阅读这篇文章:从字面上理解事物(例如文件路径) http://technet.microsoft.com/en-us/library/ff730956.aspx


EDIT

Thanks to @mklement0 for highlighting that the true cause of this inconsistency is because of a bug currently in PowerShell https://github.com/PowerShell/PowerShell/issues/79991 https://github.com/PowerShell/PowerShell/issues/7999. This bug causes escaping of wildcard characters, as well as backticks with the default -Path parameter to behave differently than other parameters e.g. the -Include and -Filter parameters.

To expand on @mklement0's excellent answer https://stackoverflow.com/a/57778204/2150063, and comments https://stackoverflow.com/questions/21008180/copy-file-with-square-brackets-in-the-filename-and-use-wildcard/21009701?noredirect=1#comment102143583_21009701, and other answers below:

为了更好地理解为什么我们需要单引号 and 两个回勾 in this情况; (and以突出bug https://github.com/PowerShell/PowerShell/issues/7999和不一致)让我们通过一些示例来演示发生了什么:

Get-Item和关联的 cmdlet (Get-ChildItem, Copy-Item等),处理-Path处理组合时参数不同转义通配符 and 未转义的通配符*同时***!

TLDR:我们需要单引号和双反引号组合的根本原因是底层 PowerShell 提供程序如何解析-Path通配符的参数字符串。它似乎解析了一次转义字符,第二次解析了通配符。

让我们通过一些例子来证明这个奇怪的结果:

首先,让我们创建两个文件来测试调用File[1]a.txt and File[1]b.txt

"MyFile" | Set-Content '.\File`[1`]a.txt'
"MyFriend" | Set-Content '.\File`[1`]b.txt'

我们将尝试不同的方式来获取该文件。我们知道方括号[ ] are 通配符 https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_wildcards?view=powershell-6,所以我们需要用反引号字符 https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_quoting_rules?view=powershell-6#single-and-double-quoted-strings.

我们将尽力获得one明确文件。

让我们从使用单引号文字字符串开始:

PS C:\> Get-Item 'File[1]a.txt'
PS C:\> Get-Item 'File`[1`]a.txt'

    Directory: C:\

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       2019-09-06   5:42 PM              8 File[1]a.txt

PS C:\> Get-Item 'File``[1``]a.txt'

    Directory: C:\

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       2019-09-06   5:42 PM              8 File[1]a.txt

对于单引号字符串,检索文件只需要一个反引号,但两个反引号也可以。

使用双引号字符串我们得到:

PS C:\> Get-Item "File[1]a.txt"
PS C:\> Get-Item "File`[1`]a.txt"
PS C:\> Get-Item "File``[1``]a.txt"

    Directory: C:\  

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       2019-09-06   5:42 PM              8 File[1]a.txt

对于双引号字符串,正如预期的那样,我们可以看到我们需要两个反引号才能使其工作。

现在,我们想要检索both files and使用通配符。

让我们从单引号开始:

PS C:\> Get-Item 'File[1]*.txt'
PS C:\> Get-Item 'File`[1`]*.txt'
PS C:\> Get-Item 'File``[1``]*.txt'

    Directory: C:\

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       2019-09-06   5:42 PM              8 File[1]a.txt
-a----       2019-09-06   5:49 PM             10 File[1]b.txt

使用单引号,当我们有通配符时,我们需要two反引号组。一个用于转义括号,第二个反引号用于转义我们在评估通配符时用于转义括号的反引号。

同样对于双引号:

PS C:\> Get-Item "File[1]*.txt"
PS C:\> Get-Item "File`[1`]*.txt"
PS C:\> Get-Item "File``[1``]*.txt"
PS C:\> Get-Item "File```[1```]*.txt"
PS C:\> Get-Item "File````[1````]*.txt"

    Directory: C:\

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       2019-09-06   5:42 PM              8 File[1]a.txt
-a----       2019-09-06   5:49 PM             10 File[1]b.txt

使用双引号时,使用通配符进行计算会更加冗长。在这种情况下,我们需要four反刻度集。对于双引号,我们需要两个反引号来转义括号,并且在评估星号通配符时还需要另外两个反引号来转义转义字符。


EDIT

As @mklement0 提及 https://stackoverflow.com/a/54108210/2150063,这种行为与-Path参数不一致,并且行为与-Include参数,其中只需要一个反引号即可正确转义括号。这可能会在更高版本的 PowerShell 中“修复”。


1 https://github.com/PowerShell/PowerShell/issues/7999 As of Windows PowerShell v5.1 / PowerShell Core 6.2.0-preview.3

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

复制文件名中带有方括号 [ ] 的文件并使用 * 通配符 的相关文章

随机推荐