I have a working script, (below), which compares files, by size only, and if one or more of the files have different size, it shows on the .bat screen.
#echo off
setlocal EnableDelayedExpansion
rem Group all file names by size
for /R %%a in (*.*) do (
set "size[%%~Za]=!size[%%~Za]!,%%~Fa"
)
rem Show groups that have more than one element
for /F "tokens=2,3* delims=[]=," %%a in ('set size[') do (
if "%%c" neq "" echo [%%a]: %%b,%%c
)
pause
But I need more!
I also need the script delete duplicate files, keeping just one. For example, if there are 3 files of the same size but with different names, the script should choose one to keep, deleting the other 2.
#LotPings, i tried with 2 .pdf files, and appeared this message in the pic below:
#LotPings
Now it recognized fine! But it doesn't deleting the duplicate, just recognizing.... Look the image below:
I think treating files with same size as same content is a bit naive.
If in doubt better do a binary compare with fc.
Your way of stuffing %%~Fa into a string without quoting every single name possibly containing spaces can be problematic in further processing.
If the files are identical you could create links.
You know that for /r will recurse into subdirs?
The following batch will process the size[] array differently passing the size and content to a subroutine which keeps the first file and (only echos) the del command.
:: Q:\Test\2018\06\06\SO_50723488.cmd
#echo off & setlocal
rem Group all file names by size
for /R %%a in (*.*) do call set size[%%~Za]=%%size[%%~Za]%%,"%%~Fa"
rem Process groups
for /F "tokens=2* delims=[]=," %%a in ('set size[') do Call :Sub %%a %%b
pause
Goto :Eof
:Sub
If "%~3"=="" (Set "size[%1]="&goto :EOf)
Echo ========================================
Echo processing %*
Echo Keep %2
Shift&shift
:loop
Echo Del %1
if not "%~2"=="" (shift&goto :loop)
Sample output:
> Q:\Test\2018\06\06\SO_50723488.cmd
========================================
processing 0 "Q:\Test\2018\05\03\Text3.txt","Q:\Test\2018\05\27\log.html"
Keep "Q:\Test\2018\05\03\Text3.txt"
Del "Q:\Test\2018\05\27\log.html"
========================================
processing 14 "Q:\Test\2018\05\03\Text1.txt","Q:\Test\2018\05\15\HP-G1610-20180515.json"
Keep "Q:\Test\2018\05\03\Text1.txt"
Del "Q:\Test\2018\05\15\HP-G1610-20180515.json"
========================================
processing 21 "Q:\Test\2018\05\12\text1.txt","Q:\Test\2018\05\12\text2.txt"
Keep "Q:\Test\2018\05\12\text1.txt"
Del "Q:\Test\2018\05\12\text2.txt"
========================================
processing 22 "Q:\Test\2018\05\20\2.txt","Q:\Test\2018\05\22\version.ps1"
Keep "Q:\Test\2018\05\20\2.txt"
Del "Q:\Test\2018\05\22\version.ps1"
========================================
processing 288 "Q:\Test\2018\05\11\RawData.txt","Q:\Test\2018\05\23\SO_50478080.ps1"
Keep "Q:\Test\2018\05\11\RawData.txt"
Del "Q:\Test\2018\05\23\SO_50478080.ps1"
The following script removes duplicate files in the current directory. It leaves one file, and removes rest of its duplicates. I developed the script for Windows 10, so it might not work for other Windows versions.
The advantage of this script is it not only checks the last modified date and time, but also the file size. Let's say you have a text file with *** symbols? you can turn them all ### symbols, and still occupy the same space. The script checks the last modified date, and time along with its size to ensure both the files are identical, otherwise it doesn't remove any file.
setlocal enabledelayedexpansion
echo(
echo "This program removes duplicate files in the current directory."
echo "Warning: Take a backup of the current directory to avoid accidents"
PAUSE
echo(
set path=%cd%
set /A count=0
for %%a in (*.*) do (
for %%b in (*.*) do (
if exist "%%b" if %%a neq %%b (
if "%%~Ta %%~Za" equ "%%~Tb %%~Zb" (
echo "%%a File is deleted"
set /A count+=1
del "%%a"
)
)
)
)
echo(
echo "---------"
echo "!count! Duplicate Files were deleted in the current directory"
echo "---------"
echo(
endlocal
PAUSE
If you have any problems report me at
https://github.com/donqq/Duplicate-File-Remover/
Related
I'm working on a project which works like that:
take a long video hard subtitled and cut it in a lot of smaller
scenes and where each scene lasts the time that it lasts the
subtitle to disappear
cut one only picture (maybe the first one or the last one) of each
segment of the original video and do it automatically
repeat (copy and paste) the picture extracted as many times as the
number of pictures that there are on each fragment that has been cut
on the original video
join everything
I have already achieved the point 1) and 2), now I'm trying to achieve point 3) and I need your help, please. Let's say that I have achieved point 2) with this batch script (that I call a.bat) :
pushd %1
if not exist newfiles\ (
mkdir newfiles
)
if not exist newfiles2\ (
mkdir newfiles2
)
:start
for %%F in (*.mov) do (
md "%%~nF"
echo "%%~nF"
ffmpeg -i %%F -r 1 -f image2 -qscale:v 2 "%%~nF\%%~nF_image-%%3d.png"
copy "%%~nF\%%~nF_image-001.png" ".\newfiles"
)
popd
So, I have this situation:
It means that in each folder there is a variable number of images that have been extracted from the *.mov files. Now, I want that the first image on the list of the images located on the relative folders is copied in another folder, as many times as many files there are in the same folder where it is. For example, let's take a look at this folder:
Here there are 4 images, right? I want to copy the first (or the last) image of the list for 4 times in this folder:
I would like that someone can help me to improve this batch script (that I call b.bat)...
#echo off
setlocal enabledelayedexpansion
set count=0
for %%x in (*.png) do set /a count+=1
echo %count%
FOR %%F IN (*.png) DO (
set filename=%%F
goto tests
)
:tests
echo "%filename%"
for /l %%i in (1,1,%count%) do copy %filename% ..\newfiles2\%%i.png
endlocal
pause
because I figured out that it works only if I put a copy of it in every/each folder,but then I have to enter in each folder to run it,wasting a lot of time. Let's say that I want to run it in the folder where all the others folders are located. How can I modify the script to do so ? This is what happens if I run it on the "root" folder :
EDIT : thanks to the suggestion of #AlexP I modified the script like this :
#echo off
setlocal enabledelayedexpansion
set count=0
for /d %%d in (render*) do set /a count+=1t
echo %count%
pause
for %%f IN ("%%~d\*") do (
set filename=%%F
goto tests
)
:tests
echo "%filename%"
for /l %%i in (1,1,%count%) do copy %filename% .\%%i.png
endlocal
pause
now the var "count" has value 4,but this is wrong. the value that i need is inside each folder that starts with the word render* ; so,since I have 4 pics inside the "render00003211" folder the value is 4; 5 pics under "render00003266" the value is 5 and so on..
UPDATE : I've ordered sequentially the names of the pictures by placing this script inside the Duplicates folder...
#echo off
setlocal enabledelayedexpansion
mkdir pics
copy *.png .\pics
del *.png
for /d /r %%a in (%1\*.*) do (
set /a counter=0
for %%b in ("%%a\*.*") do (
set /a counter += 1
set zcounter=0000!counter!
set source="%%~fb"
set target="pic!zcounter:~-4!%%~xb"
echo Renaming !source! to !target!
ren !source! !target!
)
)
for /l %%i in (1,1,%count%) do copy %filename% %somewhere%
From for /?:
FOR /L %variable IN (start,step,end) DO command [command-parameters]
The set is a sequence of numbers from start to end, by step amount. So (1,1,5) would generate the sequence (1 2 3 4 5) and (5,-1,1) would generate the sequence (5 4 3 2 1).
Here is a script which implements what I understand to be the requirements:
#echo off
:: This script will visit each subdirectory of the directory from where it is
:: run; it will take the first file found in that subdirectory and copy it to
:: the directory ..\Duplicates as many times as there are files in that
:: subdirectory; the names of the copied files are taken from the name of the
:: subdirectory with a numeric suffix appended, and have the extension of the
:: copied file. If ..\Duplicates does not exist then it is created.
setlocal
echo Working in directory "%CD%"
if not exist ..\Duplicates mkdir ..\Duplicates
if not exist ..\Duplicates\. (
echo Destination ..\Duplicates does not exist, and I cannot create it.
exit /b
)
for /d %%d in (*) do call :duplicateDir "%%~d"
exit /b
:duplicateDir
echo * "%~1"
set COUNT=0
set "SUBNAME=%~n1"
set SUBFILE=&
set SUBEXT=&
for %%f in ("%~1\*") do call :duplicateFile "%%~f"
echo "%SUBFILE%" copied %COUNT% times
exit /b
:duplicateFile
if not defined SUBFILE set "SUBFILE=%~1"
if not defined SUBEXT set "SUBEXT=%~x1"
set /a COUNT=COUNT+1
echo copy "%SUBFILE%" "..\Duplicates\%SUBNAME%-%COUNT%%SUBEXT%"
:: copy "%SUBFILE%" "..\Duplicates\%SUBNAME%-%COUNT%%SUBEXT%" >nul
exit /b
Note that instead of actually doing the copying the script displays the command which would be executed. When you are happy with it, comment out the echo copy and uncomment the copy.
I have a Batch script :
#echo off
setlocal enableDelayedExpansion
SET /P UserInput=Please Enter a Number:
SET /A number=UserInput
ECHO number=%number%
for %%i in (*.jpeg) do call :JPG %%~ni %%i
goto :end
:JPG
set str=%1
set /a str2=%str:_color=%
set /a newnamej=%str2%+%number%
echo %1 ==> I can see the problem with it
set lastnamej=%newnamej%_color.jpeg
ren %2 %lastnamej%
goto :eof
:end
The goal of this script is to take all file in a folder. They are all named after a number (1_color.jpeg, 2_color.jpeg, 3_color.jpeg,..) and I want to rename them with an additionnal number (if user input is 5, 1_color.jpeg will become 6_color.jpeg, and so on).
I have a problem with this script.
if I use a number such as 555, the first file will pass in the for loop 2 times.
(little example : 1_color.jpeg and 2_color.jpeg,
I use my script with 5 so 1_color.jpeg => 6_color.jpeg and 2_color.jpeg => 7_color.jpeg but then, 6_color.jpeg will be read again once, and will become 11_color.jpeg, so my result will be 11_color.jpeg and 7_color.jpeg).
Do someone know how to fix this issue?
Thanks for all!
The problem have two parts: the for %%i in (*.jpeg) ... command may be dinamically affected by the position that a renamed file will occupy in the whole file list, so some files may be renamed twice and, in certain particular cases with many files, up to three times.
The solution is to use a for /F %%i in ('dir /B *.jpeg') ... command instead, that first get the list of all files, and then start the renaming process.
Also, the rename must be done from last file to first one order, to avoid duplicate numbers.
However, in this case the use of for /F combined with "tokens=1* delims=_" option also allows to process the first underscore-separated number in the file names in a simpler way:
#echo off
setlocal EnableDelayedExpansion
SET /P number=Please Enter a Number:
ECHO number=%number%
for /F "tokens=1* delims=_" %%a in ('dir /O:-N /B *.jpeg') do (
set /A newNum=%%a+number
ren "%%a_%%b" "!newNum!_%%b"
)
User Aacini provided a nice solution in his answer, pointing out both issues at hand, namely the fact that for does not fully enumerate the directory in advance (see this thread: At which point does for or for /R enumerate the directory (tree)?) and the flaw in the logic concerning the sort order of the processed files.
However, there is still a problem derived from the purely (reverse-)alphabetic sort order of dir /B /O:-N *.jpeg, which can still cause collisions, as the following example illustrates:
9_color.jpeg
8_color.jpeg
7_color.jpeg
6_color.jpeg
5_color.jpeg
4_color.jpeg
3_color.jpeg
2_color.jpeg
10_color.jpeg
1_color.jpeg
So if the entered number was 1, file 9_color.jpeg is tried to be renamed to 10_color.jpeg, which fails because that file already exists as it has not yet been processed (hence renamed to 11_color.jpeg).
To overcome this problem, you need to correctly sort the items in reverse alpha-numeric order. This can be achieved by left-zero-padding the numbers before sorting them, because then, alphabetic and alpha-numeric sort orders match. Here is a possible implementation:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_LOCATION=." & rem // (directory containing the files to rename)
set "_PATTERN=*_*.jpeg" & rem // (search pattern for the files to rename)
set "_REGEX1=^[0-9][0-9]*_[^_].*\.jpeg$" & rem // (`findstr` filter expression)
set "_TEMPFILE=%TEMP%\%~n0_%RANDOM%.tmp" & rem // (path to temporary file)
rem // Retrieve numeric user input:
set "NUMBER="
set /P NUMBER="Please Enter a number: "
set /A "NUMBER+=0"
if %NUMBER% GTR 0 (set "ORDER=/R") else if %NUMBER% LSS 0 (set "ORDER=") else exit /B
rem /* Write `|`-separated list of left-zero-padded file prefixes, original and new
rem file names into temporary file: */
> "%_TEMPFILE%" (
for /F "tokens=1* delims=_" %%E in ('
dir /B "%_LOCATION%\%_PATTERN%" ^| findstr /I /R /C:"%_REGEX1%"
') do (
set "NAME=%%F"
setlocal EnableDelayedExpansion
set "PADDED=0000000000%%E"
set /A "NUMBER+=%%E"
echo !PADDED:~-10!^|%%E_!NAME!^|!NUMBER!_!NAME!
endlocal
)
)
rem /* Read `|`-separated list from temporary file, sort it by the left-zero-padded
rem prefixes, extract original and new file names and perform actual renaming: */
< "%_TEMPFILE%" (
for /F "tokens=2* delims=|" %%K in ('sort %ORDER%') do (
ECHO ren "%%K" "%%L"
)
)
rem // Clean up temporary file:
del "%_TEMPFILE%"
endlocal
exit /B
After having successfully verified the correct output of the script, to not forget to remove the upper-case ECHO command in front of the ren command line.
The script uses a temporary file that receives a |-separated table with the padded numeric prefix in the first, the original file name in the second and the new file name in the third column, like this:
0000000010|10_color.jpeg|11_color.jpeg
0000000001|1_color.jpeg|2_color.jpeg
0000000002|2_color.jpeg|3_color.jpeg
0000000003|3_color.jpeg|4_color.jpeg
0000000004|4_color.jpeg|5_color.jpeg
0000000005|5_color.jpeg|6_color.jpeg
0000000006|6_color.jpeg|7_color.jpeg
0000000007|7_color.jpeg|8_color.jpeg
0000000008|8_color.jpeg|9_color.jpeg
0000000009|9_color.jpeg|10_color.jpeg
The temporary file is read and sorted by the sort command. The strings from the second and third columns are extracted and passed over to the ren command.
In a large .ahk file, i need to locate the text 'no label' in a line, delete 2 lines before that, delete 23 lines after that, and delete the line with 'no label' itself (26 lines total). There can be multiple cases of this in the file, and in all cases it needs to remove these 26 lines.
I have no knowledge of SED, AWK and so on, and I need this to run on a windows machine. Is it doable with a .bat or some other windows application that I'll be able to run?
#ECHO OFF
SETLOCAL
SET "$="
SET "tempfile=%temp%\some-tempfile-name.txt"
ECHO.>"%tempfile%"
FOR /f "tokens=1*delims=:" %%a IN ('findstr /n /r ".*" q34397055.txt') DO (
ECHO %%b|FIND "no label" >NUL
IF NOT ERRORLEVEL 1 CALL :saveline# %%a
)
IF NOT DEFINED $ COPY /b q34397055.txt u:\newfile.txt 2>NUL >nul&GOTO done
(
FOR /f "tokens=1*delims=:" %%a IN ('findstr /n /r ".*" q34397055.txt^|findstr /v /b /g:"%tempfile%"') DO (
ECHO(%%b
)
)>u:\newfile.txt
:done
DEL "%tempfile%"
GOTO :EOF
:saveline#
:: calculate START line number to delete
SET /a $=%1 - 2
:: number of lines to delete
SETLOCAL enabledelayedexpansion
FOR /l %%d IN (1,1,26) DO (
>>"%tempfile%" ECHO(!$!:
SET /a $+=1
)
GOTO :EOF
I used a file named q34397055.txt containing some test data for my testing.
Produces u:\newfile.txt
Essentially, read the entire file, numbering each line in the format line#:line content
Use the tokens facility to extract the line number part, and if the line-content part contains the target string (it's not clear whether OP wants a line containing "no label" or whether a line exactly matching "no label" is required) then call :saveline# passing the line number.
In :saveline#, calculate the starting line of the block-to-be-deleted and then write the line numbers to be deleted to a file in the format (eg) 6:..32:.
Then perform the same numbering trick, but this time filter the output for lines that do not contain (/v) at the beginning of the line (/b) any string in the tempfile of line-numbers-to-be-deleted.
Output any line-content parts that pass through the filter.
[Edit : to fix empty-output-if-no-target-found problem
Insert set "$=" to ensure variable $is deleted at the start.
Insert if not defined $... line to detect whether $ has been established (ie. :saveline# has been called at least once). Simply mechanically copy the source file to the destination if :saveline# has not been called, and then skip to the label done to delete the tempfile.
Insert the label done
Suggestion : establish variables to contain the source and destination filenames so that only one change need be made to change the filenames, not two or three.
]
Okay, challenge accepted. This should do what you want in 100% batch-file form. I threw in a few comments but if you have questions feel free to ask.
First it scans the file for any instance of the searchPhrase (currently "no label"). If found it saves that line number as refLine*. It then sets the upper bounds as refLine + 23 and the lower bounds as refLine - 2, as per your criteria. If the current line number falls outside those bounds it will write the line to a new, temporary, file. Once complete, it backs up the original file then deletes it and renames the temp file.
#echo off
setlocal enabledelayedexpansion
set "sourceFile=c:\temp\batchtest\myfile.txt"
set "tempFile=c:\temp\batchtest\tempfile.txt"
set "searchPhrase=no label"
set /a lineNum=0
REM check file for search phrase, store line as refLine
FOR /F "delims=" %%i IN (%sourceFile%) DO (
set /a lineNum+=1
echo !lineNum! = "%%i"
if "%%i" == "%searchPhrase%" (
echo Found "%searchPhrase%" on line !lineNum!
set /a refLine=!lineNum!
)
)
REM make backup
copy "%sourceFile%" "%sourceFile%-%DATE:/=-% %TIME::=-%.bak"
echo. 2>%tempFile%
REM Rewrite file
set /a lineNum=0
set /a lowEnd=%refLine%-2
echo "Set low end to %lowEnd%"
set /a highEnd=%refLine%+23
echo "Set high end to %highEnd%"
FOR /F "delims=" %%i IN (%sourceFile%) DO (
set /a lineNum+=1
if !lineNum! GTR %lowEnd% (
if !lineNum! LSS %highEnd% (
echo "Skipping line #!lineNum!"
)
)
if !lineNum! LSS %lowEnd% (
echo "Writing Line !lineNum! %%i to temp file..."
echo %%i >> %tempFile%
)
if !lineNum! GTR %highEnd% (
echo "Writing Line !lineNum! %%i to temp file..."
echo %%i >> %tempFile%
)
)
REM get target filename only
for %%F in ("%sourceFile%") do set fname=%%~nxF
REM del original file and rename tempfile
echo "Deleting original file..."
echo Y | del "%sourceFile%"
echo "Renaming %tempFile% to %fname%"
ren "%tempFile%" "%fname%"
*Note that it will currently only find one instance of "no label". If you think there are multiple instances, just run the bat file again. If a person wanted to, they could find multiple instances and store the line numbers to a 3rd, temporary, text file then use that to determine more complicated bounds for filtering. Alternatively, you could put a loop around the entire thing and exit the loop when it doesn't find an instance of the searchPhrase.
#echo off
setlocal EnableDelayedExpansion
rem Get number of lines of sections to preserve in "copy.tmp" file
set last=0
(for /F "delims=:" %%a in ('findstr /N /C:"no label" input.ahk') do (
set /A copy=%%a-3-last, last=copy+26
echo !copy!
)) > copy.tmp
rem Read from input file
< input.ahk (
rem Process all "copy-lines, skip-26" sections
for /F %%n in (copy.tmp) do (
for /L %%i in (1,1,%%n) do (
set "line="
set /P "line="
echo(!line!
)
for /L %%i in (1,1,26) do set /P "line="
)
rem Copy the rest of lines after last section
findstr "^"
) > output.ahk
del copy.tmp
move /Y output.ahk input.ahk
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
)
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%