【问题标题】:Order and move files into directories based on some filenames pattern根据某些文件名模式对文件进行排序并将其移动到目录中
【发布时间】:2016-10-09 14:26:46
【问题描述】:

要将文件移动到文件夹中,我使用此脚本

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem // Define constants here:
set "SPLITCHAR=-"  & rem // (a single character to split the file names)
set "SEARCHSTR=_"  & rem // (a certain string to be replaced by another)
set "REPLACSTR= "  & rem // (a string to replace all found search strings)
set "OVERWRITE="   & rem // (set to non-empty value to force overwriting)

rem // Get file location and pattern from command line arguments:
set "LOCATION=%~1" & rem // (directory to move the processed files into)
set "PATTERNS=%~2" & rem // (file pattern; match all files if empty)

rem /* Prepare overwrite flag (if defined, set to character forbidden
rem    in file names; this affects later check for file existence): */
if defined OVERWRITE set "OVERWRITE=|"
rem // Continue only if target location is given:
if defined LOCATION (
    rem // Create target location (surpress error if it already exists):
    2> nul md "%LOCATION%"
    rem /* Loop through all files matching the given pattern
    rem    in the current working directory: */
    for /F "eol=| delims=" %%F in ('dir /B "%PATTERNS%"') do (
        rem // Process each file in a sub-routine:
        call :PROCESS "%%F" "%LOCATION%" "%SPLITCHAR%" "%SEARCHSTR%" "%REPLACSTR%"
    )
)

endlocal
exit /B


:PROCESS
rem // Retrieve first argument of sub-routine:
set "FILE=%~1"
rem // Split name at (first) split character and get portion in front:
for /F "delims=%~3" %%E in ("%~1") do (
    rem // Append a split character to partial name:
    set "FOLDER=%%E%~3"
)
setlocal EnableDelayedExpansion
rem // Right-trim partial name:
if not "%~4"=="" set "FOLDER=!FOLDER:%~4%~3=!"
set "FOLDER=!FOLDER:%~3=!"
rem /* Check whether partial name is not empty
rem    (could happen if name began with split character): */
if defined FOLDER (
    rem // Replace every search string with another:
    if not "%~4"=="" set "FOLDER=!FOLDER:%~4=%~5!"
    rem // Create sub-directory (surpress error if it already exists):
    2> nul md "%~2\!FOLDER!"
    rem /* Check if target file already exists; if overwrite flag is
    rem    set (to an invalid character), the target cannot exist: */
    if not exist "%~2\!FOLDER!\!FILE!%OVERWRITE%" (
        rem // Move file finally (surpress `1 file(s) moved.` message):
        1> nul move /Y "!FILE!" "%~2\!FOLDER!"
    )
)
endlocal
exit /B

要使用脚本我必须

1- 打开 cmd
2-要执行批处理我必须

cd C:\Users\Administrator\Desktop\T\
"C:\Users\Administrator\Desktop\T\build-folder-hierarchy.bat" "C:\Users\Administrator\Desktop\T\" "*.pdf"

但是问题是什么?

为每个 .pdf 文件批处理创建一个相对文件夹,但我不希望它以这种方式创建文件夹。看http://i.imgur.com/TVhQyzv.png

aaaa aaaa S02 [folder]
aaaa aaaa S02e01.pdf [folder]
aaaa aaaa S02e02.pdf [folder]
aaa.aaaa.aaa.aa.aaaaa.S02 [folder]

我想要什么?

├─aaaa aaaa S02 [folder]
│ ├─aaaa aaaa S02e01.pdf[file]
│ ├─aaaa aaaa S02e02.pdf [file]
  └─ ....
├─aaa.aaaa.aaa.aa.aaaaa.S02 [folder]
│ └─aaa.aaaa.aa.aa.aaaaa.S02E13.pdf [file]
:

只是一个示例名称,以了解 .pdf 文件名的格式

aaaaaaaaa aa aaaaa S01e12 720p Repack.pdf
aaa aaaaaaaaa S01e05 Versione 720p.pdf
aaa aaaaaaaa S01e05 Versione 1080p.pdf
aaa aaaa s2e06.pdf
aaa aaaa S03e12.pdf
aaa.aaaa.aaa.on.Earth.S02E13.pdf
aaa.aaaa.aaaa.S02E01.HDTV.x264.SUB.ITA.pdf

通常pdf文件名都是这样格式化的[pattern]

s01
s01e1
s1
s1e1
s1e01
s1e01-10

字符,例如 es 几乎总是出现在这些模式名称中 一般形式应该是

sxx
sxxex
sx
sxex
sxexx
sxexx-xx

X 是一个数字,字母 se 的大小写无关

Powershell 解决方案被广泛接受。

【问题讨论】:

  • 请将您的实际文件夹结构作为文本放入您的问题中,而不是指向图像的链接!
  • 我添加了脚本制作的实际结构
  • 我知道我以前见过that script...我没有得到你真正想要的,因为你提供了多个例子(如aaaa aaaa S02e01.pdfs01e1[.pdf]);该脚本旨在将文件名拆分为某个字符,取之前的部分并将其用作目标文件夹名称;有没有这样的字符,例如e
  • 取之前的部分并将其用作目标文件夹名称? BUT 该脚本不足,因为我有不同的文件名模式。字符,例如 es 几乎总是出现在这些模式名称中。
  • 所以基本上你有一大堆,呃......单本小说......在他们自己的目录中,你想将它们分组,呃......书籍系列......和您还想用句点替换空格以匹配,呃... 标准命名它们的方式?

标签: powershell batch-file


【解决方案1】:

您的问题令人困惑。您没有描述文件名的格式,而只是显示一些示例,使用示例而不是规范可能会被误解。为其他不适用于此问题的问题编写的邮政编码当然没有用。您没有使用真实文件名显示输入和想要输出的示例,因此基于示例数据的解决方案可能不适用于真实数据。

编辑添加了新规范。规格和程序代码都已根据 cmets 中给出的要求进行了相应修改。

据我了解,以下是此问题的规范:


“给定一系列具有这种格式的 *.pdf 文件:

any string hereS##Eany string here.pdf
              / | ^-- "E" letter
    "S" letter  digit

提取“S-digit”分隔符后“E”之前结束的字符串并将文件移动到具有此类名称的文件夹中,“S”和“E”字母不区分大小写。忽略没有以前格式的文件。"

这段代码根据这样的规范解决了问题:

@echo off
setlocal EnableDelayedExpansion

rem Change current directory to the one where this .bat file is located
cd "%~P0"

set "digits=0123456789"

rem Process all *.pdf files
for %%f in (*.pdf) do (

   rem Get the folder name of this file
   call :getFolder "%%f"

   rem If this file have a properly formatted name: "headS##Etail"
   if defined folder (
      rem Move the file to such folder
      if not exist "!folder!" md "!folder!"
      move "%%f" "!folder!"
   )

)
goto :EOF


:getFolder file

set "folder="
set "file=%~1"
set "head="
set "tail=%file%"

:next
   for /F "delims=%digits%" %%a in ("%tail%") do set "head=%head%%%a"
   set "tail=!file:*%head%=!"
   if not defined tail exit /B
   if /I "%head:~-1%" equ "S" goto found
   :digit
      if "!digits:%tail:~0,1%=!" equ "%digits%" goto noDigit
      set "head=%head%%tail:~0,1%"
      set "tail=%tail:~1%"
   goto digit
   :noDigit
goto next

:found
for /F "delims=Ee" %%a in ("%tail%") do set "folder=%head%%%a"
exit /B

要使用此批处理文件,请将其放在原始文件所在的同一文件夹中,并在不带参数的情况下执行;您也可以通过在资源管理器中双击来执行它。示例会话:

C:\Users\Antonio\Documents\test> dir /B
test.bat
The_Good_Wife_S06e15.pdf
The_Good_Wife_S06e22.pdf
TOCCO_ANGELO_4.pdf
True Blood S07e07_001.pdf
True Detective S02E03-04 Repack.pdf
True Detective S02e03.pdf
True Detective S02e03_001.pdf
True.Detective.S02e02.1080p.WEBMux.pdf
Tudors S04e08.pdf
Tutti pazzi per amore s3e15-16.pdf
Tutto Pu‗ Succedere S01e01-02.pdf
Twin Peaks s1e1-8.pdf
Twin Peaks s2e16-22.pdf
Tyrant S02e07.pdf
Tyrant.S01e01_02.720p.DLMux.pdf
Ultimo 2 - La Sfida.pdf
Ultimo 3 -L Infiltrato.pdf
Una Mamma Imperfetta S02e01-13.pdf
Under the Dome S02e02 Versione 720p.pdf
Under.the.Dome.S03E07.HDTV.x264.SUB.ITA.pdf

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

C:\Users\Antonio\Documents\test> tree /F
Listado de rutas de carpetas
El número de serie del volumen es 00000088 0895:160E
C:.
│   test.bat
│   TOCCO_ANGELO_4.pdf
│   Ultimo 2 - La Sfida.pdf
│   Ultimo 3 -L Infiltrato.pdf
│
├───The_Good_Wife_S06
│       The_Good_Wife_S06e15.pdf
│       The_Good_Wife_S06e22.pdf
│
├───True Blood S07
│       True Blood S07e07_001.pdf
│
├───True Detective S02
│       True Detective S02E03-04 Repack.pdf
│       True Detective S02e03.pdf
│       True Detective S02e03_001.pdf
│
├───True.Detective.S02
│       True.Detective.S02e02.1080p.WEBMux.pdf
│
├───Tudors S04
│       Tudors S04e08.pdf
│
├───Tutti pazzi per amore s3
│       Tutti pazzi per amore s3e15-16.pdf
│
├───Tutto Pu‗ Succedere S01
│       Tutto Pu‗ Succedere S01e01-02.pdf
│
├───Twin Peaks s1
│       Twin Peaks s1e1-8.pdf
│
├───Twin Peaks s2
│       Twin Peaks s2e16-22.pdf
│
├───Tyrant S02
│       Tyrant S02e07.pdf
│
├───Tyrant.S01
│       Tyrant.S01e01_02.720p.DLMux.pdf
│
├───Una Mamma Imperfetta S02
│       Una Mamma Imperfetta S02e01-13.pdf
│
├───Under the Dome S02
│       Under the Dome S02e02 Versione 720p.pdf
│
└───Under.the.Dome.S03
        Under.the.Dome.S03E07.HDTV.x264.SUB.ITA.pdf

如果“S”分隔符之前的文件名不能包含数字,则此代码会简单得多。此解决方案假定文件名中没有感叹号!

【讨论】:

  • 您非常接近我的要求,您的解决方案很好但不完整。看看我的示例列表:如果存在一些无法识别的文件,则脚本冲突 - 例如,如果存在像 pastebin.com/xzSnJab6 这样的文件名,它就不起作用。但是脚本 它可以工作,相反,如果我有这些文件 pastebin.com/1mi7TKKe Pic i.imgur.com/JxSHLia.png 。您可以看到它已成功重组。 但是pastebin.com/utp02Qrz 这样的文件夹中的混合文件名不会被您的脚本处理,因为您的代码的某些部分会阻止其执行,将其锁定。
  • 如果我的正则表达式中有一些文件 check-in 脚本也不会启动。如果正确检测到其他文件名,为什么不处理?另一个例子:在这个文件列表pastebin.com/gNunY729 中,只有 The_Good_Wife_S06e15.pdf 被脚本移动到 The_Good_Wife_S06 生成的文件夹中,而不是其他文件。但是,如果我删除只有这些文件 pastebin.com/TT2kM9FC 脚本 works !某些文件名阻止您的正则表达式识别,因为在您的代码中缺少某些元素,从而阻止正确执行,阻止其操作。
  • 如果您再次阅读我的回答,您可能会注意到这句话:“...有可能基于示例数据的解决方案不适用于真实数据”。你的问题也没有“我的规范”表明当文件名没有给定的headS##Etail.pdf 格式时该怎么做!在这种情况下我的代码会做什么?很简单:它失败了。没有必要进行多次测试来证明这一点。在这种情况下代码应该做什么?好吧,如果你给出在这种情况下要做什么的规范,我很乐意相应地修改我的代码......
  • 重要提示:在我们的交流中,为了避免混淆,有一个共同的基础很重要。当“仅移动 The_Good_Wife_S06e15.pdf 文件”时,您的文件列表顺序错误。文件按照dir命令的顺序处理,所以The_Good_Wife_S06e15.pdf和...S06e22.pdf是前两个文件,TOCCO_ANGELO_4.pdf是第三个文件。这意味着我的代码总是 处理文件,直到出现第一个格式错误的文件(我不明白“无法​​识别的文件”是什么意思)。另外,请勿使用未出现在我的答案中的术语,例如“我的正则表达式 check-in”...
  • 嗯..我开始明白了。您能否修复您的代码,包括我的文件名列表中显示的用于扩展格式 headS##Etail.pdf 的示例中的此类规范?但是..可以绕过你的条件这意味着我的代码总是处理文件,直到出现第一个格式错误的文件避免在出现错误格式时停止脚本? 文件按照dir命令的顺序处理..ok,但是为​​什么不绕过坏格式继续编写我们所追求的好格式呢?谢谢,对不起我的英语
【解决方案2】:

获取正则表达式子字符串的最后一个实例的最简单方法是将字符串分成块并以相反的顺序处理这些块。

:: A script for grouping PDF files based on book series name
:: http://i.imgur.com/seh6p.gif

@echo off
setlocal enabledelayedexpansion
cls

:: Main Directory Containing PDF Directories (change this to suit your needs)
set "source_dir=.\test"

:: Move to source dir and process each folder, one at a time.
pushd "%source_dir%"

for /f "delims=" %%A in ('dir /b /a:d') do (
    call :getSeriesName "%%A" series_name

    mkdir !series_name! 2>nul

    REM If you want to do additional cleanup, change the copy to a move
    copy "%%A\*.pdf" !series_name! >nul
)

popd
exit /b

::------------------------------------------------------------------------------
:: Extracts the series name from the directory and changes spaces to periods
:: 
:: Arguments: %1 - The original book release name
::            %2 - The variable that will contain the returned value because
::                 batch doesn't actually have functions
:: Returns:   The series name and volume number
::------------------------------------------------------------------------------
:getSeriesName
:: Convert spaces to periods
set "raw_name=%~1"
set standard_name=!raw_name: =.!

:: Split the folder name into period-delimited tokens
set token_counter=0
:name_split
for /f "tokens=1,* delims=.-" %%B in ("!standard_name!") do (
    set name_part[!token_counter!]=%%B
    set standard_name=%%C
    set /a token_counter+=1
    goto :name_split
)

:: Get the volume number
for /l %%B in (0,1,!token_counter!) do (
    echo !name_part[%%B]!|findstr /R /C:"[sS][0-9][0-9]*[eE][0-9][0-9]*" >nul
    if !errorlevel! equ 0 (
        set /a name_end=%%B-1
        set volume_value=!name_part[%%B]!
        set volume_value=!volume_value:~0,3!
    )
)

:: Rebuild the series name
set "extracted_name="
for /l %%B in (0,1,!name_end!) do set "extracted_name=!extracted_name!!name_part[%%B]!."
set extracted_name=!extracted_name!!volume_value!

:: Purge the name_part array
for /l %%B in (0,1,!token_counter!) do set "name_part[%%B]="

:: Return the extracted name
set "%~2=!extracted_name!"

【讨论】:

  • 我为路径设置set "source_dir=C:\Users\Administrator\Desktop\A\" 为路径,然后我按.bat 但它返回我系统找不到指定的文件。您的解决方案很奇怪,因为我在父文件夹中有不同的空文件夹和 .pdf 文件,例如我有一个名为 Alfred Hitchcock 的文件夹,但你的脚本创建了一个名为 alfred 的新文件夹。为什么 ?你的意图是什么?解决方案 Aacini 是我所期望的。还是谢谢
  • @user3520363 - 为什么会有Alfred Hitchcock 文件夹?您是说子文件夹中有子文件夹吗?这与您的原始描述不符。我打算让您将每一集放在主目录中自己的文件夹中,并让每集目录包含 SxxExx 编号,因为这就是您所描述的。您对子目录只字未提。
  • @user3520363 - 作为参考,我的脚本将this 转换为this
  • mmm.. 我希望像你的第二张照片imgur.com/8po6Ljh。你的脚本没有启动。我将您的脚本更改为pastebin.com/meMuN6Z4。但它不执行。问题很简单:在 C:\Users\Administrator\Desktop\test2 我有这个示例文件名列表pastebin.com/GnwSvGtF。好吧,我双击 .bat 包含你的脚本但没有任何反应。该脚本也不会启动。是否有任何参数,所以我需要从 cmd 开始? P.S:我没有每个文件夹下的文件,是需要处理的文件吗,文件夹必须根据文件名生成,不好意思
  • 哦,您在同一目录中拥有所有单个文件。是的,我需要为此完全重写我的脚本。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-06
  • 1970-01-01
相关资源
最近更新 更多