如何解析文件名以确定多个文件夹中的每个文件夹中的最新文件

时间:2014-09-02 19:22:11

标签: powershell

我有从各种Linux服务器写入中央Windows NAS服务器的日志。它们以E:\ log格式:

E:\日志\过程1 \ log20140901.txt,

E:\日志\过程2 \ 20140901.txt,

E:\ LOG \ process3 \登录过程20140901.txt,

同时每周复制多个文件,因此创建日期不是确定最新文件的好方法。因此我编写了一个powershell函数来解析日期,我正在尝试迭代并获取每个文件夹中的最新文件,使用我的函数输出作为“日期”。我肯定做错了什么。

这是我到目前为止写的Powershell:

Function ReturnDate ($file)
{
    $f = $file
    $f = [RegEx]::Matches($f,"(\d{8})") | Select-Object -ExpandProperty Value
    $sqlDate = $f.Substring(0,4) + "-" + $f.substring(4,2) + "-" + $f.substring(6,2)
    return $sqlDate
}

Get-ChildItem E:\log\* |
 Where {$_.PsIsContainer} |
  foreach-object { Get-ChildItem $_ -Recurse |
   Where {!$_.PsIsContainer} |
    ForEach-Object { ReturnDate $_}|
     Sort-Object ReturnDate -Descending |
      Select-Object -First 1 | Select Name,ReturnDate
       }

我似乎混淆了属性并导致“你无法在空值表达式错误上调用方法”,但我不确定该怎么做。

3 个答案:

答案 0 :(得分:2)

我怀疑你的$f变量为null,并且你试图在空值上调用一个方法(Substring)。试试这个:

Get-ChildItem E:\Log -File -Recurse | Where Name -Match '(\d{8})\.' | 
    Foreach {Add-Member -Inp $_ NoteProperty ReturnDate ($matches[1]) -PassThru} | 
    Group DirectoryName | 
    Foreach {$_.Group | Sort ReturnDate -Desc | Select -First 1}

这需要V3或更高版本。如果你在V1或V2上改为:

Get-ChildItem E:\Log -Recurse | 
    Where {!$_.PSIsContainer -and $_.Name -Match '(\d{8})\.'} | 
    Foreach {Add-Member -Inp $_ NoteProperty ReturnDate ($matches[1]) -PassThru} |
    Group DirectoryName | 
    Foreach {$_.Group | Sort ReturnDate -Desc | Select -First 1}

答案 1 :(得分:1)

当我尝试它时,你的代码对我来说没问题,直到你做了select你要求的名字并且当这些属性不存在时返回。使用这些值创建自定义对象将使您的代码工作。我也从你的管道中删除了一些逻辑。最终结果应该仍然有用(我只是制作了一些虚拟文件来测试,就像你的例子一样)。

使用原始代码,您可以拥有类似的内容。这只适用于v3或更高版本。如果需要,简单的更改可以使其工作更低。大多数情况下[pscustomobject]

Function ReturnDate ($file)
{

    $f = $file
    $f = [RegEx]::Matches($f,"(\d{8})") | Select-Object -ExpandProperty Value
    $sqlDate = $f.Substring(0,4) + "-" + $f.substring(4,2) + "-" + $f.substring(6,2)
    [pscustomobject] @{
        'Name' = $file.FullName
        'ReturnDate' = $sqlDate
    }
}

Get-ChildItem C:\temp\E\* -Recurse |
   Where-Object {!$_PSIsContainer} | 
   ForEach-Object{ReturnDate $_} |
   Sort-Object ReturnDate -Descending |
   Select-Object -First 1

答案 2 :(得分:1)

Sort-Object cmdlet支持按自定义脚本块排序,并按脚本块返回的任何内容进行排序。因此,使用正则表达式来获取时间戳并将其返回。

Get-ChildItem E:\log\* -Directory |
    ForEach-Object { 
        Get-ChildItem $_ -Recurse -File |
        Sort-Object -Property {
            if( $_.Name -match '(\d{8})' )
            {
                return $Matches[1]
            }
            Write-Error ('File ''{0}'' doesn't contain a timestamp in its name.' -f $_.FullName)
        } | 
        Select-Object -Last 1 | 
        Select Name,ReturnDate
    }

请注意,Select-Object -First 1已更改为Select-Object -Last 1,因为日期将从最旧到最新排序。