I am creating this batch file, that works with handbrakecli, to batch convert avi to mp4.
However I am stuck in how to continue the loop and skip the current file inside a loop.
FOR /R "%somepath%" %%G in (*.avi) DO (
rem skip if filename contains word trailer
rem skip if file name contains word sample
rem do conversion
)
This currently doesn't work in skipping the files that contain trailer or sample
I have tried using find or findstr and both fail to skip.
echo "%%G" | c:\windows\system32\findstr /i "trailer" > NUL
If %ERRORLEVEL% EQU 1 set skip Yes
Here is for sample.
echo "%%G" | c:\windows\system32\findstr /i "sample" > NUL
If %ERRORLEVEL% EQU 1 set skip Yes
If a file contains either trailer or sample, I do not want to do any handbrakecli conversions, but to just skip it.
I do echo's to display which files get converted, and it does include files with Sample or sample in the name.
I have tried using find or findstr and both fail to set skip to yes
if skip == No do ( rem do conversion )
I only want to convert non-trailer/sample avi files.
Thank you for your time.
try this, put your conversion commands in the loop and remove the word echo before handbrakecli if the output is OK:
#echo off &setlocal
FOR /R "%somepath%" %%G in (*.avi) DO (
set "fpath=%%G"
set "fname=%%~nG"
setlocal enabledelayedexpansion
if "!fname!"=="!fname:trailer=!" if "!fname!"=="!fname:sample=!" (
echo handbrakecli.exe "!fpath!" &rem put your conversion command here
>>"logfile.log" echo !fname!
)
endlocal
)
The file name+file path is in the variable "!fpath!".
Added some code concerning the needs of the OP:
#echo off &setlocal
rem replace avi with mp4 files in my movie folder
rem grab 4 random folders with avi in them and no mp4
rem Settings for this Batch File
set "moviepath=H:\Movies"
set "logfile=C:\Documents and Settings\%USERNAME%\LogFiles\avi_converter.log"
rem check if log file exists
if not exist "%logfile%" echo(>"%logfile%"
rem create empty convert file
copy nul "convert_movies.bat" >nul 2>&1
rem add echo off
echo #echo off >>"convert_movies.bat"
rem set counter
SET /A COUNT=1
FOR /R "%moviepath%" %%G in (*.avi) DO (
set "fpath=%%~fG"
set "fname=%%~nG"
setlocal enabledelayedexpansion
rem check if count greater than 4
if !COUNT! gtr 4 goto:eof
if "!fname!"=="!fname:trailer=!" if "!fname!"=="!fname:sample=!" (
rem echo handbrakecli.exe "!fpath!" &rem put your conversion command here
rem Send File To HandBrakeCLI
CALL :DOHandBrakeCLI "!fpath!"
rem Delete File
CALL :DeleteOldFile "!fpath!"
rem Add Log Entry
CALL :LogEntry "!fpath!"
rem add line break space
echo( >>"convert_movies.bat"
endlocal
rem increment counter
SET /A COUNT+=1
) else endlocal
)
rem end main program, to close cmd window replace it with EXIT
goto:eof
:DOHandBrakeCLI
rem skip if the parameter is empty
IF "%~1"=="" goto:eof
For %%A in ("%~1") do (
Set "Folder=%%~dpA"
Set "Name=%%~nxA"
)
rem echo %Folder%%Name%
echo start /b "" "c:\handbrakecli\HandBrakeCLI.exe" -i "%~1" -o "%Folder%%~n1.mp4" --preset="High Profile">>"convert_movies.bat"
exit /b
:DeleteOldFile
rem skip if the parameter is empty
IF "%~1"=="" goto:eof
For %%A in ("%~1") do (
Set "Folder=%%~dpA"
Set "Name=%%~nxA"
)
rem sends parameters to deletefile which will make sure new file exists before deleting old one
echo c:\projects\deletefile.bat "%~1" "%Folder%%~n1.mp4">>"convert_movies.bat"
exit /b
:LogEntry
rem skip if the parameter is empty
IF "%~1"=="" goto:eof
echo "%~1">>"%logfile%"
exit /b
This should work:
#echo off
FOR /R "%somepath%" %%G in (*.avi) DO (
echo "%%~nG" |findstr /i "trailer sample">nul || (
rem do conversion
)
)
It's difficult to see where your post is pseudocode and where actual code.
The first sample contains only REM statements, so it's not surprising it apparently does nothing.
Your second and third sample are effectively identical - the only difference is the target string. It's not surprising that the variable skip isn't set to Yes since the correct syntax is
if %errorlevel% equ 0 set skip=Yes
The syntax you've posted will REPORT that skip is not defined - it ignores the Yes
HOWEVER this syntax is only usable OUTSIDE of a "block statement" - that is, a multiple-instruction statement (enclosed in parentheses) or cascaded&by&ersands. Batch first PARSES a complete statement - from the FOR or if through to the appropriate closing-parenthesis and THEN executes it. As part of the PARSING phase, any %var% - including %errorlevel% is replaced by its value as it stands at the time the entire statement is parsed - not as it changes due to the operation of the for.
In order to use the value as it changes, you need to use
if errorlevel 1 (do_something) else (do_something_else)
where do_something and do_something_else) may themselves be compound statements.
OR
if defined variable (do_something) else (do_something_else)
where the variable either is defined or not
OR
setlocal enabledelayedexpansion
....
if !errorlevel! equ x (do_something) else (do_something_else)
OR
if !var! neq something (do_something) else (do_something_else)
But it's quite possible that
FOR /R "%somepath%" %%G in (*.avi) DO (
echo(%%G|findstr /i "sample trailer" >nul
if errorlevel 1 echo %%G
)
will give you an appropriate skeleton.
Echo the filename through FINDSTR and look for "sample" or "trailer" /i case-insensitive. Findstr sets errorlevel 0 if either target string is found, 1 otherwise - and the if errorlevel x syntax works on the dynamic value of errorlevel within a loop.
#ECHO on &SETLOCAL
REM This script was inspired by Endoro's expanded script
(https://stackoverflow.com/a/16891696/10572786).
REM This batch script will recursively search for all .mp4 files that don't
have (x265) in the file name. Any valid results will be encoded with x265
using FFmpeg. The original .mp4 file will remain unchanged in it's original
folder with the new x265 version.
REM Example: %PATH%\A.mp4 > %PATH%\A(x265).mp4
REM If you don't have ffmpeg.exe on your PC you must download or build it
with Microsoft Visual Studios. I recommend you download and run media
autobuild suite on GitHub: (https://github.com/jb-alvarado/media-
autobuild_suite).
REM Once ffmpeg is compiled/downloaded make sure to set it's folder path as
an environmental variable in Windows before running the script. Change the
script's working directory to your .mp4 files root folder using the "cd"
command.
REM !!BEGIN SCRIPT!!
cd /d %USERPROFILE%\Desktop\Vids\
REM or perhaps use [cd /d %OneDrive%\Desktop\Vids]
REM Set mp4PATH to the root folder you wish to recursively search.
SET "mp4PATH=%USERPROFILE%\Desktop\Vids\"
REM Create empty convert file.
COPY NUL "convert_movies.bat" >NUL 2>&1
REM Add ECHO off.
ECHO #ECHO off >>"convert_movies.bat"
REM Recursively search root folder.
FOR /R "%mp4PATH%" %%G IN (*.mp4) DO (
SET "fpath=%%~fG"
SET "fname=%%~nG"
SETLOCAL enabledelayedexpansion
REM Ignore all files that have "(x265)" in the file name.
IF "!fname!"=="!fname:*(x265)=!" (
CALL :DO_FFmpeg_CLI "!fpath!"
ECHO(>>"convert_movies.bat"
) ELSE ENDLOCAL
)
)
GOTO:EOF
REM CALL variables for use in FFmpeg's command line.
:DO_FFmpeg_CLI
IF "%~1"=="" GOTO:EOF
FOR %%I IN ("%~1") DO (
SET "Folder=%%~dpI"
SET "Name=%%~nxI"
)
REM Export info to "convert_movies.bat and run ffmpeg.exe's command line in the cmd.exe window.
ECHO ffmpeg -y -i "%~1" -c:v libx265 -preset slow -crf
18 -c:a aac "%Folder%%~n1(x265).mp4">>"convert_movies.bat" && ffmpeg |
ffmpeg -y -i "%~1" -c:v libx265 -preset slow
-crf 18 -c:a aac "%Folder%%~n1(x265).mp4"
EXIT /B
PAUSE
The Batch file below solve the original question AND limit the number of converted files to a given number (that does not appear in the original question):
#echo off
setlocal EnableDelayedExpansion
rem Insert in the next line the list of files to skip
set skip=/trailer/sample/
set count=0
FOR /R "%somepath%" %%G in (*.avi) DO (
if /I "!skip:/%%~nG/=!" equ "%skip%" (
echo Current file name is not in skip variable
echo Do conversion on: %%G
set /A count+=1
if !count! equ 20 goto :endLoop
)
)
:endLoop
echo Converted files: %count%
Related
I need to move few files from one folder to sub folder. My folder structure is already ready.
File current folder: D:\AB\*.*
The file name is: SS-AA-Report-Temp File for Script Testing-Daily-31March.txt
Destination folder: D:\AB\Pm 1.1 File For Script\Daily\
How to check file name substring with folder name substring and move?
Note I have multiple files like this.
set Path1= d:\AB
Pushd %Path1%
echo %Path1%
for %%i in (*.*) do SET "FName=%%~ni"
For /F "Tokens=4-5 Delims=-" %%A In ("%FName%") Do (
Set "FoldOne=%%A"
Set "FoldTwo=%%B"
)
echo out %RDate%
mkdir %Path1%\"%FoldOne%"\"%FoldTwo%"\%RDate%
move %Path1%\"%FName%".* %Path1%\"%FoldOne%"\"%FoldTwo%"\%RDate%\
Edit:
File names format:
A-A-Format-Here First connectivity install on Day 0 regurlarly-Daily-All-2017-03-27-09-31-16.xls
A-A-Format-Already First connectivity with 10 days created-Weekly-All-2016-11-28-10-01-02.csv
A-A-Report-withname 1.2 Sample Report (Network Plan Report)-Daily-Detail-2017-01-03-23-53.xls
A-A-Report-Nextreport 1.2 Sample Report (Network Plan Report)-Weekly-Detail-2017-01-03-23-02-53.csv
Now my folder structure is:
D:\AB\Pm 1.1 First connectivity install on Day 0\Daily\05042017
D:\AB\Pm 2.1 First connectivity with 10 days\Weekly\29032017
D:\AB\Pm 1.2 Sample Report\Daily\05042017
D:\AB\Pm 1.2 Sample Report\Weekly\29032017
And here is the batch file I have already:
set Path1= d:\AB
Pushd %Path1%
echo %Path1%
for %%i in (*.*) do SET "FName=%%~ni"
For /F "Tokens=4-5 Delims=-" %%A In ("%FName%") Do (
Set "FoldOne=%%A"
Set "FoldTwo=%%B"
)
echo 1 %FoldOne%
echo 3 %FoldTwo%
IF %FoldTwo% == Daily (
echo here Daily
For /F UseBackQ %%A In (
`PowerShell "(Get-Date).AddDays(-1).ToString('ddMMyyyy')"`
) Do (Set "RDate=%%A"
echo ffor %RDate%
)
)
IF %FoldTwo% == Weekly (
Echo Weekly
For /F UseBackQ %%A In (
`PowerShell "(Get-Date).AddDays(-7).ToString('ddMMyyyy')"`
) Do (Set "RDate=%%A"
echo %RDate%
)
)
mkdir %Path1%\"%FoldOne%"\"%FoldTwo%"\%RDate%
move %Path1%\"%FName%".* %Path1%\"%FoldOne%"\"%FoldTwo%"\%RDate%\
Pushd d:\
GoTo :EOF
The logic for matching file name substrings with folder name is still very fuzzy.
However, I coded two possible solutions doing both the same using partly different methods.
The first complete batch code:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
cd /D "D:\AB"
rem Get name of each subfolder starting with string Pm, a space, two single
rem digit numbers separated by a dot, one more space and more characters to
rem indexed environment variables for later usage. And assign the substring
rem after the first 7 characters of each folder name also to an index
rem environment variable.
set FolderIndex=0
for /D %%I in ("Pm ?.? *") do (
set "FolderName!FolderIndex!=%%I"
set "CurrentPath=%%I
set "FolderPart!FolderIndex!=!CurrentPath:~7!"
set /A FolderIndex+=1
)
set "FolderCount=%FolderIndex%"
rem set Folder
rem Get date of yesterday and date of a week ago.
for /F "usebackq" %%I in (`PowerShell.exe "(Get-Date).AddDays(-1).ToString('ddMMyyyy')"`) do set "DateDaily=%%I"
for /F "usebackq" %%I in (`PowerShell.exe "(Get-Date).AddDays(-7).ToString('ddMMyyyy')"`) do set "DateWeekly=%%I"
rem set Date
rem Process now each file matching the wildcard pattern below in
rem current folder and calling a subroutine with current file name.
set "FileNotMoved=0"
for %%I in (*-*-*-*-*) do call :MoveToFolder "%%I"
endlocal & if not %FileNotMoved% == 0 pause
goto :EOF
rem This subroutine first gets fourth and fifth dash delimited part from
rem each passed double quoted file name.
rem Then it replaces in each fourth file name part each folder name part
rem by an empty string until either all folder name parts are processed
rem or the string substitution was successful meaning the file name part
rem really contains the folder name part.
rem Note: The substitution does not work correct if any folder name part
rem contains an equal sign as this character is the delimiter
rem between string to find and replace string for substitution.
rem In second case with substitution being successful the folder for
rem the file could be determined and the file is moved to the found
rem folder if also time part could be determined from file name.
:MoveToFolder
for /F "tokens=4,5 delims=-" %%A in ("%~1") do set "NamePart=%%A" & set "NameTime=%%B"
set "FolderIndex=0"
:FindFolder
if %FolderIndex% == %FolderCount% (
set "FileNotMoved=1"
echo Found no folder for: %1
goto :EOF
)
call set "CurrentPart=%%FolderPart%FolderIndex%%%"
if "!NamePart:%CurrentPart%=!" == "!NamePart!" (
set /A FolderIndex+=1
goto FindFolder
)
call set "CurrentFolder=%%FolderName%FolderIndex%%%"
if /I "%NameTime%" == "Daily" (
set "FolderTime=%DateDaily%"
) else if /I "%NameTime%" == "Weekly" (
set "FolderTime=%DateWeekly%"
) else (
set "FileNotMoved=1"
echo Undefined time for: %1
goto :EOF
)
mkdir "%CurrentFolder%\%NameTime%\%FolderTime%" 2>nul
move "%~1" "%CurrentFolder%\%NameTime%\%FolderTime%\" >nul
if errorlevel 1 (
set "FileNotMoved=1"
echo Failed to move file: %1
)
goto :EOF
The second batch code differs from first solution only on how subroutine MoveToFolder is coded for finding the corresponding folder for current file name. For that reason just the code of the subroutine is posted below.
:MoveToFolder
for /F "tokens=4,5 delims=-" %%A in ("%~1") do set "NamePart=%%A" & set "NameTime=%%B"
for /F "tokens=1* delims==" %%X in ('set FolderPart') do (
if not "!NamePart:%%Y=!" == "%NamePart%" (
set "FolderName=%%X"
goto FoundFolder
)
)
set "FileNotMoved=1"
echo Found no folder for: %1
goto :EOF
:FoundFolder
if /I "%NameTime%" == "Daily" (
set "FolderTime=%DateDaily%"
) else if /I "%NameTime%" == "Weekly" (
set "FolderTime=%DateWeekly%"
) else (
set "FileNotMoved=1"
echo Undefined time for: %1
goto :EOF
)
set "FolderIndex=%FolderName:~10%"
call set "CurrentFolder=%%FolderName%FolderIndex%%%"
mkdir "%CurrentFolder%\%NameTime%\%FolderTime%" 2>nul
move %1 "%CurrentFolder%\%NameTime%\%FolderTime%\" >nul
if errorlevel 1 (
set "FileNotMoved=1"
echo Failed to move file: %1
)
goto :EOF
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /?
cd /?
echo /?
endlocal /?
for /?
goto /?
if /?
mkdir /?
move /?
pause /?
rem /?
set /?
setlocal /?
Read also the Microsoft article about Using Command Redirection Operators for an explanation of 2>nul and >nul and answer on question Single line with multiple commands using Windows batch file for meaning of operator & on Windows command lines.
I have a folder with files and a .txt file with a list of file names and number of copies that I need to copy from one folder to another.
The script is copying the files but if the .txt file has two files of the same name it overwrites the old file.
In the list I have:
file1.txt 1
file2.txt 1
file1.txt 3
file2.txt 2
I want the achieve the following:
file1.txt
file2.txt
file1(1).txt
file1(2).txt
file1(3).txt
file2(1).txt
This is the code I have so far:
#echo off
set Source=C:\Users\siddique.gaffar\Desktop\Artworks
set Target=C:\Users\siddique.gaffar\Desktop\Artworks Copy
set FileList=C:\Users\siddique.gaffar\Desktop\Artwork TXT File\Book1.txt
echo.
if not exist "%Source%" echo Source folder "%Source%" not found & goto Exit
if not exist "%FileList%" echo File list "%FileList%" not found & goto Exit
if not exist "%Target%" md "%Target%"
for /F "delims=" %%a in ('type "%FileList%"') do copy "%Source%\%%a" "%Target%"
:Exit
echo.
echo press the Space Bar to close this window.
pause > nul
The following should do the trick:
#echo off
set Source=C:\Users\siddique.gaffar\Desktop\Artworks
set Target=C:\Users\siddique.gaffar\Desktop\Artworks Copy
set FileList=C:\Users\siddique.gaffar\Desktop\Artwork TXT File\Book1.txt
echo.
if not exist "%Source%" echo Source folder "%Source%" not found & goto Exit
if not exist "%FileList%" echo File list "%FileList%" not found & goto Exit
if not exist "%Target%" md "%Target%"
for /F "usebackq tokens=1-2" %%a in ("%FileList%") do call :CopyFile "%%a" %%b
:Exit
echo.
echo press the Space Bar to close this window.
pause > nul
exit /b 0
:CopyFile
:: first argument = filename
:: second argument = number of copies
REM A little trick that will put limit on 0 if second argument is empty or not a number
set secondarg=%~2
set /a limit=secondarg
REM if limit is invalid (not strict positive), exit the function
IF %limit% LEQ 0 (
echo Invalid number of copies
exit /b 1
)
IF NOT EXIST "%Target%\%~1" (
copy "%Source%\%~1" "%Target%"
IF %limit% LEQ 1 exit /b 0
set /a limit-=1
)
REM File already exists: search correct index for filename
set index=0
set "targetfile=%target%\%~n1"
set file_ext=%~x1
:following
set /a index+=1
Rem if file with index %index% already exists, go back to get following index
IF exist "%targetfile%(%index%).%file_ext%" goto :following
Rem we have the correct index, now we can copy
set /a limit=index+limit-1
FOR /L %%g IN (%index%,1,%limit%) DO copy "%Source%\%~1" "%targetfile%(%%g).%file_ext%"
exit /b 0
Another option if you have long filenames is the use of usebackq and surrounding the path with double quotes in the for f loop instead of analyzing the output of the type command.
The function :CopyFile checks the existence of the file with an IF EXIST and uses a counter to find the next index for the filename of the new file. It uses path manipulation to construct a new filename with the index.
EDIT: I've added the possibility to read the number of copies needed from the textfile and specify that number as second argument to the :CopyFile function. If no number is given or the number is not strict positive (greater than 0), it won't make a copy.
PS: the "little trick" I used that will set %limit% to 0 in case the second argument is empty works because set with the /a flag will replace empty variables with 0. This won't work if you use argument variables directly though:
set /a limit=%~2
will throw an error if the second argument is empty because the cmd parser will substitute %~2 with an empty string and it will execute set /a limit= which is an invalid assignement using the /a flag. But if you use an extra variable as transit:
set var=%~2
set /a limit=var
you'll let set handle the variable expansion and not the cmd interpreter. The set will see that the var variable is empty (in the case %2 is empty) and will replace it with 0.
#echo off
set "Source=C:\Users\siddique.gaffar\Desktop\Artworks"
set "Target=C:\Users\siddique.gaffar\Desktop\Artworks Copy"
set "FileList=C:\Users\siddique.gaffar\Desktop\Artwork TXT File\Book1.txt"
setlocal EnableDelayedExpansion
for /f "delims=" %%a in ('type "%FileList%"') do (
if not defined count set "count=1"
cd "%Target%"
if exist %%a (
set "curfile=%%a"
set "curfile=!curfile:~0,-4!"
set "curfile=!curfile!(!count!).txt"
if exist !curfile! (
set /a "count=!count! + 1"
set "curfile=%%a"
set "curfile=!curfile:~0,-4"
set "curfile=!curfile!(!count!).txt"
)
cd "%Source%"
ren "%Source%\%%a" "!curfile!"
xcopy "%Source%\!curfile!" "%Target%"
ren "%source%\!curfile!" "%%a"
) else (
xcopy "%Source%\%%a" "%Target%"
)
)
pause
replace all your code by this code. put this batch file in the same directory wher your files to copy is. p. s.: for now it works only with .txt files.
I'm having a bit of trouble with a FOR DO command in a .BAT file I'm working on for work.
Here is the entire code I'm working with
SET parent="%~dp0"
SET GroomedDir="%~dp0Groomed\"
XCOPY /s/e/y Groomed %parent%NewGroomed\
CD NewGroomed
setlocal enabledelayedexpansion
FOR %%i in (IMG_*.jpg) DO (
SET OldName=%%i
SET ImgNumber=!OldName:~4,-4!
SET DBLookup=FINDSTR !ImgNumber! Database.txt
!DBLookup! > return.txt
FOR /F "tokens=1-5 delims=|" %%J in (return.txt) do (
REN !OldName! "%%K_%%L.jpg"
MKDIR %%M\%%N
MOVE "%%K_%%L.jpg" %%M\%%N
)
)
del return.txt
endlocal
cd ..
ren Groomed "Groomed Backup"
ren NewGroomed Groomed
The trouble come in lines 12-14 (I put in line separators). I can't seem to put the variable %DBLookup% into the FOR command, and am forced to use a placeholder text file instead. It works, in the end, but wouldn't it be better to save myself the write to return.txt operation, and the read return.txt operation?
For context, return.txt contains a single line from of text like this:
115525|Last_First|5233|8|Teacher
I use the FOR command because it allows me to delimit using the pipe character, or whatever else, and output to %%J %%K %%L %%M and %%N variables.
Any help or advice for this relative newcomer is much appreciated!
Here's my code with my comments:
REM THESE FOUR LINES:
REM 1) SET A VARIABLE FOR THE PARENT DIRECTORY LOCATION,
REM 2) SET A VARIABLE FOR THE GROOMED DIRECTORY,
REM 3) COPY THE GROOMED DIRECTORY TO "NEWGROOMED\",
REM 4) CHANGE THE LOCATION TO BE WORKING ENTIRELY WITHING NEWGROOMED\
SET parent="%~dp0"
SET GroomedDir="%~dp0Groomed\"
XCOPY /s/e/y Groomed %parent%NewGroomed\
CD NewGroomed
REM THIS FOR LOOP LOADS ALL JPGS IN THE \NEWGROOMED\ DIRECTORY THAT BEGIN WITH THE STRING, "IMG_"
setlocal enabledelayedexpansion
FOR %%i in (IMG_*.jpg) DO (
SET OldName=%%i
REM THIS LINE COPIES THE OLD NAME MINUS THE FIRST FOUR CHARACTERS, "IMG_", AND MINUS THE EXTENSION (LAST 4 CHARS)
SET ImgNumber=!OldName:~4,-4!
REM THESE NEXT TWO LINES LOOK UP OUR IMAGE NUMBER IN DATABASE.TXT AND RETURN THE ENTIRE LINE TO A NEW FILE CALLED RETURN.TXT
SET DBLookup=FINDSTR !ImgNumber! Database.txt
!DBLookup! > return.txt
REM NOW WE PARSE RETURN.TXT USING PIPE DELIMITERS INTO THE VARIABLES J,K,L,M,N (ID,Name,IMG#,Grade,Homeroom)
FOR /F "tokens=1-5 delims=|" %%J in (return.txt) do (
REN !OldName! "%%K_%%L.jpg"
MKDIR %%M\%%N
MOVE "%%K_%%L.jpg" %%M\%%N
)
)
del return.txt
endlocal
cd ..
ren Groomed "Groomed Backup"
ren NewGroomed Groomed
Overall, my goal is to begin with a folder, "Groomed," with a bunch of images titled as such: IMG_####.jpg.
My batch file will:
1) create a backup of the entire starting directory
2) rename each image according to the database.txt file
3) move each renamed image into a new grade/teachername folder
I am starting with a file, (database.txt) that comes to me from another employee. The file is a plain list for each student in the following format: student id|lastname_firstname|image#|grade#|teachername.
As i mentioned. The file works perfectly, but since I'm new to batch files I was feeling like it might be dumb of me to write to a throwaway file just to save a string and then delete it. That's what variables are for, but I was having a hard time getting that variable to pass into the FOR command.
sample of Database.txt
659968|Saperstein_Ryan|4603|7|Hallock
015520|Qian_Emily|2528|7|Hallock
528852|Rizzo_Jason|4618|7|Krukowski
and a few filenames I'm starting with:
IMG_2528.jpg
IMG_4544.jpg
IMG_7044.jpg
IMG_6880.jpg
IMG_4839.jpg
Edit:
A first bunch by parsing database.txt first and then compare by using if exist. The second is by comparing variables
code:
rem create a sample of the following example
rem :: student id|lastname_firstname|image#|grade#|teachername
rem :: The common points are only in the first 3 jpg
copy nul IMG_4603.jpg
copy nul IMG_2528.jpg
copy nul IMG_4618.jpg
copy nul IMG_4619.jpg
copy nul IMG_4620.jpg
copy nul IMG_4630.jpg
(
echo 659968^|Saperstein_Ryan^|4603^|7^|Hallock
echo 015520^|Qian_Emily^|2528^|7^|Hallock
echo 528852^|Rizzo_Jason^|4618^|7^|Krukowski
echo 528817^|Rizzo_Jas17^|4617^|7^|Krukows17
echo 528816^|Rizzo_Jas16^|4616^|7^|Krukows16
)>sample.txt
rem :: type sample.txt
rem :: pause
Method #1
#echo off
setlocal enabledelayedexpansion
for /f "tokens=1-5 delims=|" %%a in (sample.txt) do (
set "student_id=%%a"
set "student_name=%%b"
set "student_image=%%c"
set "student_grade=%%d"
set "student_teacher=%%e"
rem :: echo !student_name!_!student_image!.jpg
if exist "IMG_!student_image!.jpg" (
rem :: remove echo in the following lines if it's okay.
echo:
echo ren "IMG_!student_image!.jpg" "!student_name!_!student_image!.jpg"
echo mkdir "!student_grade!\!student_teacher!"
echo move "!student_name!_!student_image!.jpg" "!student_grade!\!student_teacher!"
)
)
Method #2
#echo off
setlocal enabledelayedexpansion
for %%i in (IMG_*.jpg) do (
set "OldName=%%~i"
set "image_number=!OldName:~4,-4!"
rem :: echo image_number: !image_number!
for /f "tokens=1-5 delims=|" %%b in (
'findstr !image_number! sample.txt'
) do (
set "student_id=%%a"
set "student_name=%%b"
set "student_image=%%c"
set "student_grade=%%d"
set "student_teacher=%%e"
if "!student_image!"=="!student_image!" (
rem :: remove echo in the following lines if it's okay.
echo:
rem :: echo !image_number! = !student_image!
echo ren "IMG_!student_image!.jpg" "!student_name!_!student_image!.jpg"
echo mkdir "!student_grade!\!student_teacher!"
echo move "!student_name!_!student_image!.jpg" "!student_grade!\!student_teacher!"
)
)
)
output:
ren "IMG_2528.jpg" "Qian_Emily_2528.jpg"
mkdir "7\Hallock"
move "Qian_Emily_2528.jpg" "7\Hallock"
ren "IMG_4603.jpg" "Saperstein_Ryan_4603.jpg"
mkdir "7\Hallock"
move "Saperstein_Ryan_4603.jpg" "7\Hallock"
ren "IMG_4618.jpg" "Rizzo_Jason_4618.jpg"
mkdir "7\Krukowski"
move "Rizzo_Jason_4618.jpg" "7\Krukowski"
I have a batch script which accepts >=1 files via drag & drop. The full paths are kept in an array and later fed to another program as input. The file name+extension is kept in another array which is then shown to the user.
I am trying to check the file extension and if it is not .bin, automatically rename the file I dragged & dropped to .bin and reload it to be added to the two arrays. How can I do that? I have tried some if commands or %%~xi but usually it doesn't properly detect if it's .bin or not and of course the path is not updated at the array.
#echo off
pushd %~dp0
setlocal enabledelayedexpansion
set /a Count = 0
:START
set file="%~1"
if %file%=="" goto RUN
for %%i in (%file%) do set name=%%~nxi
set /a Count += 1
set [FilePath.!Count!]=%file%
set [FileName.!Count!]=%name%
shift
goto START
:RUN
for /l %%i in (1, 1, %Count%) do (
program.exe -command "![FilePath.%%i]!"
echo.
echo File Name: ![FileName.%%i]!
echo.
pause
cls
if exist file.log del file.log
)
You could just rename it during your array population. There are a few other potential problems with your script (such as pushd to an unquoted directory, delayedexpansion where you don't need it where it will potentially clobber filenames containing exclamation marks, and if %file%=="" should have "%file%" quoted). And there's really no reason to maintain an array of filenames or loop twice. Your script is much more complicated than it needs to be.
#echo off
setlocal
pushd "%~dp0"
for %%I in (%*) do (
if /I not "%%~xI"==".bin" move "%%~fI" "%%~dpnI.bin" >NUL
program.exe -command "%%~dpnI.bin"
echo;
echo File Name: "%%~nxI"
echo;
rem If you want to rename the file back the way it was after running
rem program.exe on it, uncomment the following line:
rem if /I not "%%~xI"==".bin" move "%%~dpnI.bin" "%%~fI" >NUL
pause
cls
if exist file.log del file.log
)
A slightly archaic question I'm afraid but here goes:
I have a program which produces some .RAW files in a sequence eg.
Example_1.RAW
Example_2.RAW
This then adds extra significant figures to the number as necessary, eg.
Example_10.RAW
Example_200.RAW
I have a need to convert these file names into numbers for running through a batch processor that then produces more files as outputs. I've written a batch file that does the renaming and stores the old and new filenames in a text file, my code is:
#echo off
set i=1
echo Running Batch Rename
for %%f in (*.RAW) do (set file=%%f) & CALL :rename
:rename
echo %i% >>Names.txt
echo %file% >>Names.txt
echo. >>Names.txt
ren %file% %i%.RAW
set /A i+=1
This then renames all my .RAWs as 1.RAW, 2.RAW etc and creates Names.txt with the old and new filenames. Thanks to the way in which DOS processes numbers this does mean that I get a slightly wonky numbering process, ie it will process Ex_1, Ex_10, Ex_100, Ex_101 as 1, 2, 3, 4 which would lead to more work in the post processing of these results in order to get the right results in the right places.
Would it be possible to write another batch file that takes the Names.txt and reverses the process for the output files? So it will take a folder with 1.raw, 1.something, 1.something else, refer to the Names.txt and rename them to Example_1.raw etc?
This should do the job
#echo off
set cnt=0
del Names.txt > nul 2>&1
echo Running Batch Rename
for %%f in (*.RAW) do (
set "file=%%f"
CALL :renameToNumber
)
echo .. Do the jobs ...
rem ** As sample: copy the file
copy *.raw *.some
call :renameBack
exit /b
:renameToNumber
set /A cnt+=1
set "number=00000%cnt%"
set "number=%number:~-4%"
(echo %number% %file%) >> Names.txt
ren "%file%" %number%.RAW
exit /b
:renameBack
for /F "tokens=1,*" %%A in (names.txt) DO (
set "number=%%A"
set "filename=%%~nB"
call ren %%number%%.* "%%filename%%_%%number%%.*"
call echo ren %%number%%.* "%%filename%%_%%number%%.*"
)
exit /b
I was able to adapt the above code, to function within an existing batch routine, by testing for the last file in the directory - using 'if errorlevel' - so that the routine did not exit after the last file was reached but instead returned to my routine.
:: *** Renumber .JPG files ***
setlocal EnableDelayedExpansion
set dir=C:%homepath%\Desktop\Temp
:: Create variable and set to zero
set cnt=0
:: For each file in specified class
for %%f in (%dir%\*.jpg) do (
:: Get name of file
set "file=%%f"
:: Run specified Subroutine
CALL :renameToNumber
)
:renameToNumber
:: Increment variable by 1
set /A cnt+=1
:: Preceed value of variable with 00000
set "number=00000%cnt%"
:: Delete all but final 2 digits
set "number=%number:~-2%"
:: Store new and original name of file
(echo %number% %file%) >> Names.txt
:: Rename file
ren "%file%" %number%.jpg
:: Quit Subroutine if no further files
if errorlevel==1 goto :Continue
:: Loop back to start of Subroutine
exit /b
:Continue
:: *** Zip the image files into an RAR file ***
SET rar=C:\Program Files (x86)\WinRAR\RAR.exe
"%rar%" a -ep -m0 temp.rar "%dir%\*.*"
You can prepare two batch files, one to rename RAW files to 1.RAW, 2.RAW, etc, and a second one to reverse this process back.
Rename script stores original names of RAW files in corresponding txt files:
#echo OFF
#setlocal ENABLEDELAYEDEXPANSION
set I=1
for %%G in (*.RAW) do (
set ORIGINAL_NAME=%%~nG
(
REM Try to rename file
ren "%%G" "!I!.RAW"
) && (
REM Renaming was successful
> "!I!.txt" echo !ORIGINAL_NAME!
set /A I+=1
) || (
REM Renaming was a failure
echo Cannot rename [!ORIGINAL_NAME!.RAW] file.
)
)
#endlocal
And the RenameBack script uses that information to restore names of all corresponding files:
#echo OFF
#setlocal ENABLEDELAYEDEXPANSION
for %%F in (*.txt) do (
set BASENAME=%%~nF
REM Read original name from txt file
for /F %%G in (%%F) do (
REM iterate over all corresponding files
for %%H in (!BASENAME!.*) do (
set EXTENSION=%%~xH
REM Remove dot from extension string
set EXTENSION=!EXTENSION:~1!
if not "!EXTENSION!" == "txt" (
REM Process files
(
REM try to rename corresponding file to old name
ren "!BASENAME!.!EXTENSION!" "%%G.!EXTENSION!"
) && (
REM Operation was successful - remove TXT file
del /F /Q "%%F"
) || (
REM Something went wrong
echo Cannot restore old name for file [!BASENAME!.!EXTENSION!].
)
)
)
)
)
#endlocal