【问题标题】:Retrieving $_.Extension with double file extensions使用双文件扩展名检索 $_.Extension
【发布时间】:2022-01-19 01:35:41
【问题描述】:

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

只是疏忽? 或者可以缓解吗?

【问题讨论】:

  • 因为不存在双重扩展。否则,My.cool.document.pdfdocument.pdf.pdf.pdffile.zip.tar.gz 的扩展名是什么? ;-) 请注意,即使是单个扩展名也只是文件名的一部分。您可以将file.1.tar.gz 重命名为foo,并且仍然可以解压缩并解压缩它。您的操作系统可能不会自动为您提供该选项。

标签: powershell filenames


【解决方案1】:

这是预期的行为。

这是来自 Microsoft Doc 的引用。关于[System.IO.Path]::GetExtension 方法,它似乎与其他类似功能和Powershell Cmdlet 共享相同的实现逻辑。

此方法通过在路径中搜索路径来获取路径的扩展名 句点 (.),从路径中的最后一个字符开始并继续 朝向第一个字符。如果在 a 之前找到一个句点 DirectorySeparatorChar 或 AltDirectorySeparatorChar 字符, 返回的字符串包含句点及其后面的字符; 否则,返回 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 Method

【讨论】:

    【解决方案2】:

    正如Sage Pourpre's helpful answer 所说,只有last .-separated 标记被视为文件扩展名。

    正如 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
    

    【讨论】:

      猜你喜欢
      • 2011-02-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-08
      相关资源
      最近更新 更多