检索具有双文件扩展名的 $_.Extension
Retrieving $_.Extension with double file extensions
Powershell 的 .Extension
方法似乎无法识别双重扩展名。
结果,像这样:
Get-ChildItem -Path:. | Rename-Item -NewName {
'{0}{1}' -f ($_.BaseName -replace '\.', '_'), $_.Extension
}
最终将 file.1.tar.gz
重命名为 file_1_tar.gz
,而我想要 file_1.tar.gz
。
只是一个疏忽?
还是可以缓解?
这是预期的行为。
引用自 Microsoft Doc。关于 [System.IO.Path]::GetExtension
方法,它似乎与其他类似功能和 Powershell Cmdlet 共享相同的实现逻辑。
This method obtains the extension of path by searching path for a
period (.), starting with the last character in path and continuing
toward the first character. If a period is found before a
DirectorySeparatorChar or AltDirectorySeparatorChar character, the
returned string contains the period and the characters after it;
otherwise, String.Empty is returned.
您当然可以通过为 tar.gz 和其他双重扩展创建异常来缓解这种情况,方法是使用字典来定义应被视为双重异常的内容。这是一个缓解的例子。
Get-ChildItem -Path 'C:\temp' | % {
$BaseName = $_.BaseName
$Extension = $_.Extension
if ($_.FullName.EndsWith('.tar.gz')) {
$BaseName = $_.BaseName.SubString(0,$_.BaseName.Length -4)
# I used the full name as reference to preserve the case on the filenames
$Extension = $_.FullName.Substring($_.FullName.Length - 7)
}
Rename-Item -Path $_.FullName -NewName (
'{0}{1}' -f ($BaseName -replace '.', '_'), $Extension
)
}
请注意,由于我只有 .tar.gz
,我实际上并没有使用字典,但如果您有多个双扩展类型,最好的方法是通过对每个扩展的循环来应用此方法以查看如果匹配。
以这个为例,它循环遍历一个数组来检查多个双重扩展
# Outside of the main loop to avoid redeclaring each time.
$DoubleExtensionDict = @('.tar.gz', '.abc.def')
Get-ChildItem -Path 'C:\temp' | % {
$BaseName = $_.BaseName
$Extension = $_.Extension
Foreach ($ext in $DoubleExtensionDict) {
if ($_.FullName.EndsWith($ext)) {
$FirstExtLength = ($ext.split('.')[1]).Length
$BaseName = $_.BaseName.SubString(0, $_.BaseName.Length - $FirstExtLength -1)
$Extension = $_.FullName.Substring($_.FullName.Length - 7)
break
}
}
Rename-Item -Path $_.FullName -NewName (
'{0}{1}' -f ($BaseName -replace '.', '_'), $Extension
)
}
参考资料
如 所述,在设计上只有 last .
分隔的标记被认为是文件扩展名。
没有创建已知“多扩展”的哈希表(字典),正如 Sage 所建议的那样 - 这将不得不预料到 所有 - 你可以根据以下规则尝试heuristic(因为你需要排除考虑.1
部分的多重扩展):
- 任何非空 运行 的
.
分隔标记 不以数字 开头,在 结尾 [=31] =] 的文件名,被认为是多扩展名,包括 .
个字符:
@{ Name = 'file.1.tar.gz'},
@{ Name = 'file.1.tar.zip'},
@{ Name = 'file.1.html'},
@{ Name = 'file.1.ps1'},
@{ Name = 'other.1'} |
ForEach-Object {
if ($_.Name -match '(.+?)((?:\.[^\d]+))$') {
$basename = $Matches[1]
$exts = $Matches[2]
} else {
$basename = $_.Name
$exts = ''
}
($basename -replace '\.', '_') + $exts
}
以上结果:
file_1.tar.gz
file_1.tar.zip
file_1.html
file_1.ps1
other_1
Powershell 的 .Extension
方法似乎无法识别双重扩展名。
结果,像这样:
Get-ChildItem -Path:. | Rename-Item -NewName {
'{0}{1}' -f ($_.BaseName -replace '\.', '_'), $_.Extension
}
最终将 file.1.tar.gz
重命名为 file_1_tar.gz
,而我想要 file_1.tar.gz
。
只是一个疏忽? 还是可以缓解?
这是预期的行为。
引用自 Microsoft Doc。关于 [System.IO.Path]::GetExtension
方法,它似乎与其他类似功能和 Powershell Cmdlet 共享相同的实现逻辑。
This method obtains the extension of path by searching path for a period (.), starting with the last character in path and continuing toward the first character. If a period is found before a DirectorySeparatorChar or AltDirectorySeparatorChar character, the returned string contains the period and the characters after it; otherwise, String.Empty is returned.
您当然可以通过为 tar.gz 和其他双重扩展创建异常来缓解这种情况,方法是使用字典来定义应被视为双重异常的内容。这是一个缓解的例子。
Get-ChildItem -Path 'C:\temp' | % {
$BaseName = $_.BaseName
$Extension = $_.Extension
if ($_.FullName.EndsWith('.tar.gz')) {
$BaseName = $_.BaseName.SubString(0,$_.BaseName.Length -4)
# I used the full name as reference to preserve the case on the filenames
$Extension = $_.FullName.Substring($_.FullName.Length - 7)
}
Rename-Item -Path $_.FullName -NewName (
'{0}{1}' -f ($BaseName -replace '.', '_'), $Extension
)
}
请注意,由于我只有 .tar.gz
,我实际上并没有使用字典,但如果您有多个双扩展类型,最好的方法是通过对每个扩展的循环来应用此方法以查看如果匹配。
以这个为例,它循环遍历一个数组来检查多个双重扩展
# Outside of the main loop to avoid redeclaring each time.
$DoubleExtensionDict = @('.tar.gz', '.abc.def')
Get-ChildItem -Path 'C:\temp' | % {
$BaseName = $_.BaseName
$Extension = $_.Extension
Foreach ($ext in $DoubleExtensionDict) {
if ($_.FullName.EndsWith($ext)) {
$FirstExtLength = ($ext.split('.')[1]).Length
$BaseName = $_.BaseName.SubString(0, $_.BaseName.Length - $FirstExtLength -1)
$Extension = $_.FullName.Substring($_.FullName.Length - 7)
break
}
}
Rename-Item -Path $_.FullName -NewName (
'{0}{1}' -f ($BaseName -replace '.', '_'), $Extension
)
}
参考资料
如 .
分隔的标记被认为是文件扩展名。
没有创建已知“多扩展”的哈希表(字典),正如 Sage 所建议的那样 - 这将不得不预料到 所有 - 你可以根据以下规则尝试heuristic(因为你需要排除考虑.1
部分的多重扩展):
- 任何非空 运行 的
.
分隔标记 不以数字 开头,在 结尾 [=31] =] 的文件名,被认为是多扩展名,包括.
个字符:
@{ Name = 'file.1.tar.gz'},
@{ Name = 'file.1.tar.zip'},
@{ Name = 'file.1.html'},
@{ Name = 'file.1.ps1'},
@{ Name = 'other.1'} |
ForEach-Object {
if ($_.Name -match '(.+?)((?:\.[^\d]+))$') {
$basename = $Matches[1]
$exts = $Matches[2]
} else {
$basename = $_.Name
$exts = ''
}
($basename -replace '\.', '_') + $exts
}
以上结果:
file_1.tar.gz
file_1.tar.zip
file_1.html
file_1.ps1
other_1