2017-02-02 2 views
0

Я пытаюсь найти способ разобрать несколько сотен файлов XLS; они содержат ежемесячные отчеты и хранятся в подкаталогах. В некоторых случаях есть несколько отчетов за месяц из-за ошибок в исходном файле XLS, которые были впоследствии исправлены. Я работаю в среде Windows. Мне нужно импортировать эти файлы в SAS для проведения анализа; Я не могу использовать какой-либо другой инструмент, кроме SAS и основной оболочки Windows (возможно, powershell).Список только последних файлов за каждый месяц в Windows

Имя файла содержит информацию о дате его создания, чтобы я мог идентифицировать повторные прогоны только из имен. Пример содержания каталога будет как:

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 

Моя идея заключается в том, чтобы перенаправить вывод команды оболочки для SAS, так что я знаю, какие файлы для чтения. Я не могу найти способ получить один файл за каждый месяц, фильтруя все, кроме самого последнего за каждый месяц. Поэтому я бы получил один для февраля, один для Мар, один для апреля и так далее. Любой указатель приветствуется.

+0

В вашем вопросе не хватает нескольких деталей. Являются ли файлы сгруппированы в подкаталоги в год? Вам нужны результаты по годам или все файлы в том же отчете? Является ли формат имени _always_ XXXX_MMDDYYYY.xls или префикс может иметь разную длину? Префикс _always_ ограничен символом подчеркивания? Если вы не публикуете точные вопросы, вы можете не получить точные ответы ... – Aacini

+0

...и ваш комментарий в этом примере неверен: «это будет повторение на feb 11, если отчет feb 1 содержит ошибку», но есть _not_ отчет о feb 1, только на feb 2's. ** ': /' ** – Aacini

+0

@aacini: я переустановил то, что, на мой взгляд, является опечаткой - первое имя файла должно включать '02012016' не' 02021916' – Magoo

ответ

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; 

Это должно быть довольно близко, хотя, обратите внимание, что делает много предположений о формате ваших имен файлов - вы можете разделить имя файла на подчеркивании, например, ,

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 
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 retieve 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 
    ) 
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 
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 в соответствии с вашей CIRC umstances.

Первый шаг заключается в том, чтобы получить часть даты из имени файла, отменив ее как yyyymmXX, где XX = 50-dd. Это достигается добавлением константы 50, добавлением 100 и вычитанием 1 с номером дня, чтобы идея партии о том, что строка, начинающаяся 0 (например, 08), является восьмеричной, а не десятичной.

В результате переменная $ с более поздней датой в месяце будет иметь меньшее число в позиции «dd», чем раньше в месяце, и, следовательно, будет указана ранее в списке set. Затем $number присваивается исходная строка даты из имени файла.

Все, что требуется, - это определить, когда изменяется $ yyyymm в списке set за $ vars. Как только эта строка изменится, обнаружен новый месяц, и имя файла может быть восстановлено. Это также устанавливает новый prevdate, удобно отсекая последние 2 цифры gendate путем деления на 100.

Смежные вопросы