正在检索具有双重文件扩展名的$_.Extension



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

只是疏忽?还是可以减轻?

这是预期的行为。

这是微软文档的一句话。关于[System.IO.Path]::GetExtension方法,它似乎与其他类似的函数和Powershell Cmdlet共享相同的实现逻辑。

此方法通过在路径中搜索句点(.(,从路径中的最后一个字符开始并继续朝向第一个字符。如果在DirectorySeparatorChar或AltDirectorySepartmentChar字符返回的字符串包含句点及其后面的字符;否则返回String.Empty。

您当然可以通过为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
)
}

参考

Path.GetExtension方法

正如Sage Pourre有用的回答所指出的,在设计中,只有最后一个.分隔的令牌被视为文件扩展名。

除了创建已知";"多扩展";,正如Sage提出的那样-必须预测所有-您可以根据以下规则尝试启发式(因为您需要排除将.1作为多重扩展的一部分(:

  • 在文件名的结尾,任何不以数字开头的.分隔标记的非空运行都被视为多扩展名,包括.字符:
@{ 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

最新更新