Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

powershell - Order and move files into directories based on some filenames pattern

To move files into folders I use this script

@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

To use script I must

1- open cmd
2- to execute batch i have to

cd C:UsersAdministratorDesktopT
"C:UsersAdministratorDesktopTuild-folder-hierarchy.bat" "C:UsersAdministratorDesktopT" "*.pdf"

But problem what is ?

For each .pdf file batch creates a relative folder but I don't want it creates folders in that way. Look 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]

What I want instead ?

├─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]
:

Just an example name to understand how .pdf files name are formatted

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

Usually pdf files name are formatted in this way [pattern]

s01
s01e1
s1
s1e1
s1e01
s1e01-10

character, like the e and s are almost always present within these patterns name general form should be

sxx
sxxex
sx
sxex
sxexx
sxexx-xx

X is a number, case for letter s and e is irrilevant

Powershell solution is well accepted for answer.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The easiest way to get the last instance of a regex substring is to break the string into chunks and process the chunks in reverse order.

:: 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=.est"

:: 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!"

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...