BAT脚本按文件名

时间:2016-03-08 15:59:22

标签: windows batch-file cmd directory subdirectory

我正在尝试编写一个BAT脚本,根据文件名将文件移动到子文件夹中 - 不需要详细说明这个文件的明确目的,这些文件以2个描述性前缀“PREFIX1_PREFIX2_descriptivefilename”命名 - 带有下划线分隔符

我想根据一些依赖于PREFIX1和PREFIX2的不同规则将文件移动到文件夹中。

这旨在用于组织打印文档和图像的内部系统,这些文档和图像打印在各种类型的纸张上。例如,假设我们只使用2种PREFIX1类型 - Class1和Class2。 PREFIX2可以采用多种形式表示纸张尺寸,简单来说,“A6paper”,“A5paper”,“A4paper”和“更大”。

我需要文件夹的文件名与前缀略有不同,因为任何一个文件夹都可以包含PREFIX1和PREFIX2文档类型的混合,因为打印类型数量有限,假设我们正在使用的文件夹是“A5”,“A4”,“其他”,带有A6paper和A5paper前缀的文件都将进入“A5”。

以下是我的示例BAT脚本:

for /f "tokens=1,2* delims=_" %%a in ('dir /B *_*_*.pdf *_*_*.png') do (
    if /I %%a == Class1 (
        if /I %%b == A4paper (
            if not exist "A4" md "A4"
            move "%%a_%%b_%%c" "A4\%%a_%%b_%%c"
        )
        else if /I %%b == A5paper (
            if not exist "A5" md "A5"
            move "%%a_%%b_%%c" "A5\%%a_%%b_%%c"
        )
        else if /I %%b == A6paper (
            if not exist "A5" md "A5"
            move "%%a_%%b_%%c" "A5\%%a_%%b_%%c"
        )
        else if /I %%b == Larger (
            if not exist "Other" md "Other"
            move "%%a_%%b_%%c" "Other\%%a_%%b_%%c"
        )
    )

else if /I %%a == Class2 (
    if /I %%b == A4paper (
        if not exist "A4" md "A4"
        move "%%a_%%b_%%c" "A4\%%a_%%b_%%c"
    )
    else if /I %%b == A5paper (
        if not exist "A5" md "A5"
        move "%%a_%%b_%%c" "A5\%%a_%%b_%%c"
    )
    else if /I %%b == A6paper (
        if not exist "A5" md "A5"
        move "%%a_%%b_%%c" "A5\%%a_%%b_%%c"
    )
    else if /I %%b == Larger (
        if not exist "Other" md "Other"
        move "%%a_%%b_%%c" "Other\%%a_%%b_%%c"
    )
)

else if....

因为你可以看到这段代码看起来有点笨拙。我真的不确定BAT的语法,是否应该完全删除“else”,因为我使用它会出现一些错误。无论如何,输出似乎与预期的一样,嵌套if子句中的代码似乎是随机执行的,无论更高级别的规则如何。

我还希望能够写出如下内容:

if /I %%b in ("A5paper", "A6paper") (
    if not exist "A5" md "A5"
    move "%%a_%%b_%%c" "A5\%%a_%%b_%%c"
)

......但似乎不允许这样做。

非常感谢任何帮助。

2 个答案:

答案 0 :(得分:1)

for %%a in (A4 A5 Other) do md %%a 2>nul
for /f "tdelims=" %%r in ('dir /B *_*_*.pdf *_*_*.png') do (
 for /f "tokens=1,2* delims=_" %%a in ("%%r") do (
  if /i "%%a"== "Class1" (
   if /i "%%b"=="A4paper" (move "%%r" "a4\" >nul)
   if /i "%%b"=="A5paper" (move "%%r" "a5\" >nul)
   if /i "%%b"=="A6paper" (move "%%r" "a5\" >nul)
   if /i "%%b"=="Larger"  (move "%%r" "Other\" >nul)
  )
  if /i "%%a"== "Class2" (
   if /i "%%b"=="A4paper" (move "%%r" "a4\" >nul)
   if /i "%%b"=="A5paper" (move "%%r" "a5\" >nul)
   if /i "%%b"=="A6paper" (move "%%r" "a5\" >nul)
   if /i "%%b"=="Larger"  (move "%%r" "Other\" >nul)
  )
  )
 )
)

您的问题似乎基本上属于逻辑问题,但在批处理中,必须放置任何else,以便else关键字前面的闭括号和后面的左括号都在相同的物理线。

从您的示例中,您会发现%%b只能是A4paperA5paperA6paperLarger。关键是它不能匹配多个这些值。同样适用于%%a

语法if "value"=="anothervalue" ...可能更好,因为它可以确保处理值而不管任何会扰乱cmd解析的分隔符(行间距)。

如果您首先创建所有目标目录,则无需在例程中创建它们,这简化了事务。

2>nul会抑制错误消息(例如already exists>nul会抑制正常消息(例如1 files(s) moved)。

将文件名应用于%%r是为了简化 - 内部for可以按照显示的方式处理%%r%%r可以方便地包含整个名称,因此它不需要重建。

同样,使用move语句中的引号表示正确处理了spaces in filenames

答案 1 :(得分:1)

解决此问题的最简单,最有效的方法是通过array:您事先定义一系列数组元素,为每对PREFIX1和PREFIX2指定目标文件夹。之后,您只需使用数组数据处理文件

@echo off
setlocal EnableDelayedExpansion

rem Define the array for destination folders:

set "folder[Class1,A4paper]=A4"
set "folder[Class1,A5paper]=A5"
set "folder[Class1,A6paper]=A5"
set "folder[Class1,Larger]=Other"

set "folder[Class2,A4paper]=A4"
set "folder[Class2,A5paper]=A5"
set "folder[Class2,A6paper]=A5"
set "folder[Class2,Larger]=Other"

rem Move the files:
for /F "tokens=1,2* delims=_" %%a in ('dir /B *_*_*.pdf *_*_*.png') do (
   if not exist "!folder[%%a,%%b]!" md "!folder[%%a,%%b]!"
   move "%%a_%%b_%%c" "!folder[%%a,%%b]!\"
)

您无需在move命令中重复文件名。

有关批处理文件中阵列管理的进一步说明,请参阅:Arrays, linked lists and other data structures in cmd.exe (batch) script