我正在尝试找到解析数百个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月,依此类推。 任何指针都是受欢迎的。
答案 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。