你所拥有的非常好,你已经很接近了。
我正在测试的环境需要do (
将 open paren 与 do 放在同一行。中间有换行符的格式可能会导致问题。
您完全缺少的是对预期为 YYYYMMDD 的目录名称的任何解析。你可以这样做:
set dirname=%%d
set year=%dirname:~0,4%
set month=%dirname:~4,2%
set day=%dirname:~6,2%
完成此操作后,很容易根据 YYYY、MM、DD 创建文件名和路径:
set s3path=!file_year!!file_month!\!file_day!.!file_month!.!file_year!
将生成类似 YYYYMM\DD.MM.YYYY 的路径。
您可以使用以下方法获取“最后一个”目录:
for /f "tokens=1" %%a IN ('dir /b /a:d /o:n ????????') do (
set dirset=%%a
)
注意:这仅在第二种解决方案中实现。让我们分解一下:
dir /b /a:d /o:n ????????
是否以“裸”格式创建目录(仅匹配文件列表,每行一个),具有属性目录(仅列出目录),按名称排序(这是 NTFS 的默认设置,但不是 FAT,因此最好指定排序顺序),匹配 ??????????,任意 8 个字符(因为目录应该命名为 YYYYMMDD,所以总是 8 个字符)。这将返回 8 个字符的目录名称的有序列表。
for /f "tokens=1" %%a IN ('command') do echo %%a
command
逐行执行并解析结果。这里将回显每个结果的第一个标记。
for /f "tokens=1" %%a IN ('dir /b /a:d /o:n ????????') do (
set dirset=%%a
)
我们将它们放在一起,看看dirset
将设置为每个匹配的目录名称。但是在for
循环完成后,它将被设置为最后一个值,或“最新”目录。
在下面的代码中我已经dirname
单独设置以避免变量扩展规则的问题。或者,您应该能够使用:
setlocal enableextensions enabledelayedexpansion
set dirname=%%d
set year=!dirname:~0,4!
如前所述,您的问题不需要递归。我的代码只是迭代每个目录,然后迭代每个文件。如果文件布局的结构不如您指出的那样,则可能需要递归。
您没有指定您使用哪个 Windows S3 命令行工具,所以我*S3COPY*
使用本地完整路径和部分路径进行回应。您应该可以用您的复制命令替换它。
您需要从中运行它,d:\RecFileD
或者您可以在 bat 文件顶部附近添加它:
d:
cd \RecFileD
您可能需要更改s3root
为本地 S3 副本的实际根目录。我没有移动文件,而是让 sox 在正确的位置创建它们。
我设置了年、月、日变量,processfiles
因为变量扩展规则使设置它们processdirs
变得复杂。
如果您做的远不止这些,我建议您研究 Python。它有一个很棒的社区/生态系统,很容易上手并且是免费的。另外,您不会把所有的时间都花在与语言打架上。
这是我的第一次尝试:
@echo off
setlocal
set s3root=d:\s3\bucket\voice
call :processdirs
goto :eof
:processfiles
set year=%dirname:~0,4%
set month=%dirname:~4,2%
set day=%dirname:~6,2%
set s3path=%year%%month%\%day%.%month%.%year%
set s3dir=%s3root%\%s3path%
if not exist "%s3dir%" md "%s3dir%"
for %%f in (*.wav) do (
sox "%%~nf.WAV" "%s3dir%\%%~nf.mp3"
sox "%%~nf.WAV" "%s3dir%\%%~nf-short.mp3" trim 0:30 1:00
)
echo *S3COPY* %s3dir% %s3path%
goto :eof
:processdirs
for /D %%d in (*) do (
set dirname=%%d
cd "%%d"
call :processfiles
cd ..
)
goto :eof
@Aacini 的回答让我意识到,不幸的是我的解决方案缺乏。它不仅仅处理今天的文件。但我很关心跳过一天会发生什么。
我添加了两个参数来控制处理的内容。第一个参数指定一个命名过滤器,可以是以下之一:
- newlatest - 最新目录中的新文件,基于文件名(默认)
- latest - 最新目录中的所有文件,基于文件名
- today - 今天的目录
- newdirs - S3 树中不存在的所有目录(缺失日期)
- newfiles - S3 树中不存在的所有文件
- all - 所有文件(用于覆盖 S3 树中的损坏)
如果过滤器是newdirs
,newfiles
或all
,则可以使用第二个参数来进一步过滤目录名称。您可以使用 * 和 ? 通配符匹配一组文件。
如果您将脚本保存为 ProcDirs.bat,那么这里有一些示例:
ProcDirs all 20121119
将强制处理(或重新处理)指定目录。
ProcDirs newdirs 201211??
将处理与目录名称匹配的新目录(从输出树中丢失)(指定年份和月份的任何一天)。
ProcDirs newfiles 2012????
将处理与目录名称匹配的目录中的新文件(从输出树中丢失)(指定年份的任何一天)。
ProcDirs
ProcDirs newlatest
完全相同,因为newlatest
是默认值。这将处理(词法上)“最新”目录中的新文件
代码比较复杂,但还不错。我确实尝试使用@Aacini 的代码来获取今天的月/日/年,但它在我的系统上不起作用(因为我的日期格式必须与要求的不同)。所以我使用了一种不依赖于本地日期格式的不同方法。
我的第一个解决方案不需要延迟扩展,但是这个解决方案需要使用setlocal
(适用于 Win XP 但可能不适用于较旧的 Windows)并使用!
而不是%
用于环境变量替换。
@echo off
setlocal enableextensions enabledelayedexpansion
set s3root=d:\s3\bucket\voice
rem Set the default filter mode
set newfilter=none
set dirsetfilter=none
set arg=%1
if "!arg!" == "" set arg=newlatest
if "!arg!" == "newdirs" (
set newfilter=newdirs
) else if "!arg!" == "newfiles" (
set newfilter=newfiles
) else if "!arg!" == "all" (
set dirsetfilter=none
set newfilter=none
) else if "!arg!" == "today" (
set dirsetfilter=today
) else if "!arg!" == "latest" (
set dirsetfilter=latest
) else if "!arg!" == "newlatest" (
set newfilter=newfiles
set dirsetfilter=latest
)
if !dirsetfilter! == today (
for /f "skip=1 tokens=1-3" %%a IN ('wmic path Win32_LocalTime Get Day^,Month^,Year /Format:table') do (
if %%a GTR 0 (
set now_day=%%a
set now_month=%%b
set now_year=%%c
)
)
set dirset=!now_year!!now_month!!now_day!
if not "%2" == "" echo Second parameter, dirset, ignored when filter is today
) else if !dirsetfilter! == latest (
rem pull out the name of the 'last' directory
for /f "tokens=1" %%a IN ('dir /b /a:d /o:n ????????') do (
set dirset=%%a
)
if not "%2" == "" echo Second parameter, dirset, ignored when filter is latest
) else if not "%2" == "" (
rem The second parameter is dirset. Wild card chars, *? allowed
rem only matched dir(s) processed
set dirset=%2
) else (
rem process all dirs that match filter
set dirset=*
)
call :processdirs
goto :eof
:processfiles
set file_year=!dirname:~0,4!
set file_month=!dirname:~4,2!
set file_day=!dirname:~6,2!
set s3path=!file_year!!file_month!\!file_day!.!file_month!.!file_year!
set s3dir=!s3root!\!s3path!
set skipdir=FALSE
if not exist "!s3dir!" (
md "!s3dir!"
) else (
if newdirs == !newfilter! set skipdir=TRUE
)
if !skipdir! == FALSE (
set havenewfiles=FALSE
for %%f in (*.wav) do (
set skipfile=FALSE
if newfiles==!newfilter! if exist "!s3dir!\%%~nf.mp3" set skipfile=TRUE
if !skipfile! == FALSE (
set havenewfiles=TRUE
echo sox "%%~nf.WAV" "!s3dir!\%%~nf.mp3"
sox "%%~nf.WAV" "!s3dir!\%%~nf.mp3"
)
set skipfile=FALSE
if newfiles == !newfilter! if exist "!s3dir!\%%~nf-short.mp3" set skipfile=TRUE
if !skipfile! == FALSE (
set havenewfiles=TRUE
echo sox "%%~nf.WAV" "!s3dir!\%%~nf-short.mp3" trim 0:30 1:00
sox "%%~nf.WAV" "!s3dir!\%%~nf-short.mp3" trim 0:30 1:00
)
)
if !havenewfiles! == TRUE (
echo *S3COPY* !s3dir! !s3path!
)
)
goto :eof
:processdirs
for /D %%d in (!dirset!) do (
echo Process Dir: %%d
set dirname=%%d
cd "%%d"
call :processfiles
cd ..
)
goto :eof
祝你好运。我希望这有帮助。