Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Speed and time issue in cmd programming

Recently there where a question about moving many files with user predefined file type extension from one folder to many different folders that are instantly created upon a key string (YEAR) inside the name of the files. Also, when moving to newly created folders, files should be saved without user predefined file type extension (File name 2016.myextension.txt > File name 2016.txt). I have been interested into this problem, so I have created simple cmd program.

There Are Two Problems :

Program works correctly but it is too slow.

Is there any way to make it run faster?

The ECHO %TIME% command inside the for /l %%A in (1900,1,2099) loop, look at the end of the program code, always returns the same time value.

Is there any way to make it return correct current system time?

Here is the program code :

rem program start
rem 
rem use double % for cmd line parameters when generating .bat
rem use single % for cmd line parameters for direct cmd execution 
rem use ^ for cmd line brake
rem
rem
rem change command prompt attributes
rem 
echo off
mode con:cols=80 lines=40
title Program
color 0A
cls
echo.
echo Program start running at... %TIME%
echo.
rem set local variables value 
setlocal EnableDelayedExpansion EnableExtensions
set old_folder_path=C:\Torrent_files\
set new_folder_path=C:\Torrent_movies\
set folder_path=C:\Torrent_movies\Year_
set f1=.
set f2=.
set list_path_extension=C:\Torrent_movies\Torrent_list.txt
set extension=.torrent
rem create root folder for new movie folders
if not exist %new_folder_path% (echo Creating Torrent_movies folder... && ^
md %new_folder_path% && echo Done at... %TIME%)
echo.
rem set current directory to new_folder_path
cd %new_folder_path%
rem create new list 
rem of torrent files inside the folder
echo Creating empty List of files...
echo. > %list_path_extension%
echo Done at... %TIME%
echo.
rem Fill List of files
echo Filling List with file names...
for /r %old_folder_path% %%T in (*%extension%) do (^
set f1=%%T && ^
set f2=!f1:%old_folder_path%=! && ^
echo !f2! >> %list_path_extension%)
echo Done at... %TIME%
echo.
rem search for year inside file paths saved in Torrent_list.txt file
rem by using for loop, where value of cmd parameter 
rem A goes from year 1900 up to 2099, 
rem if there is match between string value of A as a regular expression, 
rem and string inside file path, create new folder for that year
rem else skip
echo Moving files
for /l %%A in (1900,1,2099) do (^
for /f "tokens=*" %%G in ('findstr /r "\<%%A" %list_path_extension%') do (^
(if exist %folder_path%%%A (echo.) ^
else (md %folder_path%%%A && echo %folder_path%%%A   Folder created)) && ^
echo Moving file %%G && set f1=%%G && set f2=!f1:%extension%=! && ^
move "%old_folder_path%%%G" "%folder_path%%%A\!f2!" && echo Done at... %TIME% && echo.))
rem list current directory to show changes
dir %new_folder_path%
echo.
echo Program finished at...%TIME%
echo.
pause
rem program end

According to all answers given to my question I have made this program that completely solves the problem. Any suggestions for improvement are welcome.

@echo off
    rem
    rem Program solves next problem :
    rem
    rem Inside one folder there are many files.
    rem Files have different file type.
    rem File name can contain :
    rem only one or none, YYYY (year) string,
    rem key word or user predefined file type 
    rem
    rem exmpl :
    rem 
    rem Root folder path : 
    rem
    rem C:\My_files_type_of_backup
    rem
    rem Folder contains :
    rem
    rem File 1 video (1998).backup.avi
    rem File 2 painting 2016.backup.bmp
    rem File 3 mp3 1901.backup.wav
    rem File 4 My Bigraphy 2000.backup.txt
    rem File 5 mp4 19.wav
    rem File 6 My file 2000.txt
    rem File 7 List of files.rtf

    rem
    rem Program must select all files which names contains
    rem YYYY string, year from 1900-2099 and 
    rem selected key word, 
    rem or user predefined file type entered by keyboard and
    rem selected file type extension entered by keyboard
    rem
    rem Program then creates new folders 
    rem with YYYY string inside folder name and
    rem moves files to newly created folders 
    rem according to year inside file name
    rem
    rem Depending on the options selected 
    rem at the beginning of the program,
    rem program moves only files that
    rem have selected key word inside file name and
    rem key word can be deleted from 
    rem file name before moving
 
    rem After program execution this would be result :
    rem
    rem    options selected : 
    rem
    rem    key_word = .backup, 
    rem    erase key word = Yes
    rem    file type = .*
    rem
    rem Root folder path : 
    rem
    rem C:\My_files_type_of_backup
    rem
    rem Folder contains new folders with files in it:
    rem
    rem Year 1901
    rem 		File 3 mp3 1901.wav
    rem Year 1998
    rem 		File 1 video (1998).avi
    rem Year 2000
    rem 		File 4 My Bigraphy 2000.txt
    rem 		File 6 My file 2000.txt
    rem Year 2016
    rem 		File 2 painting 2016.bmp
    rem 
    rem File 5 mp4 19.wav
    rem File 7 List of files.rtf
    rem 
    rem


    rem
    rem CMD attributes
    rem
    mode con:cols=80 lines=40
    title Program move files
    color 0A
    cls
    echo.
    echo Program started at ... %TIME%
    rem
    rem Local variables
    rem
    setlocal enableextensions enabledelayedexpansion
    set f=0
    set f1=.
    set f2=.

    rem
    rem Program options
    rem
    set /p key_word=Please enter key word [exmpl .backup] : || set key_word=*
    echo.
    echo Selected key word : %key_word%
    echo.
    set /p erase=Do You wish to erase key word from file name [Enter=No]: || set erase=n
    echo.	
    set /p file_type=Please enter file type  exmpl .* or .bmp : || set file_type=.*
    echo.
    echo Selected file type : %file_type%
    echo.

    rem	
    rem Find all files inside folder that contains 
    rem YYYY string (year 1900-2099) and 
    rem selected key word inside file name
    rem
    for %%# in (*%key_word%*%file_type%) do (
        for /f "tokens=1-26 delims=0123456789 " %%a in ("%%~n#") do (
            set "delims=%%a%%b%%c%%d%%e%%f%%g%%h%%i%%j%%k%%l%%m%%n%%o%%p%%q%%r%%s%%t%%u%%v%%w%%x%%y%%z"
            call :extractYear && (
                for %%y in ("!year!") do (

                
                    rem Create new folder
                    if not exist "%%~y\" md "Year %%~y"
                    
                    rem Erase selected key word from file name
                    rem if erase option is set to 'Yes' and
                    rem key word is not empty string
                    rem
                    set f1=%%~#
                    set f2=!f1!
                    if %erase% neq n if %key_word% neq *  (set f2=!f1:%key_word%=!)

                    rem
                    rem Move file
                    rem
		    echo Moving "!f1!" to folder "Year %%~y\!f2!"
		    move "!f1!" "Year %%~y\!f2!"

                    rem count number of moved files
                    set /a f=f+1     
                )
            )
        )
    )

    echo.
    if %f% equ 0 (echo There are no files that match criteria for moving) else (echo %f% files moved)
    echo.
    echo Program finished at ... %TIME%
    pause
    goto :eof

:extractYear
    for %%a in ("") do for /f "tokens=1-26 delims=%delims% " %%a in ("%%~n#") do for %%# in (
        %%~z %%~y %%~x %%~w %%~v %%~u %%~t %%~s %%~r %%~q %%~p %%~o %%~n
        %%~m %%~l %%~k %%~j %%~i %%~h %%~g %%~f %%~e %%~d %%~c %%~b %%~a 
    ) do if %%~# geq 1900 if %%~# leq 2099 (
        set "year=%%~#"
        exit /b 0
    )
    exit /b 1
like image 732
Perić Željko Avatar asked Sep 04 '26 08:09

Perić Željko


2 Answers

Just another idea to try to avoid calling findstr. While not bulletproof (only tested against a listing of the first few pages in a torrent movie site), this could handle the task in reasonable times.

The main idea is to remove the numbers from the file name (using them as delimiters in a for /f loop) and use the remaining characters as delimiters in another for /f, to only leave the numbers in the file name. The set of numbers are then iterated to determine if they match the required year range. If a year is found, then the script will echo to console the move command to execute. If the output is correct, remove the echo to perform the move operations.

@echo off
    setlocal enableextensions disabledelayedexpansion

    for %%# in (*.torrent) do (
        for /f "tokens=1-26 delims=0123456789 " %%a in ("%%~n#") do (
            set "delims=%%a%%b%%c%%d%%e%%f%%g%%h%%i%%j%%k%%l%%m%%n%%o%%p%%q%%r%%s%%t%%u%%v%%w%%x%%y%%z"
            call :extractYear && (
                setlocal enabledelayedexpansion
                for %%y in ("!year!") do (
                    endlocal
                    if not exist "%%~y\" md "%%~y"
                    echo move "%%~#" "%%~y"
                )
            )
        )
    )
    goto :eof

:extractYear
    for %%a in ("") do for /f "tokens=1-26 delims=%delims% " %%a in ("%%~n#") do for %%# in (
        %%~z %%~y %%~x %%~w %%~v %%~u %%~t %%~s %%~r %%~q %%~p %%~o %%~n
        %%~m %%~l %%~k %%~j %%~i %%~h %%~g %%~f %%~e %%~d %%~c %%~b %%~a 
    ) do if %%~# geq 1900 if %%~# leq 2016 (
        set "year=%%~#"
        exit /b 0
    )
    exit /b 1
like image 81
MC ND Avatar answered Sep 07 '26 11:09

MC ND


It looks like you are running findstr 199 times. I'd expect a speed increase by removing the for /l loop and using a single findstr instance Perhaps:

findstr /r "\<19[0-9][0-9] \<20[0-9][0-9]"
like image 31
Compo Avatar answered Sep 07 '26 11:09

Compo