仅列出Windows中每个月的最新文件

时间:2017-02-02 10:49:21

标签: windows powershell batch-file sas

我正在尝试找到解析数百个XLS文件的方法;这些包含月度报告并存储在子目录中。在某些情况下,由于初始XLS文件中的错误后来纠正了一个月的几个报告。我在Windows环境中工作。 我需要在SAS中导入这些文件来进行分析;我不能使用除SAS和基本Windows shell之外的任何其他工具(也许是powershell)。

文件名包含有关其生成日期的信息,因此我只能从名称中识别重新运行。目录内容的示例如下:

rep1_02012016.xls
rep1_02112016.xls #this would be a rerun on feb 11 if feb 1's report contains an error
rep1_03012016.xls
rep1_04012016.xls

我的想法是将shell命令的输出传递给SAS,以便我知道要读取哪些文件。我无法找到一种方法来获取每个月的单个文件,每月过滤掉除最新文件之外的所有文件。所以我会在2月份获得一个,一个用于Mar,一个用于4月,依此类推。 任何指针都是受欢迎的。

5 个答案:

答案 0 :(得分:2)

像(未经测试)的东西:

data with_dates;
   set all_files;
   * Assume the date always starts at position 6 and is 8 chars long;
   date = input(substr(filename, 6, 8), mmddyy8.);
   * Get the month and year from the date;
   month = month(date);
   year = year(date);
run;

* Sort into monthly groups with the records in date otder within each group;
proc sort data=with_dates out=with_dates_sorted;
   by year month date;
run;

* Keep only the last file from each monthly group;
data last_per_month_only;
   set with_dates_sorted;
   by year month;
   if last.month;
run;

这应该非常接近,但请注意它会对文件名的格式做出许多假设 - 例如,您可能希望在下划线上拆分文件名。

答案 1 :(得分:2)

您可以使用powershell执行此操作,这假设您的报告统一命名为文件名用于确定子字符串的日期:

$files = Get-ChildItem .\path\to\dir
$months = @("01","02","03","04","05","06","07","08","09","10","11","12")

$output = @()

foreach ($m in $months) {
  $f = $files.name | Where-Object { $_.substring(5,2) -eq $m }
  if ($f.count -gt 1) {
    $f = ($f | Sort-Object -Descending)[0]
  }
  $output += $f
}

Write-Host $output

答案 2 :(得分:1)

@echo off
setlocal EnableDelayedExpansion

rem Process the files, store the last one of each month in "file" array
for /F "tokens=1* delims=_" %%a in ('dir /B *.xls') do (
   set "fdate=%%b"
   set "file[!fdate:~0,2!]=%%a_%%b"
)

rem Show the result
for /F "tokens=2 delims==" %%a in ('set file[') do echo %%a

答案 3 :(得分:0)

对于批处理文件版本

@echo off
    setlocal enableextensions disabledelayedexpansion

    rem Configure source folder
    set "rootPath=x:\somewhere"

    rem If the source folder can be reached
    pushd "%rootPath%" && (

        rem Prepare a temporary file reference
        for %%t in ("%temp%\%random%%random%%random%%random%.tmp") do (

            rem Prepare a list of files in reverse name order
            >"%%~ft" ((for /r "." %%a in (rep1_*.xls) do @echo(%%~na %%~fa)|sort /r)

            rem For each month retrieve the first file in the list 
            for %%m in (
                01 02 03 04 05 06 07 08 09 10 11 12
            ) do for /f "tokens=1,*" %%a in ('
                findstr /i "rep1_%%m" "%%~ft" ^| cmd /e /v /c"set /p.=&(echo(!.!)"
            ') do if not "%%~b"=="" (echo(%%b)

        rem Remove the temporary file
        ) & del /q "%%~ft"

        rem Return to previous active directory
        popd
    )

答案 4 :(得分:0)

@ECHO Off
SETLOCAL ENABLEDELAYEDEXPANSION 
SET "sourcedir=U:\sourcedir"
:: remove variables starting $ which shouldn't exist - make sure
For %%b IN ($) DO FOR  /F "delims==" %%a In ('set %%b 2^>Nul') DO SET "%%a="

:: set $yyyymm50-dd for each date where a file exists.
FOR /f "tokens=2delims=_." %%a IN (
 'dir /b /a-d "%sourcedir%\rep1_*.xls" '
 ) DO (
 SET "gendate=%%a"
 SET /a gendate=!gendate:~-4!!gendate:~0,2!50 -1!gendate:~2,2!+100
 SET "$!gendate!=%%a"
)

:: Now read each set $ value in date-order of YYMM, reverse-dd
SET prevdate=0
FOR /f "tokens=1,2delims=$=" %%a IN ('set $') DO (
 SET /a gendate=%%a
 IF "!prevdate!" neq "!gendate:~0,6!" (
  SET /a prevdate=%%a/100
  ECHO rep1_%%b.xls
 )
)


GOTO :EOF

您需要更改sourcedir的设置以适合您的具体情况。

第一步是从文件名中获取日期部分,将其重新绑定为yyyymmXX,其中XX = 50-dd。这是通过插入一个常量50,添加100并减去1与日期编号串联来实现的,以便批处理开始0的字符串(如08)是八进制,而不是十进制。

结果是,月份中较晚日期的$变量在“dd”位置上的数字将小于该月份之前的数字,因此会在set列表的前面列出。然后为$number分配文件名中的原始日期字符串。

然后需要的是检测$ {yyyymm在set列表中为$ vars更改的时间。一旦该字符串发生变化,就会检测到新的月份,并且可以重建文件名。这也设置了一个新的prevdate,方便地将gendate的最后两位数除以100。