【问题标题】:Powershell Sort-Object Name with numbers doesn't properly带有数字的 Powershell 排序对象名称不正确
【发布时间】:2014-05-22 23:41:12
【问题描述】:

我正在尝试在文件夹中查找 .sql 文件并根据上次写入时间过滤它们。根据上次写入时间,我得到了 4 个文件作为输出。

TestScript10.sql
TestScript5.sql
TestScript6.sql
TestScript7.sql

现在,当我的命令尝试执行排序对象时,我在顶部看到的是 Testscript10 而不是 TestScript5,我该如何解决这个问题?

我的代码

$File= Get-ChildItem $FileLocation -Filter *.sql | Where-Object {$_.LastWriteTime -gt $datetime} | Sort-Object Name

$File 输出

[DBG]: PS SQLSERVER:\>> $File


    Directory: C:\SQLScripts


Mode                LastWriteTime     Length    Name
----                -------------     ------ ----
-a---         5/22/2014  10:20 AM         61 TestScript10.sql
-a---         5/22/2014  10:16 AM         60 TestScript5.sql
-a---         5/22/2014  10:24 AM         66 TestScript6.sql
-a---         5/22/2014  10:10 AM         24 Testscript7.sql

【问题讨论】:

  • 由于名称是一个字符串,它正在执行字符串比较。由于“1”在“5”之前,因此它们按您所见的顺序排列(它永远不需要检查“0”字符)。如果您希望它们以其他方式排序,则必须检索名称的该部分(将其转换为 int)并按其排序。
  • 您应该像这样命名您的文件:TestScript01.sql、TestScript02.sql 等(或“001”或其他名称,具体取决于有多少。)它们会按名称正确排序.

标签: .net powershell


【解决方案1】:

感谢您对我的问题提出上述所有建议。在简化建议后,下面的代码对我的情况很有效。这有助于我像 Windows 资源管理器一样按自然顺序排序。

$ToNatural= { [regex]::Replace($_, '\d+',{$args[0].Value.Padleft(20)})}
$File= Get-ChildItem $FileLocation -Filter *.sql | Where-Object {$_.LastWriteTime -gt $datetime} | Sort-Object $ToNatural

【讨论】:

    【解决方案2】:

    类似这样的:

    | sort-object {[int]($_.basename -replace '\D')}
    

    【讨论】:

      【解决方案3】:

      嗯……终于弄明白了。

      Windows 资源管理器在对字符串进行排序时使用 shlwapi.dll 中称为 StrCmpLogicalW 的旧 API。

      我不想使用填充零,所以写了一个脚本。

      https://github.com/LarrysGIT/Powershell-Natural-sort

      找到以下 powershell 脚本,它使用相同的 API。您可能需要检查 repo 中的最新代码,因为我不会一直在这里更新。

      function Sort-Naturally
      {
          PARAM(
              [System.Collections.ArrayList]$Array,
              [switch]$Descending
          )
      
          Add-Type -TypeDefinition @'
      using System;
      using System.Collections;
      using System.Collections.Generic;
      using System.Runtime.InteropServices;
      namespace NaturalSort {
          public static class NaturalSort
          {
              [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
              public static extern int StrCmpLogicalW(string psz1, string psz2);
              public static System.Collections.ArrayList Sort(System.Collections.ArrayList foo)
              {
                  foo.Sort(new NaturalStringComparer());
                  return foo;
              }
          }
          public class NaturalStringComparer : IComparer
          {
              public int Compare(object x, object y)
              {
                  return NaturalSort.StrCmpLogicalW(x.ToString(), y.ToString());
              }
          }
      }
      '@
          $Array.Sort((New-Object NaturalSort.NaturalStringComparer))
          if($Descending)
          {
              $Array.Reverse()
          }
          return $Array
      }
      

      在下面找到测试结果。

      PS> # Natural sort
      PS> . .\NaturalSort.ps1
      PS> Sort-Naturally -Array @('2', '1', '11')
      1
      2
      11
      PS> # If regular sort is used
      PS> @('2', '1', '11') | Sort-Object
      1
      11
      2
      

      还有,

      PS> # Not good
      PS> $t = (ls .\Scripts*.txt).name
      PS> $t | Sort-Object
      Scripts1.txt
      Scripts10.txt
      Scripts2.txt
      PS> # Good
      PS> Sort-Naturally -Array $t
      Scripts1.txt
      Scripts2.txt
      Scripts10.txt
      

      【讨论】:

      • 最佳解决方案,因为它不需要任何输入模式知识。
      • 这是一个真正的解决方案。如果您尝试对具有以下文件名的文件进行排序: 1.1 file.txt 1.5 file.txt 1.10 file.txt 其他解决方案在这个解决方案中不起作用。
      【解决方案4】:

      我更喜欢@mjolinor 解决方案,因为它展示了 PowerShell 中的排序功能有多么强大。但是以防万一您想“修复”带有 cmets 中提到的前缀的文件名:

      Get-ChildItem Test*.sql | 
          Rename-Item -NewName { 'TestScript{0:D2}.sql' -f [int]($_.BaseName -replace '\D') }
      

      重命名后,文件将按预期排序。如果您需要超过两位数 - 只需更改格式 ({0:D#})。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-01-04
        • 1970-01-01
        • 2021-07-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-16
        • 2019-07-31
        相关资源
        最近更新 更多