2

我对批处理文件/脚本非常不满意,尤其是与那些“流利”的人相比:)。我真的很想帮助我创建一个简单(并且易于“调整”)的批处理文件/脚本,它可以帮助我做我需要做的事情(如下所述)。

我正在尝试转换我的照片目录的目录结构。我将这些目录中的大多数以一种/类似的方式排列,我想将其转换为对我来说更方便的不同结构。

我目前的结构如下 -

PhotosCollection01\
|-> Img003.jpg
|-> Img004.jpg
|-> Img005.jpg
|-> Img007.jpg
|-> Img010.jpg
|-> ...
|-> Chosen\
    |-> Img005.jpg
    |-> Img010.jpg

批处理文件/脚本应将结构更改为 -

PhotosCollection01\
|-> NewName001.jpg (formerly Img003.jpg)
|-> NewName002.jpg (formerly Img004.jpg)
|-> NewName004.jpg (formerly Img007.jpg)
|-> ...
|-> Chosen\
    |-> NewName003.jpg (formerly Img005.jpg)
    |-> NewName005.jpg (formerly Img010.jpg)

这就是批处理文件/脚本所做的 -

1) Names are all "NewName???.jpg" (from 001 and up)
2) No duplication of photos under the "Photos" directory and its sub-dirs
3) The "Chosen" directory holds the same amount of photos as before (these were removed from the "Photos" directory)
4) The numbering order of the "NewName" photos is kept in the same order as the "Img" order (although numbering is reset to start from 000)
5) I would love to be able to have "PhotosCollectionXX", "NewNameXXX" and "Chosen" to be able to consist of spaces in their real names

直到(如果)我得到答案,我会尝试自己学习和编写脚本。任何帮助将不胜感激!

提前非常感谢, 埃亚尔

4

4 回答 4

1
@ECHO OFF
SETLOCAL
SET "relroot=u:\photos collection 01"
SET "oldmask=im age"
SET "newmask=new name"
SET "ext=jpg"
SET "skipped="
::
:: step 1 - ensure no 'newname*.ext' exists in the subtree
::
FOR /f %%i IN (
  'DIR /s/b/a-d "%relroot%\%newmask%*.%ext%" 2^>nul^|FIND /c /v "" '
 ) DO IF NOT %%i==0 ECHO Files matching new mask already exist&GOTO :EOF 
::
:: step 2 - list target files
::
:temploop
SET tempfile=%temp%\Photo%random%
IF EXIST "%tempfile%*" GOTO temploop
:: now have random tempfile name
(
FOR /f "delims=" %%i IN (
  'DIR /s/b/a-d "%relroot%\%oldmask%*.%ext%" '
  ) DO (
  ECHO %%~ni*%%~fi
)
)>"%tempfile%1"
::
:: Now do the rename
::
SET count=1000
SET prev=%newmask%
FOR /f %%i IN ('find /c "*" ^<"%tempfile%1"') DO IF %%i gtr 1000 ECHO %%i files - exceeds capacity&GOTO :eof
FOR /f "delims=*" %%i IN ('SORT "%tempfile%1"') DO (CALL :incren "%%i")
IF DEFINED skipped ECHO some files were NOT renamed&DIR /s/b/a-d "%relroot%\%oldmask%*.%ext%"

DEL "%tempfile%1"
GOTO :eof

:incren
:: repeat?
IF "%prev%"==%1 GOTO :EOF
:: no - process next name found
SET "prev=%~1"
FOR %%n IN (firstname secondname) DO (SET %%n=)
:: scan the tempfile, looking for matches to name found
FOR /f "usebackqtokens=1,2delims=*" %%m IN ("%tempfile%1") DO IF /i "%%m"=="%prev%" (
 IF DEFINED firstname SET skipped=Y&IF NOT DEFINED secondname SET secondname=%%n
 IF NOT DEFINED firstname SET firstname=%%n
)
IF DEFINED secondname SET firstname=%secondname%
ECHO REN "%firstname%" "%newmask%%count:~-3%.%ext%"
SET /a count+=1
GOTO :eof

好吧,毕竟不是太难。

不太符合您的规范 - 我避免删除文件,所以我没有重命名任何具有重复名称的目标。

尝试处理 IMO 愚蠢的文件名时给予了太多的关注。如果你!%^)=在你的文件名中使用类似的字符——好吧——你很聪明——你会想出来的。

所以,假设合理的文件名字符和空格,工作!

首先设置您的relative root(起始子目录)名称、要使用的文件掩码、新旧文件以及扩展名。我使用set "var=string"语法来避免应用不可见且可能导致混乱的杂散终端空间。另请注意,在字符串赋值中,'=' 两边的空格很重要。

第一步是记录在案的。如果树中已经有与新名称匹配的文件,不确定该怎么做 - 所以什么也不做。如果一切正常,计算从dir /s/b/a-d(目录,带有子目录,基本形式(因此没有标题)和没有目录名称)出现的行数应该大约为 0。

我喜欢使用 showm 方法设置临时文件。如果没有%temp%与选择的随机名称匹配的名称,那么使用该名称+您喜欢的任何附录应该是安全的(因此,如果需要,您可以创建许多临时文件。)

下一步是再次以基本形式获取旧名称文件的子目录 - 但这次输出到临时文件。输出的是每个文件的一行,结构为仅 NAME 部分 ( %%~ni) 一个星号和完整的文件名 ( %%~fi)。星号充当列分隔符并且是安全的,因为*不能出现在文件名中。

接下来是重命名阶段。我们从COUNT1000 开始,以便我们可以使用最后 3 个字符来创建名称。如果您想从 001 开始,请改用 1001。PREV被初始化为一个不能作为要重命名的文件名出现的值。

再次计算要重命名的名称。如果太多,弃船。

下一步是对临时文件进行排序,因此将按原始基本文件名的顺序(每行中的“*”之前)处理结果,然后,如果名称匹配,则按子目录名称的字母顺序(因为 name* parent 将在 name*parent\subdir) 之前排序。然后将遇到的每个 NAME 传递给:incren例程 - 引用以适应文件名中的空格要求。

INCREN 例程做的第一件事是检查该名称是否与之前遇到的名称重复。如果是,则忽略该名称(因为它已被处理)。PREV然后设置为遇到的下一个名称。SET "prev=%~1"从第一个参数中删除引号,然后将结果分配给prev和封闭的引号防止杂散空格对接。firstname然后secondname设置为 [nothing]

然后我们再次扫描临时文件,寻找匹配的名称作为第一个标记并将第二个标记(完整文件名)分配给%%n

找到第一个时,未设置名字,因此将其设置为完整文件名。如果找到第二个名称,则firstname已经设置,因此设置SKIPPED为标记遇到问题。如果尚未设置第二个文件名,则设置为该secondname完整文件名。如果找到更多匹配项,则由于现在已设置,将不再进行任何操作。secondname

处理完文件后,我们将firstname设置为第一个完整文件名(因为第一个遇到的是相对根目录),并且secondname只有在找到 2 个或更多匹配名称时才会设置。在这种情况下,设置firstname为遇到的第二个名称的值,该名称将位于较低的子目录中。

现在进行重命名。我刚刚ECHO编辑了它,但要激活,请ECHOECHO REN...行中删除。我们知道firstname包含要重命名的文件的全名,并且我们知道新文件名的结构将是新的掩码+最后3个字符COUNT+一个点+选定的扩展名。

并为下一次重命名准备好计数...

这是删除后的测试运行ECHO

============= before =========

u:\photos collection 01\im age 612.jpg
u:\photos collection 01\im age 003.jpg
u:\photos collection 01\im age 005.jpg
u:\photos collection 01\im age 610.jpg
u:\photos collection 01\im age 009.jpg
u:\photos collection 01\im age 609.jpg
u:\photos collection 01\im age 505.jpg
u:\photos collection 01\selection 01\im age 001.jpg
u:\photos collection 01\selection 01\im age 004.jpg
u:\photos collection 01\selection 01\im age 005.jpg
u:\photos collection 01\selection 01\im age 006.jpg

=============  run  =========

some files were NOT renamed
u:\photos collection 01\im age 005.jpg

============= after  =========

u:\photos collection 01\new name009.jpg
u:\photos collection 01\new name001.jpg
u:\photos collection 01\im age 005.jpg
u:\photos collection 01\new name008.jpg
u:\photos collection 01\new name005.jpg
u:\photos collection 01\new name007.jpg
u:\photos collection 01\new name006.jpg
u:\photos collection 01\selection 01\new name000.jpg
u:\photos collection 01\selection 01\new name002.jpg
u:\photos collection 01\selection 01\new name003.jpg
u:\photos collection 01\selection 01\new name004.jpg

请注意,这是在 FAT 驱动器上执行的,因此实际文件的顺序在两个列表中是相同的。

于 2013-04-14T10:07:25.290 回答
0

试试这个并删除echobefore move,如果输出正常:

@echo off&setlocal
set "sourcefolder=PhotosCollection01"

for /r "%sourcefolder%" %%i in (*.jpg) do (
    if defined "$n%%~nxi" set "$d%%~nxi=%%~nxi"
    set "$p%%~nxi=%%~dpi"
    set "$n%%~nxi=%%~nxi"
)
set "$d" >nul 2>&1 && (
    echo(Duplicate filename(s^):
    for /f "tokens=2delims==" %%i in ('set $d') do echo(%%i
    goto:eof
)
set /a counter=1000
for /f "tokens=2delims==" %%i in ('set $n') do (
    set /a counter+=1
    setlocal enabledelayedexpansion
    if exist "!$p%%~i!NewName!counter:~-3!%%~xi" (
    echo(file already exists: "!$p%%~i!NewName!counter:~-3!%%~xi"
    ) else echo move "!$p%%~i!%%~i" "!$p%%~i!NewName!counter:~-3!%%~xi"
    endlocal
)

如果在子文件夹中发现重复的文件名,脚本将终止。如果目标文件已经存在,则不会被覆盖。请注意:%sourcefolder% 中的所有文件夹都使用相同的计数器。如果您有不同的选择,请为每个选择调用此脚本或写评论。

于 2013-04-14T15:07:33.980 回答
0

如果您在 Windows 下有 Total Commander(从示例中的路径分隔符,我假设您使用 Windows),您可能无需脚本即可实现此目的。如果按 Ctrl+B,它将列出当前目录中的所有文件和一个列表中的所有子目录。然后如果你全选(*)并按Ctrl+M,会出现批量重命名工具,你可以重命名它们,设置用NewName替换Img并在文件名末尾添加一个计数器。

于 2013-04-14T08:20:16.510 回答
0

有趣的话题!我这样理解您的要求: 1- 从 PhotosCollection 和 Chosen 创建一个唯一文件名列表,但优先选择 Chosen 的文件(PhotosCollection 的同名文件将被删除)。2- 将列表中的文件重命名为从001开始的连续数字。下面的批处理文件实现了这个过程,但是它处理当前目录中的所有目录(从PhotosCollection01到PhotosCollectionNN)并处理每个目录下的所有子目录,即,如果 Chosen 子目录有“兄弟”,它们都以相同的方式处理。

@echo off
setlocal

rem Set this value as you wish (ie: set NewName=New Name With Spaces)
set NewName=NewName

rem Process all directories at this level
for /D %%a in (*) do (
   rem Enter into this directory (ie: PhotosCollection01)
   cd "%%a"
   rem Insert file names in the initial list as "parent" (ie: Img003.jpg Img004.jpg Img005.jpg)
   setlocal EnableDelayedExpansion
   for %%c in (*.jpg) do (
      set unique[%%c]=.
   )
   rem Process each subdirectory
   for /D %%b in (*) do (
      rem Enter into this subdirectory (ie: Chosen)
      cd "%%b"
      rem Process "nested" file names (ie: Img005.jpg Img010.jpg)
      for %%c in (*.jpg) do (
         if "!unique[%%c]!" equ "." (
            rem Delete duplicated file in parent directory (ie: PhotosCollection01\Img005.jpg)
            del "..\%%c"
         )
         rem Insert file name in the list as "nested"
         set unique[%%c]=%%b
      )
      rem Go back to parent directory (ie: PhotosCollection01)
      cd ..
   )
   rem Rename all names in the list from 001 and up
   set number=1000
   for /F "tokens=2,3 delims=[]=" %%c in ('set unique[') do (
      set /A number+=1
      ren "%%d\%%c" "%NewName%!number:~-3!.jpg"
   )
   rem Delete the list
   endlocal
   rem Go back to original directory (where PhotosColection01...NN exist)
   cd ..
)

将此批处理文件放在包含集合的同一文件夹中并执行它,您必须对测试文件执行几次,直到您对结果满意为止。请注意,可以轻松修改该方法,以便同时删除或重命名所有 Chosen 兄弟文件夹中的重复文件,即如果“Chosen2”文件夹有 Img010.jpg 文件(也位于 Chosen 中),则删除或重命名 Chosen 或 Chosen2 的一个(目前它们被保留,但未重命名)。所有目录和文件名都可以有空格,但是包含感叹号的名称将不会被正确处理;如果需要,这个细节可能会被修复。

C:\Users\Antonio\Documents\test
>dir /b
PhotosCollection01
renumber.bat

C:\Users\Antonio\Documents\test
>dir /b PhotosCollection01
Chosen
Img003.jpg
Img004.jpg
Img005.jpg
Img007.jpg
Img010.jpg

C:\Users\Antonio\Documents\test
>dir /b PhotosCollection01\Chosen
Img005.jpg
Img010.jpg

C:\Users\Antonio\Documents\test
>renumber.bat

C:\Users\Antonio\Documents\test
>dir /b PhotosCollection01
Chosen
NewName001.jpg
NewName002.jpg
NewName004.jpg

C:\Users\Antonio\Documents\test
>dir /b PhotosCollection01\Chosen
NewName003.jpg
NewName005.jpg
于 2013-04-14T17:04:10.667 回答