【问题标题】:Finding unique filename parts in path在路径中查找唯一的文件名部分
【发布时间】:2019-04-18 16:06:45
【问题描述】:

我有一个文件夹,里面有一堆xxxxxx_MMddyyHHmmss.json 格式的文件。我想找到唯一的 xxxxxx 组件,因为有些是在不同时间创建的重复项。

我引用了this 的问题,但作为一个很少涉足 Powershell 的人,我无法让它工作。

$result = Get-ChildItem  C:\Users\<me>\Desktop\FileData\* -recurse -name -include *.json|%{$_.split("_")[0]|sort-object -unique

但我无法让它真正执行。回车时它只是转到下一行。

理想情况下,我可以将其通过管道传输到文件中进行审查。

【问题讨论】:

    标签: shell powershell parsing


    【解决方案1】:

    您的命令中存在语法错误(% (ForEach-Object) 调用的脚本块 ({ ... }) 缺少结束 }),但原则上它应该可以工作。

    一个精简、更快、更易读的版本是这样的:

    Get-ChildItem $HOME\Desktop\FileData -Recurse -Filter *.json | 
      ForEach-Object { ($_.Name -split '_')[0] } |  
        Sort-Object -Unique
    
    • Get-ChildItem $HOME\Desktop\FileData -Recurse -Filter *.json$HOME\Desktop\FileData 的目录子树中的所有*.json 文件返回文件信息对象

    • ForEach-Object { ($_.Name -split '_')[0] } 将每个文件信息输入对象转换为其名称的第一个 _ 分隔标记。

      • 请注意,我已从使用 .NET [string] 类型的 .Split() 方法 ($_.Split("_")[0]) 切换到使用 PowerShell 的 -split 运算符 (($_ -split "_")[0]),因为-split is generally preferable for its flexibility

      • 也就是说,当性能很重要时,.Split() 明显更快

    • Sort-Object -Unique 然后对生成的令牌进行排序并仅返回唯一的令牌(省略重复项)。

    • 使用-Filter *.json 代替-Include *.json 可以加快文件检索速度,因为-Filter 参数效率更高,因为在源头进行过滤。


    优越的替代方案:

    TheMadTechnician 建议使用Group-Object,它允许您保留有关共享给定前缀的各个输入文件的信息:

    Get-ChildItem $HOME\Desktop\FileData -Recurse -Filter *.json |
      Group-Object { ($_.Name -split '_')[0] } |
        Sort-Object Name
    

    注意:如果您不需要对唯一前缀进行排序,您可以省略Sort-Object 调用,在这种情况下它们将按照它们出现的顺序出现文件遍历过程中再次遇到。

    这会导致输出对象包含属性 .Name 中的唯一前缀,以及所有在 Group 属性中具有该前缀的文件,它会打印如下内容:

    Count Name                      Group
    ----- ----                      -----
        2 abcdef                    {/tmp/abcdef_file1, /tmp/abcdef_file1}
    ...
    

    获得唯一的前缀,就像在第一个命令中一样,将整个命令包装在(...).Name中。

    TheMadTechnician 还建议使用稍微快一点的方法(尽管可能更隐蔽)来提取前缀:$_.Name -replace '_.*' 使用 -replace operator 来删除名称中第一个 _ 中的所有内容。
    但是,$_.Split("_")[0] 仍然是总体上最快的解决方案。

    【讨论】:

    • @TheMadTechnician:我更关注性能:虽然-replace '_.*'($_.Name -split '_')[0] 快,但$_.Split("_")[0] 似乎是迄今为止最快的。
    猜你喜欢
    • 2017-03-11
    • 1970-01-01
    • 1970-01-01
    • 2010-09-29
    • 2021-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-02
    相关资源
    最近更新 更多