我从PowerShell - Batch change files encoding To UTF-8修改了PowerShell脚本。
# Modified version of https://stackoverflow.com/q/18684793
[Threading.Thread]::CurrentThread.CurrentUICulture = 'en-US'
$Encoding = New-Object System.Text.UTF8Encoding($True) # If UTF8Encoding($False), It will be UTF-8 without BOM
$source = "C:\Users\AKULA\Desktop\SRC" # source directory
$destination = "C:\Users\AKULA\Desktop\DST" # destination directory
if (!(Test-Path $destination)) {
New-Item -Path $destination -ItemType Directory | Out-Null
}
# Delete all previously generated file
Get-ChildItem -Path $destination -Include * -File -Recurse | ForEach-Object {$_.Delete()}
# Recursively convert all files into UTF-8
foreach ($i in Get-ChildItem $source -Force -Recurse -Exclude "desktop.ini") {
if ($i.PSIsContainer) {
continue
}
$name = $i.Fullname.Replace($source, $destination)
$content = Get-Content $i.Fullname
if ($null -ne $content) {
[System.IO.File]::WriteAllLines($name, $content, $Encoding)
} else {
Write-Host "No content from: $i"
}
}
但是使用之后,我发现PS不能很好的处理[
或者]
,我做了一些测试文件,文件名/内容都有差异。
Get-Content : An object at the specified path C:\Users\AKULA\Desktop\SRC\FILENAME[[[[[[]]]]]]]].txt does not exist, or
has been filtered by the -Include or -Exclude parameter.
At C:\Users\AKULA\Desktop\Convert_to_UTF-8.ps1:24 char:16
+ $content = Get-Content $i.Fullname
+ ~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (System.String[]:String[]) [Get-Content], Exception
+ FullyQualifiedErrorId : ItemNotFound,Microsoft.PowerShell.Commands.GetContentCommand
由于我不能嵌入图像的问题,这里是IMGUR相册的链接。
完整图像列表:https://imgur.com/a/aN1RG2L
这些是我测试过的:
- 测试文件有不同的名称。它们的名称包含空格、
'
、[]
。还组成了不同的语言(日语、韩语)。 - 这些文件有相同的内容,编码与UCS-2 BE BOM(UTF-16 BE),以便我可以检查它是否已重新编码为UTF-8。
我怎样才能让我的脚本处理好文件名中的[
或]
?
2条答案
按热度按时间ycl3bljg1#
TL;医生
实际上,使用**
-LiteralPath
参数是最佳解决方案(在PowerShell(Core)v6+中,您可以缩短为-lp
**):-LiteralPath
确保$i.Fullname
被 * 逐字 *(照字面意思)采用;也就是说,由于被解释为wildcard expression,路径中的[
和]
被解释为 * 它们自己 ,而不是具有 * 特殊含义 ,因为它们将具有-Path
参数-注意,如果您仅将 value(字符串)作为第一个参数传递,则-Path
是 * 位置隐含的***,就像你做的那样(Get-Content $i.FullName
)注意:此答案类似地适用于同时具有
-Path
和-LiteralPath
参数,例如Set-Content
、Out-File
和Set-Location
。至于你所尝试的:
实际上等同于:
也就是说,传递给
Get-Content
的(第一个) 位置 * 参数隐式绑定到-Path
参数*。-Path
参数接受wildcard expressions以允许按 * 模式 * 匹配路径;除了支持*
(任意字符串)和?
(正好1个字符)之外,通配符模式中的[...]
表示字符集****或范围(例如,[12]
或[0-9]
)。因此,包含
[...]
(例如foo[10].txt
)的实际路径 * 不 * 被如此识别,因为[10]
被解释为匹配 * 单个 * 字符的字符集,该字符是 *1
或0
;也就是说,foo[10].txt
将匹配foo0.txt
和foo1.txt
,但不是字面上名为foo[10].txt
的文件。当(隐式地)使用
-Path
时,* 有可能 * 转义 *[
和]
示例,这些示例应该被逐字地解释,即通过反勾号(```),但是注意,当涉及引用和/或变量引用时,这可能会变得很棘手。**如果您知道某个路径是文本路径,最好养成使用
-LiteralPath
**的习惯(在PowerShell Core 中,您可以将其缩短为-lp
)。但是,如果您的路径包含 literal
[
和]
,并且您 * 还 * 需要通配符匹配,则必须使用```-转义-请参见this answer。nfzehxib2#
不幸的是,至少在两种情况下,解决方案的好建议并不适用。
选择性错误处理(PS:仅在旧版Windows PowerShell中存在问题)
Get-Content -LiteralPath "nobox[]"
给出错误消息和异常类型,就好像包含通配符一样:而没有括号,我们得到:
因此,要静默处理可选文件,而不是直接抑制每个异常,请执行以下操作:
带支架的路径上的扼流圈。
创建硬链接或符号链接
一个小的和一个大的警告:
Path
参数“与其他cmdlet的LiteralPath参数工作方式类似”,New-Item的文档中对此有明确说明,这似乎是正确的,也是有意义的,尽管我希望我们可以通过编写-LiteralPath
来澄清这一点。Value
参数,链接的目标(在v5中秘密地称为Target
,在以后公开地称为Target
),根据相同的文档不接受通配符,但这是一个谎言。使Powershell发出“无法设置位置,因为路径”*“解析为多个容器。"。
所以你总是需要目标的转义,如果你有一个名为“f[]"的文件,那么这将显示一个错误:
这将创建一个链接:
项目类型“符号链接”也是如此。