I have about 12TB (and growing) library, distributed over 3 HDDs, of video files and I would like to back them up to an external harddrive. I am using Windows 10 Pro.
My backup drive has only 8TB and I would like to always backup the newest 8TB of video files. So far I have tried about 10 sync tools but none of them allowed me to copy files according to creation date.
Also with robocopy I haven't found a way to copy only the latest 8TB of files.
Any suggestions?
I have 2 batch scripts for you that do what you have asked for. The main difference between them is, that the 1st script is using where to locate all the files which will use the timestamp of the last change. To use another timestamp e.g. last access or time of creation you have to use the 2nd script I attached which uses dir.
1.
Batch script using where to locate files:
It takes minimum 2 arguments:
Usage: batch.bat <dst> <src_1> [<src_...> <src_n>]
It uses the where /r <src_n> * /t command which will build a list of all files in all subdirectories with a timestamp of the last change in the following format:
<size> <date> <time> <file name>
5397 11.07.2017 14:32:09 C:\Users\...\foo.txt
10860 12.07.2017 11:25:15 C:\Users\...\bar.log
The timestamp is of last change if you need the time of the creation or last access take the 2nd batch script below which is using dir as there is the possibility to choose between different timestamps.
This output will be written (without the column size) into a temporary file under the temp dir %TEMP% (will be deleted automatically after script) for every source that is passed via the argument list. The complete temporary file is sorted by the date and time, newest first.
This sorted output will be used to copy it into the destination folder.
Example:
Current directory in cmd is C:\...\Desktop):
batch.bat "backup_folder" "F:\folder" "F:\folder with space"
Current directory somewhere:
batch.bat "C:\...\Desktop\backup_folder" "F:\folder" "F:\folder with space"
The C:\...\Desktop\backup_folder will contain 2 folders folder and folder with space which contain all files of these source folders after the scripts operation.
In your case the batch script would copy only 8 TB of the newest files because then the drive will be full and the batch script will exit because it recognizes copy errors.
The batch script:
#echo off
setlocal enabledelayedexpansion
rem Check if at least 2 arguments are passed
set INVARGS=0
if [%1] == [] set INVARGS=1
if [%2] == [] set INVARGS=1
if %INVARGS% == 1 (
echo Usage: %0 ^<dst^> ^<src_1^> ^<src_...^> ^<src_n^>
goto :EOF
)
rem Store Carriage return character in CR (used for spinner function, see below)
for /f %%a in ('copy /Z "%~dpf0" nul') do set "CR=%%a"
rem Set temp file name
set "uniqueFile=%TEMP%\%0_%RANDOM%.tmp"
rem Set destination path and shift to next argument
set "dstpath=%~1"
shift
rem Store src_1 to src_n arguments into src array
set idx=0
:again
rem If %1 is blank, we are finished
if not [%1] == [] (
if not exist "%~1" (
echo The following source folder doesn't exist:
echo "%~1"!
echo The program will terminate!
goto :end
)
pushd "%~1"
set "src[%idx%]=!cd!"
if [!src[%idx%]:~-1!] == [\] (
set src[%idx%]=!src[%idx%]:~0,-1!
)
set /a idx=%idx%+1
popd
rem Shift the arguments and examine %1 again
shift
goto :again
)
rem Build command string:
rem where /r "src_1" * /t ^& where /r "src_..." * /t ^& where /r "src_n" * /t ^& break"
set "command="
for /F "tokens=2 delims==" %%s in ('set src[') do (
set "command=!command!where /r "%%s" * /t ^& "
)
set "command=!command!break"
echo "Command: ^<!command!^>"
rem Clear temp file and write files to copy in it
break>"%uniqueFile%"
for /f "tokens=2,3,4,* delims= " %%F in ('!command!') do (
call :spinner
echo %%F %%G %%H %%I>>"%uniqueFile%"
)
rem Open the built file list
echo File list will be opened...
%uniqueFile%
rem Ask user if copying should start
echo Should this files copied into %dstpath%? (Y/N)
set INPUT=
set /P INPUT=Answer?:%=%
if not [%INPUT%] == [y] (
if not [%INPUT%] == [Y] (
goto :end
)
)
set "dstpathPart="
rem Sort files newest first (last changed timestamp)
for /f "tokens=3,* delims= " %%F in ('type "%uniqueFile%" ^| sort /r') do (
rem Build destination part from source folder names
call :buildDestinationPath dstpathPart "%%F %%G"
rem Prepend the destination folder
set "dstFile=!dstpath!\!dstpathPart!"
rem Make directories that doesn't exists
for %%F in ("!dstFile!") do set "directory=%%~dpF"
if not exist "!directory!" ( mkdir "!directory!" )
rem Copy files and echo it
echo copy /y "!file!" "!dstFile!"
copy /y "!file!" "!dstFile!"
echo.
rem If copying failed exit program
if errorlevel 1 (
echo Copying failed... Maybe there is no more space on the disk!
echo The program will terminate!
goto :end
)
)
goto :end
rem Function definitions
:buildDestinationPath
for /F "tokens=2 delims==" %%s in ('set src[') do (
rem Go into folder e.g.: C:\src_1\ --> C:\
pushd "%%s"
cd ..
rem file contains full path of the where command
set "file=%~2"
rem Remove trailing space
if "!file:~-1!" == " " (
call set "file=%%file:~0,-1%%"
)
rem remove src folder from file to make it relative
rem e.g. C:\src_1\foo\bar\file1.txt --> src_1\foo\bar\file1.txt
call set "dstpathPart_temp=%%file:!cd!=%%"
rem Switch back to origin folder
popd
rem If the folder name changed the substring taken was right so take next
if not [!dstpathPart_temp!] == [!file!] (
set "%~1=!dstpathPart_temp!"
goto :next
)
)
:next
goto :EOF
:spinner
set /a "spinner=(spinner + 1) %% 4"
set "spinChars=\|/-"
<nul set /p ".=Building file list... !spinChars:~%spinner%,1!!CR!"
goto :EOF
:end
del "%uniqueFile%"
goto :EOF
2.
Batch script using dir to locate files:
It takes one more argument so that you need minimum 3 arguments:
Usage: batch.bat <timeordering> <dst> <src_1> [<src_...> <src_n>]
It will generate the same list as explained above but with the help of the dir command. The dir command takes the following parameter which is the <timeordering> parameter of the script:
/tc Creation
/ta Last access
/tw Last written
The batch script:
#echo off
setlocal enabledelayedexpansion
rem Check if at least 2 arguments are passed
set INVARGS=0
if [%1] == [] set INVARGS=1
if [%2] == [] set INVARGS=1
if [%3] == [] set INVARGS=1
if %INVARGS% == 1 (
echo Usage: %0 ^<timeordering^> ^<dst^> ^<src_1^> ^<src_...^> ^<src_n^>
goto :EOF
)
rem Store Carriage return character in CR (used for spinner function, see below)
for /f %%a in ('copy /Z "%~dpf0" nul') do set "CR=%%a"
rem Set temp file name
set "uniqueFile=%TEMP%\%0_%RANDOM%.tmp"
rem Set timeordering and destination path and shift to next argument
set "timeordering=%~1"
shift
set "dstpath=%~1"
shift
rem Store src_1 to src_n arguments into src array
set idx=0
:again
rem If %1 is blank, we are finished
if not [%1] == [] (
if not exist "%~1" (
echo The following source folder doesn't exist:
echo "%~1"!
echo The program will terminate!
goto :end
)
pushd "%~1"
set "src[%idx%]=!cd!"
if [!src[%idx%]:~-1!] == [\] (
set src[%idx%]=!src[%idx%]:~0,-1!
)
set /a idx=%idx%+1
popd
rem Shift the arguments and examine %1 again
shift
goto :again
)
rem Clear temp file and write files to copy in it
break>"%uniqueFile%"
rem call commands with all sources:
rem call :getFileInformation /TC "src_1\*"
rem /TW
rem /TA
for /F "tokens=2 delims==" %%s in ('set src[') do (
call :getFileInformation %timeordering% "%%s\*" "%uniqueFile%""
)
rem Open the built file list
echo Unsorted file list will be opened...
%uniqueFile%
rem Ask user if copying should start
echo Should this files copied into %dstpath%? (Y/N)
set INPUT=
set /P INPUT=Answer?:%=%
if not [%INPUT%] == [y] (
if not [%INPUT%] == [Y] (
goto :end
)
)
set "dstpathPart="
rem Sort files newest first (last changed timestamp)
for /f "tokens=3,* delims= " %%F in ('type "%uniqueFile%" ^| sort /r') do (
rem Build destination part from source folder names
call :buildDestinationPath dstpathPart "%%F %%G"
rem Prepend the destination folder
set "dstFile=!dstpath!\!dstpathPart!"
rem Make directories that doesn't exists
for %%F in ("!dstFile!") do set "directory=%%~dpF"
if not exist "!directory!" ( mkdir "!directory!" )
rem Copy files and echo it
echo copy /y "!file!" "!dstFile!"
copy /y "!file!" "!dstFile!"
echo.
rem If copying failed exit program
if errorlevel 1 (
echo Copying failed... Maybe there is no more space on the disk!
echo The program will terminate!
goto :end
)
)
goto :end
rem Function definitions
:buildDestinationPath
for /F "tokens=2 delims==" %%s in ('set src[') do (
rem Go into folder e.g.: C:\src_1\ --> C:\
pushd "%%s"
cd ..
rem file contains full path of the where command
set "file=%~2"
rem Remove trailing space
if "!file:~-1!" == " " (
call set "file=%%file:~0,-1%%"
)
rem remove src folder from file to make it relative
rem e.g. C:\src_1\foo\bar\file1.txt --> src_1\foo\bar\file1.txt
call set "dstpathPart_temp=%%file:!cd!=%%"
rem Switch back to origin folder
popd
rem If the folder name changed the substring taken was right so take next
if not [!dstpathPart_temp!] == [!file!] (
set "%~1=!dstpathPart_temp!"
goto :next
)
)
:next
goto :EOF
:getFileInformation
for /f "delims=" %%a in ('dir /s /b /a-d %~1 "%~2"') do (
for /f "tokens=1,2 delims= " %%b in ('dir %~1 "%%a" ^| findstr /l /c:"%%~nxa"') do (
echo %%b %%c %%a>>"%~3"
call :spinner
)
)
goto :EOF
:spinner
set /a "spinner=(spinner + 1) %% 4"
set "spinChars=\|/-"
<nul set /p ".=Building file list... !spinChars:~%spinner%,1!!CR!"
goto :EOF
:end
del "%uniqueFile%"
goto :EOF
Related
I'm trying to write a batch file that will extract a zip file. (This part works) It should read the restoretranslation.conf file, which consists of two comma separated values. The first value is the file name, and the second is the file path where the respective file would reside, (if existing).
If value one exists in the extracted zip directory and is defined with a path in the conf file, it should prompt the user if they want to replace the file. If yes, backup the file in the path in the second value. (%%b in the conf file) to %%b\original_%%a. we should then replace the file.
It seems like most of my variables are not being parsed correctly. Could someone give me some pointers?
Here's an example of the data in the configuration file:
license.xml,C:\Program Files (x86)\programname
Script:
#echo on
rem Set the directory where the ZIP files are located
set zipfolder=%~dp0
setlocal enabledelayedexpansion
rem Get a list of all ZIP files in the directory that start with "RTSBACKUP-"
set cnt=0
for /f "delims=" %%a in ('dir /b /a-d "%zipfolder%RTSBACKUP-*.zip"') do (
set /A cnt+=1
set "zipfile=%%a"
set "zipfile=!zipfile:~0!"
echo !cnt! - !zipfile!
)
rem Prompt the user to select a file to extract
set /p "fileNum=Enter the number of the file you want to extract: "
rem Extract the selected file
set cnt=0
for /f "delims=" %%b in ('dir /b /a-d "%zipfolder%RTSBACKUP-*.zip"') do (
set /A cnt+=1
if !cnt!==%fileNum% (
set "zipfile=%%b"
echo %zipfile%
pause
set "zipfile=!zipfile:~0!"
start /min "***Compressing backup files...*** ***Do not close this window.***" /wait powershell Expand-Archive -LiteralPath "%zipfolder%%zipfile%" -DestinationPath "%zipfolder%%zipfile:~0,-4%"
echo The file %zipfile% has been extracted successfully!
goto :break
)
)
endlocal disabledelayedexpansion
:break
set extractedfolder=%zipfolder%!zipfile:~0,-4!\!zipfile:~0,-4!\
rem Set the location of the restoretranslation.conf file
set "resttranslationfile=%~dp0restoretranslation.conf"
rem Loop through all files in the extractedfolder
for /f "delims=" %%i in ('dir /b /a-d "%extractedfolder%*.*"') do (
set "file=%%~i"
rem Loop through the resttranslation.conf file
for /f "tokens=1,2 delims=," %%a in ("%resttranslationfile%") do (
if /i "!FILE!"=="%%a" (
set "dirto=%%b"
rem Ask for confirmation before restoring the file
set /p confirm=Do you want to restore %file% to %dirto%? (^Y/N^)^:
if /i "%confirm%"=="y" (
rem Backup the original file
echo Backing up original file to !extractedfolder!original_%file%
if exist "%dirto%\%file%" (
copy "%dirto%\%file%" "!extractedfolder!original_%file%"
)
rem Copy the backup file to the specified destination
echo Restoring !file! to %%b
copy "!extractedfolder!!file!" "%%b\"
)
)
)
)
pause
Output:
C:\Tyler>rem Set the directory where the ZIP files are located
C:\Tyler>set zipfolder=C:\Tyler\
C:\Tyler>setlocal enabledelayedexpansion
C:\Tyler>rem Get a list of all ZIP files in the directory that start
with "RTSBACKUP-"
C:\Tyler>set cnt=0
C:\Tyler>for /F "delims=" %a in ('dir /b /a-d
"C:\Tyler\RTSBACKUP-*.zip"') do ( set /A cnt+=1 set "zipfile=%a" set
"zipfile=!zipfile:~0!" echo !cnt! - !zipfile! )
C:\Tyler>( set /A cnt+=1 set
"zipfile=RTSBackup-RSC-ERIELAB2-01202023-171815.zip" set
"zipfile=!zipfile:~0!" echo !cnt! - !zipfile! ) 1 -
RTSBackup-RSC-ERIELAB2-01202023-171815.zip
C:\Tyler>rem Prompt the user to select a file to extract
C:\Tyler>set /p "fileNum=Enter the number of the file you want to
extract: " Enter the number of the file you want to extract: 1
C:\Tyler>rem Extract the selected file
C:\Tyler>set cnt=0
C:\Tyler>for /F "delims=" %b in ('dir /b /a-d
"C:\Tyler\RTSBACKUP-*.zip"') do ( set /A cnt+=1 if !cnt! == 1 ( set
"zipfile=%b" echo RTSBackup-RSC-ERIELAB2-01202023-171815.zip pause
set "zipfile=!zipfile:~0!" start /min "***Compressing backup
files...*** ***Do not close this window.***" /wait powershell
Expand-Archive -LiteralPath
"C:\Tyler\RTSBackup-RSC-ERIELAB2-01202023-171815.zip" -DestinationPath
"C:\Tyler\RTSBackup-RSC-ERIELAB2-01202023-171815" echo The file
RTSBackup-RSC-ERIELAB2-01202023-171815.zip has been extracted
successfully! goto :break ) )
C:\Tyler>( set /A cnt+=1 if !cnt! == 1 ( set
"zipfile=RTSBackup-RSC-ERIELAB2-01202023-171815.zip" echo
RTSBackup-RSC-ERIELAB2-01202023-171815.zip pause set
"zipfile=!zipfile:~0!" start /min "***Compressing backup files...***
***Do not close this window.***" /wait powershell Expand-Archive -LiteralPath "C:\Tyler\RTSBackup-RSC-ERIELAB2-01202023-171815.zip" -DestinationPath "C:\Tyler\RTSBackup-RSC-ERIELAB2-01202023-171815" echo The file RTSBackup-RSC-ERIELAB2-01202023-171815.zip has been
extracted successfully! goto :break ) )
RTSBackup-RSC-ERIELAB2-01202023-171815.zip Press any key to continue .
. . The file RTSBackup-RSC-ERIELAB2-01202023-171815.zip has been
extracted successfully
C:\Tyler>set extractedfolder=C:\Tyler\!zipfile:~0,-4!\!zipfile:~0,-4!\
C:\Tyler>rem Set the location of the restoretranslation.conf file
C:\Tyler>set "resttranslationfile=C:\Tyler\restoretranslation.conf"
C:\Tyler>rem Loop through all files in the extractedfolder
C:\Tyler>for /F "delims=" %i in ('dir /b /a-d
"C:\Tyler\RTSBackup-RSC-ERIELAB2-01202023-171815\RTSBackup-RSC-ERIELAB2-01202023-171815\*.*"')
do ( set "file=%~i" rem Loop through the resttranslation.conf file
for /F "tokens=1,2 delims=," %a in
("C:\Tyler\restoretranslation.conf") do (if /I "!FILE!" == "%a" ( set
"dirto=%b" rem Ask for confirmation before restoring the file set /p
confirm=Do you want to restore to ? (Y/N): if /I "" == "y" ( rem
Backup the original file echo Backing up original file to
!extractedfolder!original_ if exist "\" (copy "\"
"!extractedfolder!original_" ) rem Copy the backup file to the
specified destination echo Restoring !file! to %b copy
"!extractedfolder!!file!" "%b\" ) ) ) )
C:\Tyler>( set "file=License.xml" rem Loop through the
resttranslation.conf file for /F "tokens=1,2 delims=," %a in
("C:\Tyler\restoretranslation.conf") do (if /I "!FILE!" == "%a" ( set
"dirto=%b" rem Ask for confirmation before restoring the file set /p
confirm=Do you want to restore to ? (Y/N): if /I "" == "y" ( rem
Backup the original file echo Backing up original file to
!extractedfolder!original_ if exist "\" (copy "\"
"!extractedfolder!original_" ) rem Copy the backup file to the
specified destination echo Restoring !file! to %b copy
"!extractedfolder!!file!" "%b\" ) ) ) )
C:\Tyler>(if /I "!FILE!" == "C:\Tyler\restoretranslation.conf" ( set
"dirto=" rem Ask for confirmation before restoring the file set /p
confirm=Do you want to restore to ? (Y/N): if /I "" == "y" ( rem
Backup the original file echo Backing up original file to
!extractedfolder!original_ if exist "\" (copy "\"
"!extractedfolder!original_" ) rem Copy the backup file to the
specified destination echo Restoring !file! to copy
"!extractedfolder!!file!" "\" ) ) )
I started using batch commands last week and I've reached a real obstacle with a script I made.
What I want to do
Move a PDF file from C:\Users\JK\Documents\reports PDFs into pre-made subfolders in the destination W:\Departments\QA\cases.
For example the script would move 2223 report.pdf to W:\Departments\QA\cases\2201 - 2300\2223
What I tried
I made a script based off the answer in this thread
cls
#pushd %~dp0
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "SourceDir=C:\Users\JK\Documents\reports PDFs"
set "DestDir=W:\Departments\QA\cases\"
for /F "eol=| delims=" %%A in ('dir /B /A-D-H "%SourceDir%\*.pdf" 2^>nul') do (
for /F "eol=| tokens=1" %%B in ("%%~nA") do (
for /D %%C in ("%DestDir%\%%B*") do move /Y "%SourceDir%\%%A" "%%C\"
)
)
endlocal
popd
pause
Where I am stuck
How could I add subfolders or account for them in the destination directory?
FYI, I also tried adding a wildcard symbol at the end of the destination directory by changing %DestDir%\%%B to %DestDir%\*\%%B*.
I would probably accomplish the task with the following script (see all the explanatory rem remarks):
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_SOURCE=C:\Users\JK\Documents\reports PDFs" & rem // (source directory; `.` or `` is current, `%~dp0.` is script parent)
set "_TARGET=W:\Departments\QA\cases" & rem // (target directory; `.` or `` is current, `%~dp0.` is script parent)
set "_SUBDIR=#" & rem // (set to non-blank value in order to create individual sub-directories)
set "_FMASK=????*.pdf" & rem // (pattern to match source files)
set "_DMASK=???? - ????*" & rem // (pattern to match target directories)
set "_FFIL1=^[0123456789][0123456789][0123456789][0123456789] .*\.pdf$" & rem // (filter 1 for source files)
set "_FFIL2=^[0123456789][0123456789][0123456789][0123456789]\.pdf$" & rem // (filter 2 for source files)
set "_DFIL1=^[0123456789][0123456789][0123456789][0123456789] - [0123456789][0123456789][0123456789][0123456789] .*$"
set "_DFIL2=^[0123456789][0123456789][0123456789][0123456789] - [0123456789][0123456789][0123456789][0123456789]$"
rem // Change into source directory:
pushd "%_SOURCE%" && (
rem // Iterate through all files matching the specified pattern and filters:
for /F "eol=| delims=" %%F in ('
dir /B /A:-D-H-S "%_FMASK%" ^| findstr /I /R /C:"%_FFIL1%" /C:"%_FFIL2%"
') do (
rem // Store full path of currently iterated file:
set "FILE=%%~fF"
rem // Extract the leading numeric part of the file name:
for /F "eol=| delims= " %%N in ("%%~nF") do (
rem // Store the numeric part:
set "NUM=%%N"
rem /* Remove any leading zeros from the numeric part of the file name, because
rem such cause the number to be unintentionally interpreted as octal: */
set /A "INT=0" & for /F "eol=| tokens=* delims=0" %%Z in ("%%N") do 2> nul set /A "INT=%%Z"
)
rem // Change into target directory:
pushd "%_TARGET%" && (
rem // Iterate through all directories matching the specified pattern and filters:
for /F "eol=| delims=" %%D in ('
cmd /V /C 2^> nul dir /B /A:D-H-S "!_DMASK:|=%%I!" ^| findstr /I /R /C:"%_DFIL1%" /C:"%_DFIL2%"
') do (
rem // Store name of currently iterated directory:
set "TDIR=%%D"
rem // Extract first (from) and second (to) numeric parts of directory names:
for /F "eol=| tokens=1-2 delims=- " %%S in ("%%D") do (
rem // Remove any leading zeros from first (from) numeric part:
set /A "FRM=0" & for /F "eol=| tokens=* delims=0" %%Z in ("%%S") do set /A "FRM=%%Z"
rem // Remove any leading zeros from second (to) numeric part:
set /A "TOO=0" & for /F "eol=| tokens=* delims=0" %%Z in ("%%T") do set /A "TOO=%%Z"
)
rem // Toggle delayed variable expansion to avoid trouble with `!`:
setlocal EnableDelayedExpansion
rem /* Do integer comparisons to check whether the numeric part of the file name
rem lies within the range given by the directory name (from/to): */
if !INT! geq !FRM! if !INT! leq !TOO! (
rem // Numeric part of file name lies within range, hence try to move file:
if defined _SUBDIR (
2> nul md "!TDIR!\!NUM!"
ECHO move "!FILE!" "!TDIR!\!NUM!\"
) else (
ECHO move "!FILE!" "!TDIR!\"
)
)
endlocal
)
rem // Return from target directory:
popd
)
)
rem // Return from source directory:
popd
)
endlocal
exit /B
You may need to adapt a few constants to your situation in the section commented with Define constants here: at the top.
After having tested the script for the correct output, remove the upper-case ECHO commands in front of the move commands! In order to avoid multiple 1 file(s) moved. messages, replace these ECHO commands by > nul.
I have this code
#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
I use Command Prompt in this way to create folders and move files inside from folder1 to folder2
cd /D "C:\Users\Administrator\Downloads\"
"C:\Users\Administrator\Downloads\test1\build-folder-hierarchy.bat" "C:\Users\Administrator\Downloads\test2" "*.mkv"
What is the problem ?
But I want to get a folder consolidation from files moving, not generates same number of folders from files
The.Race.Corsa.Mortale.2019.S1E02.Episodio2.HDTV.AAC.iTA.X264-ARSENAL.mkv
The.Race.Corsa.Mortale.2019.S1E01.Episodio1.HDTV.AAC.iTA.X264-ARSENAL.mkv
The.Feed.1x05.Episodio.5.ITA.DLMux.x264-UBi.mkv
The.Feed.1x04.Episodio.4.ITA.DLMux.x264-UBi.mkv
The.Feed.1x03.Episodio.3.ITA.DLMux.x264-UBi.mkv
The.Feed.1x02.Episodio.2.ITA.DLMux.x264-UBi.mkv
The.Feed.1x01.Episodio.1.ITA.DLMux.x264-UBi.mkv
Swamp.Thing.1x10.La.Resa.Dei.Conti.ITA.DLMux.x264-UBi.mkv
Volevo.Fare.La.Rockstar.1x11.Confusione.ITA.WEBRip.x264-UBi.mkv
Volevo.Fare.La.Rockstar.1x07.Tabu.ITA.WEBRip.x264-UBi.mkv
Volevo.Fare.La.Rockstar.1x01.Buon.Compleanno.Olly.ITA.WEBRip.x264-UBi.mkv
Volevo Fare La Rockstar 1x12 La Tribu Ita Webrip x264-Ubi.mkv
Virgin.River.1x10.Finali.inattesi.720p.iTA.AAC.DLRip.x265.-.T7.mkv
Virgin.River.1x07.A.dire.il.vero.720p.iTA.AAC.DLRip.x265.-.T7.mkv
Virgin.River.1x04.Un.Cuore.Ferito.iTA.AC3.WEBMux.x264-ADE.CreW.mkv
Virgin.River.1x01.La.Vita.Continua.iTA.AC3.WEBMux.x264-ADE.CreW.mkv
Tre.Giorni.Di.Natale.1x03.Episodio.3.iTA.AC3.WEBMux.x264-ADE.CreW.mkv
Tre.Giorni.Di.Natale.1x01.Episodio.1.iTA.AC3.WEBMux.x264-ADE.CreW.mkv
But I want to get folders and move files in this way
├─The Race Corsa Mortale [folder]
│ ├─The.Feed.1x05.Episodio.5.ITA.DLMux.x264-UBi [file]
│ ├─The.Feed.1x04.Episodio.4.ITA.DLMux.x264-UBi [file]
└─ ....
├─Virgin River [folder]
│ └─Virgin.River.1x07.A.dire.il.vero.720p.iTA.AAC.DLRip.x265 [file]
:
I try also to use this batch script but it doesn't work: I click on in via explorer but is like disactivated (I use Windows Server 2012)
#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 *.mkv files
for %%f in (*.mkv) 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
I accept also Powershell solutions
EDIT: Portion of the file name that I need is that before of S#E##, #x## .#x##, .#x#, .#x## and similar
I would probably use the following script (please consult all the explanatory rem remarks):
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_ROOT=%~1" & rem /* (target directory; `.` is current working directory, `%~dp0.` is
rem parent of this script, `%~1` is first command line argument) */
set _MASKS="*.mkv" & rem // (space-separated list of quoted file patterns)
set _SEPS=" " "." & rem // (space-separated list of quoted separators)
rem /* Specify multiple `findstr` search strings, including the prefix `/C:`, as you would
rem directly state them at the `findstr` command, which are used to match the particular
rem sub-strings of the file names that are used to find the part where to split them at
rem and to derive the name of the sub-directory where to move the respective file to: */
set _FILTERS=/C:"^S[0123456789][0123456789]*E[0123456789][0123456789]*$" ^
/C:"^[0123456789][0123456789]*x[0123456789][0123456789]*$"
rem // Change into root directory:
pushd "%_ROOT%" && (
rem // Loop through all matching files:
for /F "delims= eol=|" %%F in ('dir /B /A:-D-H-S %%_MASKS%%') do (
rem // Store current file name and extension, initialise some auxiliary variables:
set "NAME=%%~nF" & set "EXT=%%~xF" & set "SDIR= " & set "FLAG=#"
rem // Toggle delayed expansion to avoid trouble with `!` (also later on):
setlocal EnableDelayedExpansion
rem // Replace all predefined separators by spaces:
for %%S in (!_SEPS!) do set "NAME=!NAME:%%~S= !"
rem // Loop through all space-separated (quoted) items of the file name:
for %%I in ("!NAME: =" "!") do (
rem // Skip the loop body when a sub-string has already been found before:
if defined FLAG (
rem // Store current portion of the file name:
endlocal & set "ITEM=%%~I"
rem // Use `findstr` to match against the predefined sub-strings:
cmd /V /C echo(!ITEM!| > nul findstr /R /I %_FILTERS% && (
rem // Match encountered, hence skip this and the remaining items:
set "FLAG="
) || (
rem /* No match found, so append the current item to the name of the
rem sub-directory where the file is supposed to be moved then: */
setlocal EnableDelayedExpansion
for /F "delims=" %%E in ("!SDIR!!ITEM! ") do (
endlocal & set "SDIR=%%E"
)
)
setlocal EnableDelayedExpansion
)
)
rem // Process only file naes where sub-directory names could be derived from:
if not defined FLAG if not "!SDIR:~1,-1!"=="" (
rem // Create sub-directory, if not yet existing:
ECHO 2> nul mkdir "!SDIR:~1,-1!"
rem // Move current file into the sub-directory (but do not overwrite in case):
ECHO if not exist "!SDIR:~1,-1!\!NAME!!EXT!" > nul move "!NAME!!EXT!" "!SDIR:~1,-1!\"
)
endlocal
)
popd
)
endlocal
exit /B
Supposing the script is called consolidate.bat and the target directory is %UserProfile%\Downloads, call the script like this:
consolidate.bat "%UserProfile%\Downloads"
After having tested for the correct output, remove the upper-case ECHO commands in front of the mkdir and move commands!
Assuming we can split the file name on the Digits in the name, this should do the needful.
I put a pause in, inspect the output and make sure that it is giving you the right info before clicking enter.
#(SETLOCAL EnableDelayedExpansion
ECHO OFF
REM SET "_SrcFolder=C:\Users\Administrator\Downloads\test1"
REM SET "_DstFolder=C:\Users\Administrator\Downloads\test2"
REM SET "FileGlob=*.mkv"
SET "_SrcFolder=C:\Admin"
SET "_DstFolder=C:\Admin\test2"
SET "FileGlob=*.txt"
)
CALL :Main
( ENDLOCAL
EXIT /B
)
:Main
FOR %%A IN (
"%_SrcFolder%\%FileGlob%"
) DO (
CALL :Process "%%~nA" "%%~xA" "%%~fA"
)
GOTO :EOF
:Process
SET "_OLDName=%~1"
FOR /F "Tokens=1 Delims=0123456789" %%a IN ("%~1") DO (
SET "_NewFolder=%%a"
)
SET "_NewName=!_OLDName:%_NewFolder%=!"
ECHO._OLDName=%_OLDName%.%~2
ECHO._NewFolder=%_NewFolder%
ECHO._NewName=%_NewName%.%~2
REM pause
ECHO.
ECHO. We will now do the following if you press any key:
ECHO. MD "%_DstFolder%\%_NewFolder%\"
ECHO. COPY "%~3" "%_DstFolder%\%_NewFolder%\%_NewName%%~2"
ECHO.
PAUSE
MD "%_DstFolder%\%_NewFolder%\"
COPY "%~3" "%_DstFolder%\%_NewFolder%\%_NewName%%~2"
GOTO :EOF
I have a folder with many .txt files. I would like to find string "X" in all of these files then I would like to copy the found strings into .txt files into a different folder.
So far I have tried :
#echo on
findstr /m "X" "%userprofile%\Desktop\New_Folder\New_Folder\*.txt"
if %errorlevel%==0 do (
for %%c in (*.txt) do (
type %%c >> "%UserProfile%\Desktop\New_Folder\%%~nc.txt"
pause
I do not understand the output %%~nc.txt part it's suppost to copy the changed .txt files to a new folder with the same name.
I would like to point out that string "X" is found in different places in the .txt file.
This batch file can did the trick (-_°)
So, just give a try : ScanfilesWordSearch_X.bat
#ECHO OFF
::******************************************************************************************
Title Scan a folder and store all files names in an array variables
SET "ROOT=%userprofile%\Desktop"
Set "NewFolder2Copy=%userprofile%\Desktop\NewCopyTxtFiles"
SET "EXT=txt"
SET "Count=0"
Set "LogFile=%~dp0%~n0.txt"
set "Word2Search=X"
SETLOCAL enabledelayedexpansion
REM Iterates throw the files on this current folder and its subfolders.
REM And Populate the array with existent files in this folder and its subfolders
For %%a in (%EXT%) Do (
Call :Scanning "%Word2Search%" "*.%%a"
FOR /f "delims=" %%f IN ('dir /b /s "%ROOT%\*.%%a"') DO (
( find /I "%Word2Search%" "%%f" >nul 2>&1 ) && (
SET /a "Count+=1"
set "list[!Count!]=%%~nxf"
set "listpath[!Count!]=%%~dpFf"
)
) || (
( Call :Scanning "%Word2Search%" "%%~nxf")
)
)
::***************************************************************
:Display_Results
cls & color 0B
echo wscript.echo Len("%ROOT%"^) + 20 >"%tmp%\length.vbs"
for /f %%a in ('Cscript /nologo "%tmp%\length.vbs"') do ( set "cols=%%a")
If %cols% LSS 50 set /a cols=%cols% + 20
set /a lines=%Count% + 10
Mode con cols=%cols% lines=%lines%
ECHO **********************************************************
ECHO Folder:"%ROOT%"
ECHO **********************************************************
If Exist "%LogFile%" Del "%LogFile%"
rem Display array elements and save results into the LogFile
for /L %%i in (1,1,%Count%) do (
echo [%%i] : !list[%%i]!
echo [%%i] : !list[%%i]! -- "!listpath[%%i]!" >> "%LogFile%"
)
(
ECHO.
ECHO Total of [%EXT%] files(s^) : %Count% file(s^) that contains the string "%Word2Search%"
)>> "%LogFile%"
ECHO(
ECHO Total of [%EXT%] files(s) : %Count% file(s)
echo(
echo Type the number of file that you want to explore
echo(
echo To save those files just hit 'S'
set /p "Input="
For /L %%i in (1,1,%Count%) Do (
If "%INPUT%" EQU "%%i" (
Call :Explorer "!listpath[%%i]!"
)
IF /I "%INPUT%"=="S" (
Call :CopyFiles
)
)
Goto:Display_Results
::**************************************************************
:Scanning <Word> <file>
mode con cols=75 lines=3
Cls & Color 0E
echo(
echo Scanning for the string "%~1" on "%~2" ...
goto :eof
::*************************************************************
:Explorer <file>
explorer.exe /e,/select,"%~1"
Goto :EOF
::*************************************************************
:MakeCopy <Source> <Target>
If Not Exist "%~2\" MD "%~2\"
Copy /Y "%~1" "%~2\"
goto :eof
::*************************************************************
:CopyFiles
cls
mode con cols=80 lines=20
for /L %%i in (1,1,%Count%) do (
echo Copying "!list[%%i]!" "%NewFolder2Copy%\"
Call :MakeCopy "!listpath[%%i]!" "%NewFolder2Copy%">nul 2>&1
)
Call :Explorer "%NewFolder2Copy%\"
Goto:Display_Results
::*************************************************************
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "destdir=U:\destdir"
SET "mystring=x"
FOR %%a IN ("%sourcedir%\*.txt") DO FINDSTR "%mystring%" "%%a">nul&IF NOT ERRORLEVEL 1 FINDSTR "%mystring%" "%%a">"%destdir%\%%~nxa"
GOTO :EOF
You would need to change the settings of sourcedir and destdir to suit your circumstances and set mystring appropriately, noting that you may have to adjust the findstr switches to accomodate case, literal and space-in-target-string.
Naturally, you could code sourcedir etc. directly as literals, but doing it this way means that the relevant strings need only be changed in one place.
You are close, but checking the ErrorLevel of findstr does not make sense here as this reflects the overall result, that is, ErrorLevel is set to 0 in case any of the files contain the search string.
I would parse the output of findstr /M using a for /F loop and copy the returned files in the body:
for /F "eol=| delims=" %%F in ('
findstr /M /I /C:"X" "%USERPROFILE%\Desktop\New_Folder\New_Folder\*.txt"
') do (
copy "%%F" "%USERPROFILE%\Desktop\New_Folder\"
)
This copies all those files which contain the literal search string (in a case-insensitive manner).
I am trying to put a batch together to move all zip files back one directory from the current directory in a recursive move where I specify the search directory from the parent.
In example, the current directory is download and the sub to recursive search is a command line parameter.
I then want to move the *.zip back one directory from download. I don't want to search in any other directory other than the one I specify.
>movezipdir junk 2009
This outputs junk 2009. Then junk was unexpected at this time.
Here's what I have but the for loop doesn't like the variable with spaces...
#echo off
IF %1.==. GOTO No1
set DirName=%*
echo %DirName%
For /d %DirName% in ( *.* ) do (
For /d %%e in (""%DirName%"\*") do (
rem move /Y "%%e\*.zip" "%CD%\.."
echo %DirName%
rem rd /S /Q "%%e"
)
rem rd /S /Q %DirName%
)
GOTO End1
:No1
ECHO No Directory Specified
GOTO End1
:End1
It would be great if someone could point me in the right direction. Thanks. Ken
#echo off
rem :: check if the args is not nul
if [%1] == [] (
goto error
) else (
for /f "usebackq tokens=1*" %%i in ('echo %*') do (
set "dirname=%%~i"
)
)
rem check if the specified args correspond to a directory
if exist "%dirname%\nul" echo %dirname% it's a directory || goto error
set /a c=1
setlocal EnableDelayedExpansion
for /f "tokens=* delims=" %%a in ('dir /b /s /a-d "%dirname%\*.txt"') do (
rem usage: move [{/y | /-y}] [Source] [Target]
rem https://technet.microsoft.com/en-us/library/cc772528.aspx
rem http://ss64.com/nt/move.html
rem %cd% here are redundant because when target are omitted,
rem the target are always the current directory
echo move /-y "%%a" "%cd%"
rem break loop after 5 iterations.
rem You can remove it if the test are Okay
if [!c!] equ [5] goto break_loop
set /a c+=1
)
:break_loop
rem usage: RD [/S] [/Q] [drive:]path
echo rd /s /q %dirname%
exit /b 0
:error
echo Error: No directory specified or invalid arguments
echo Usage: %~0 ^<full path of the directorys^>
echo Example: %~0 c:\user\janne\MyDocuments
exit /b 0