Need help writing a batch-file - windows

The path to the folder and the format come to the input of the batch file
file(for example, txt) (as parameters of a batch file).
The folder must contain different files.
If such folder does not exist, then write “This folder does not exist” and
terminate the program.
If such a folder exists, then find everything in it and in its subfolders
files of the specified extension for which it is installed
archive attribute. Output the number of such files in
console
[Edit /]
This is what I have:
#echo off
if not exist %1 (echo "This folder does not exist" && pause && exit /B )
set /a count=0
for %%i in (dir %1\*.%2 /A:A /S ) do ( set /a count+=1 )
Echo in the folder %1, found %count% files with extension %2 and attribute
Archive
pause
The final count is incorrect

This in a batch file works for me. One problem is that without the /B option, it is also counting extra records coming back for directories. Your current "for" is actually counting the parts of the statement inside it, not the actual output in running the command.
#echo off
cls
SETLOCAL EnableDelayedExpansion
if not exist %1 (echo "This folder does not exist" && pause && exit /B )
set /a count=0
for /f "tokens=*" %%G in ('dir "%1\*.%2" /A:A /S /B') do (
set /a count+=1
)
Echo in the folder %1, found %count% files with extension %2 and attribute Archive
pause

Your line for %%i in (dir %1\*.%2 /A:A /S ) do ... is wrong in a few ways.
You want to process the output of a command: add /f and single-quoting the command.
You count every line of the output (including header and summary: add /b to list just the filenames.
if there are spaces in your parameters, it will fail: use %~n to remove any surrounding quotes and quote the full path.
So allthogether, the line should probably be:
for /f %%i in ('dir /b "%~1\*.%~2" /A:A /S') do ...
See for /? and dir /? for details.
(to be exact, you should also add "delims=" to get the whole filename instead of just its first word, but as you are just counting the lines, it wouldn't change anything)
Another thing: if not exist %1 (echo "This folder does not exist" is suboptimal. If no parameter was given, %1 is empty, the if results in if not exist (echo (tries to find a file named (echo and the command to be executed would be "This folder does not exist" which results in the error message '"This folder does not exist"' is not recognized as an internal or external command, operable program or batch file.
Safer Syntax: if not exist "%~1" (echo ...

Related

How to rename multiple images with an incrementing integer?

Let's say I have a couple of images and I need to rename them and on every iteration add an incremented number.
For this situation I have three images no matter how they name is and I want to rename them like this.
1239.jpg => file1.jpg
file.jpg => file2.jpg
image.jpg => file3.jpg
My commands executed in a command prompt window for this task are:
setlocal EnableDelayedExpansion
set filename=file
set counter=1
for /f "usebackq delims=*" %i in ('dir /b *.jpg') do (set /a counter+=1 ren "%i" "%filename%!counter!.jpg")
But this results in the error message Missing operator.
Can anyone help me with this?
The commands SETLOCAL and ENDLOCAL can be used only in a batch file. Please read this answer for details about the commands SETLOCAL and ENDLOCAL. These two commands do nothing on being executed in a command prompt window. It is necessary to start cmd.exe with option /V:ON to use delayed expansion in a command prompt window as explained by the help output on running cmd /? in a command prompt window.
The usage of usebackq requires enclosing the command line to be executed in ` instead of ' as usual. usebackq is mainly used for processing the lines of a text file of which name is specified in the round brackets enclosed in ".
The following command line with the two commands SET and REN is not of valid syntax. The command SET interprets everything after /a as arithmetic expression to evaluate. In this case the expression misses an operator between 1 and ren whereby ren would be interpreted here as name of an environment variable and not as command to execute next after set.
(set /a counter+=1 ren "%i" "%filename%!counter!.jpg")
The valid command line would be:
set /A "counter+=1" & ren "%i" "%filename%!counter!.jpg"
Enclosing the arithmetic expression in double quotes makes it clear for command SET where the arithmetic expression starts and where it ends. The conditional execution operator & is interpreted by Windows command processor before executing the command SET and results in execution of command REN after command SET even on SET would fail to evaluate the arithmetic expression.
A file renaming task done with Windows command processor is no easy to achieve if
the file extension of the files should not change and
files with any name including those with one or more &()[]{}^=;!'+,`~ should be supported and
there can be already files in the directory with one of the new file names.
For testing the batch file below I created first in a directory following files:
file.jpg
file1.jpg
file2.jpg
file3.jpg
file 4.jpg
File8.jpg
hello!.jpg
image.jpg
The directory was on a FAT32 drive. The file systems FAT16, FAT32 and exFAT return a list of matching directory entries not sorted by name as NTFS which means the list output by command DIR in the main FOR loop in code below is in an unsorted and therefore unpredictable order.
It would be of course possible to append the DIR option /ON to get the list of file names ordered by DIR according to name, but in fact that is not real help in this case, especially because of DIR makes a strict alphabetical sort and not an alphanumeric sort.
A strict alphabetic sort returns a list of ten file names as file1.jpg, file10.jpg, file2.jpg, file3.jpg, ..., file9.jpg while an alphanumeric sort returns a list of ten file names as file1.jpg, file2.jpg, file3.jpg, ..., file9.jpg, file10.jpg.
So here is the commented batch file for this file rename task:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "FileName=file"
rem The user can run this batch file with a folder path in which all *.jpg
rem files should be renamed with an incremented number. Otherwise the
rem directory of the batch file is search for *.jpg files to rename.
if not "%~1" == "" (
pushd "%~1" || exit /B
) else (
pushd "%~dp0" || exit /B
)
set "FileCount=0"
set "DelayedLoopCount=0"
set "DelayedRenameCount=0"
rem Remove all existing environment variables in local environment of which
rem name starts with DelayedRename_ whereby the underscore is very important
rem because there is also the environment variable DelayedRenameCount.
for /F "delims==" %%I in ('set DelayedRename_ 2^>nul') do set "%%I="
rem Get a captured list of all *.jpg files in current directory and then
rem rename one file after the other if that is possible on no other file
rem has by chance already the new file name for the current file.
for /F "eol=| delims=" %%I in ('dir *.jpg /A-D /B 2^>nul') do call :RenameFile "%%I"
goto DelayedRenameLoop
:RenameFile
set /A FileCount+=1
set "NewName=%FileName%%FileCount%%~x1"
rem Has the file case-sensitive already the right name?
if %1 == "%NewName%" goto :EOF
rem Is the new file name the same as the current name
rem with exception of the case of one or more letters?
if /I %1 == "%NewName%" (
echo Rename %1 to "%NewName%"
ren %1 "%NewName%"
goto :EOF
)
rem Is there no other file which has already the new name?
if not exist "%NewName%" (
echo Rename %1 to "%NewName%"
ren %1 "%NewName%"
goto :EOF
)
rem Another file or folder has already the new name. Remember the name
rem of this file and the new file name with an environment variable for
rem a delayed rename after all other files have been renamed as far as
rem possible.
set /A DelayedRenameCount+=1
set "DelayedRename_%DelayedRenameCount%=|%~1|%NewName%"
goto :EOF
rem It could happen that "file15.jpg" should be renamed to "file3.jpg"
rem while "file3.jpg" exists already which should be renamed to "file12.jpg"
rem while "file12.jpg" exists already which should be renamed to "file20.jpg".
rem This extra loop is used for such worst case scenarios which is executed
rem in a loop until all files have been renamed with a maximum of 50 loop
rem runs in case of one file cannot be renamed and therefore blocking
rem renaming of another file. An endless running loop should be avoided.
rem A file cannot be renamed if a folder has by chance the new file name.
rem A file cannot be renamed if an application has opened the file with
rem a sharing access mode preventing the rename of the file as long as
rem being opened by this application.
:DelayedRenameLoop
if %DelayedRenameCount% == 0 goto EndBatch
for /F "tokens=1-3 delims=|" %%I in ('set DelayedRename_ 2^>nul') do if not exist "%%K" (
echo Rename "%%J" to "%%K"
ren "%%J" "%%K"
set "%%I"
set /A DelayedRenameCount-=1
)
set /A DelayedLoopCount+=1
if not %DelayedLoopCount% == 50 goto DelayedRenameLoop
:EndBatch
popd
endlocal
This batch file output on execution:
Rename "file3.jpg" to "file4.jpg"
Rename "file 4.jpg" to "file5.jpg"
Rename "File8.jpg" to "file6.jpg"
Rename "hello!.jpg" to "file7.jpg"
Rename "image.jpg" to "file8.jpg"
Rename "file2.jpg" to "file3.jpg"
Rename "file1.jpg" to "file2.jpg"
Rename "file.jpg" to "file1.jpg"
The files in the directory were finally:
file1.jpg
file2.jpg
file3.jpg
file4.jpg
file5.jpg
file6.jpg
file7.jpg
File8.jpg
What about the last file?
It has the file name File8.jpg instead of file8.jpg although executed was ren "image.jpg" "file8.jpg". Well, FAT32 is a bit problematic regarding to updates of the file allocation table on a table entry changes only in case of one or more letters.
The solution is using this batch file with two extra FOR loops with # as loop variable and optimized by removing the comments.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "FileName=file"
if not "%~1" == "" (pushd "%~1" || exit /B) else (pushd "%~dp0" || exit /B)
set "FileCount=0"
set "DelayedLoopCount=0"
set "DelayedRenameCount=0"
for /F "delims==" %%I in ('set DelayedRename_ 2^>nul') do set "%%I="
for /F "eol=| delims=" %%I in ('dir *.jpg /A-D /B 2^>nul') do call :RenameFile "%%I"
goto DelayedRenameLoop
:RenameFile
set /A FileCount+=1
set "NewName=%FileName%%FileCount%%~x1"
if %1 == "%NewName%" goto :EOF
if /I %1 == "%NewName%" (
echo Rename %1 to "%NewName%"
ren %1 "%NewName%"
goto :EOF
)
if not exist "%NewName%" (
echo Rename %1 to "%NewName%"
ren %1 "%NewName%"
for %%# in ("%NewName%") do if not "%%~nx#" == "%NewName%" ren "%%~nx#" "%NewName%"
goto :EOF
)
set /A DelayedRenameCount+=1
set "DelayedRename_%DelayedRenameCount%=|%~1|%NewName%"
goto :EOF
:DelayedRenameLoop
if %DelayedRenameCount% == 0 goto EndBatch
for /F "tokens=1-3 delims=|" %%I in ('set DelayedRename_ 2^>nul') do if not exist "%%K" (
echo Rename "%%J" to "%%K"
ren "%%J" "%%K"
for %%# in ("%%K") do if not "%%~nx#" == "%%K" ren "%%~nx#" "%%K"
set "%%I"
set /A DelayedRenameCount-=1
)
set /A DelayedLoopCount+=1
if not %DelayedLoopCount% == 50 goto DelayedRenameLoop
:EndBatch
popd
endlocal
The result of this enhanced batch file is even on FAT32:
file1.jpg
file2.jpg
file3.jpg
file4.jpg
file5.jpg
file6.jpg
file7.jpg
file8.jpg
The reason for using | as string separator on execution of
set "DelayedRename_%DelayedRenameCount%=|%~1|%NewName%"
resulting, for example, in execution of
set "DelayedRename_1=|file.jpg|file1.jpg"
set "DelayedRename_2=|file1.jpg|file2.jpg"
set "DelayedRename_3=|file2.jpg|file3.jpg"
is that the vertical bar is not allowed in a file folder name. So it is a very good character to separate the name of the environment variable with the equal sign appended from current file name and from new file name. This makes it possible to use later delims=| for renaming the file and deleting the environment variable.
See also the Microsoft documentations:
Naming Files, Paths, and Namespaces
Using command redirection operators
The equal sign is allowed in a file name. It is even possible that a *.jpg file has as file name =My Favorite Picute=.jpg which is another reason for using | to get executed for example
set "DelayedRename_4=|=My Favorite Picute=.jpg|file9.jpg"
which later results in assigned DelayedRename_4= to loop variable I, =My Favorite Picute=.jpg to loop variable J and file9.jpg to loop variable K in the FOR loop doing the delayed file renames.
Note: Each FOR loop with '...' in the round brackets results
in starting in background one more command process with %ComSpec% /c '...' and
capturing the output written to handle STDOUT like the output of the cmd.exe internal commands DIR and SET
while cmd.exe processing the batch file waits until started cmd.exe terminated (closed) itself after execution of the command line
and then processing the captured lines one after the other by FOR with ignoring empty lines and lines starting with the defined end of line character after doing the string delimiting which is the reason why eol=| is used on main FOR loop as a file name can start with default end of line character ; and which of course should not be ignored here.
The redirection operator > must be escaped with caret character ^ on those FOR command lines to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir or set command line in the separate command process started in background.
The batch file does not use delayed expansion as this would cause troubles on a file name having one or more exclamation marks which would be interpreted as beginning/end of a delayed expanded environment variable reference on command lines like ren "%%J" "%%K". Therefore a subroutine is used for the main file rename loop on which it is necessary to access the two incremented counter values.
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 /?
dir /?
echo /?
endlocal /?
exit /?
goto /?
if /?
popd /?
pushd /?
rem /?
ren /?
set /?
setlocal /?
I suggest further to look on:
Microsoft documentation for the Windows Commands
SS64.com - A-Z index of Windows CMD commands
Where does GOTO :EOF return to?
Single line with multiple commands using Windows batch file
Symbol equivalent to NEQ, LSS, GTR, etc. in Windows batch files
How does the Windows Command Interpreter (CMD.EXE) parse scripts?
Why is no string output with 'echo %var%' after using 'set var = text' on command line?

How to first order files in folder by date and then concatenate their contents into a new file?

I have a folder with four to five text files in it.
My overall aim is the following: Create one big file which has the content of the separate files, but in the right order.
I can use the time-stamp of each file to start with the oldest file up to the youngest.
My process right now looks like this:
Order the files in this folder by date.
Create a temporary file and write the content from the separate files into this file.
Output the temporary file.
In code I do something like this:
set temp_concat=%temp_dir%\temp_concat.log
echo %temp_concat%
echo aiu_logs > %temp_concat%
for /f "delims=" %%? in ('dir /b /o:d %Folder%*') do (
for /f "delims=" %%K in (%Folder%%%?) do (
echo %%K >>%temp_concat%
)
)
The above code seems to work as my temp_concat is very large.
However, this takes much much longer than expected. I have to wait about 40 seconds just to merge three files in my case.
Is there some better way of merging some amount of files, but keep them in the correct order by date?
This batch file uses the suggestion posted by Sqashman to use a FOR loop to create the arguments string for command COPY used to concatenate the file contents into a single file in the order of oldest modified file first and newest modified file last.
#echo off
setlocal EnableExtensions EnableDelayedExpansion
set "Folder=%~dp0"
if not "%~1" == "" set "Folder=%~1"
set "Folder=%Folder:/=\%"
if not "%Folder:~-1%" == "\" set "Folder=%Folder%\"
set "ResultsFile=%Folder%Results.log"
del "%ResultsFile%" 2>nul
set "Arguments="
for /F "eol=| delims=" %%I in ('dir /A-D-H /B /O:D "%Folder%*" 2^>nul') do if not "%%~fI" == "%~f0" set "Arguments=!Arguments! + "%%I""
if defined Arguments (
echo aiu_logs>"%ResultsFile%"
copy /B "%ResultsFile%"%Arguments% "%ResultsFile%" >nul
)
endlocal
The batch file as is does not work if either the folder path or one of the file names contains one or more exclamation marks ! because of an enabled delayed environment variable expansion.
Further the command line length is limited and so this batch file does not work on too many files must be concatenated depending on length of the file path of each file and the length of the file names.
A better solution would be using following batch file:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "Folder=%~dp0"
if not "%~1" == "" set "Folder=%~1"
set "Folder=%Folder:/=\%"
pushd "%Folder%" 2>nul
if errorlevel 1 goto EndBatch
set "ResultsFile=Results.log"
del "%ResultsFile%" 2>nul
set "Arguments="
for /F "eol=| delims=" %%I in ('dir /A-D-H /B /O:D * 2^>nul') do if not "%%~fI" == "%~f0" call set "Arguments=%%Arguments%% + "%%I""
if defined Arguments (
echo aiu_logs>"%ResultsFile%"
copy /B "%ResultsFile%"%Arguments% "%ResultsFile%" >nul
)
popd
:EndBatch
endlocal
A folder path with one or more exclamation marks is no problem anymore. Also the file names can contain ! because of delayed expansion is not used by this batch file which is a bit slower than the first batch file.
The folder with the files to concatenate is made the current directory by this batch file. For that reason more file names can be specified as arguments on COPY command line in comparison to first batch file because of the file names are specified without path. But the number of file contents which can be merged with this batch file is nevertheless limited by the maximum length of a Windows command line respectively the maximum length of an environment variable value.
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 /?
copy /?
dir /?
echo /?
endlocal /?
for /?
goto /?
if /?
popd /?
pushd /?
set /?
setlocal /?
Read also the Microsoft article about Using command redirection operators for an explanation of > and 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir command line with using a separate command process started in background with %ComSpec% /c and the DIR command line between the two ' appended as further arguments.
The second FOR /F does not contain a command. It contains a filename. I have not tested this, but perhaps:
set temp_concat=%temp_dir%\temp_concat.log
echo %temp_concat%
echo aiu_logs > "%temp_concat%"
for /f "delims=" %%? in ('dir /b /o:d "%Folder%"') do (
if not "%%~f?" == "%~f0" (
type %%? >>"%temp_concat%"
)
)
This will concatenate all files in the "%Folder%" directory. Paths should be quoted in case there are special characters in them.

How to get file names of files in working directory with more than 30 characters in file name written into a text file?

The batch file code used by me:
for /r %%f in (*) do (
echo %%~nf >>testy.txt
)
for /f "tokens=*" %%a in (testy.txt) do (
set _temp=%%a
for /f "tokens=30*" %%g in (_temp) do (
echo large=%%g>>length.txt
)
)
It should create length.txt having characters at 30th place and above, but it is failing in the 3rd for loop which should create length.txt.
This can be done with following batch file on no file name of a non-hidden file contains an exclamation mark.
#echo off
setlocal EnableExtensions EnableDelayedExpansion
(for %%I in (*) do (
set "FileName=%%~nI"
if not defined FileName set "FileName=%%~xI"
if not "!FileName:~30!" == "" echo %%~nxI
))>length.txt
rem Delete length.txt if being an empty file.
for %%I in (length.txt) do if %%~zI == 0 del length.txt
endlocal
The next batch file is slower, but processes correct also non-hidden files with a ! in file name.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
(for %%I in (*) do (
set "FileName=%%~nI"
if not defined FileName set "FileName=%%~xI"
setlocal EnableDelayedExpansion
if not "!FileName:~30!" == "" echo %%~nxI
endlocal
))>length.txt
rem Delete length.txt if being an empty file.
for %%I in (length.txt) do if %%~zI == 0 del length.txt
endlocal
Both batch files handle the name of a file like .htaccess as file with file name being .htaccess and having no file extension while Windows command processor handles such files as file name being empty and file extension is .htaccess.
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.
del /?
echo /?
endlocal /?
for /?
if /?
rem /?
set /?
setlocal /?
Some things are much easier done in PowerShell
To be on topic wrapped in a batch file
:: Q:\Test\2018\11\19\SO_53379317.cmd
Echo off
Set Len=30
For /f "delims=" %%A in ('
powershell -NoP -C "(Get-ChildItem '%CD%' -File| Where-Object {$_.Name.Length -gt %Len%}).Name.SubString(%Len%)"
') Do Echo %%A
In case you want the length of drive, path, name and extension replace .Name with .FullName
The file name without extansion would be .BaseName
THe -File parameter requires PSv3+ (present in Windows 8+)
As long as your directory has standard filenames with extensions, you could probably use something far more simple:
#Where .:"??????????????????????????????*.*">"length.txt"
This should output all files in the current directory containing 30 or more characters in their filenames, (ignoring the extension).

FINDSTR: help understanding results. Returns nothing, but no error when there is one expected?

I am writing a batch file. part of the program will compare the list of files in a 'source' folder. With the contents of a list in a text file.
I loop through each file in the folder, and search for its filename in the text file using FINDSTR
Everything works until there is a filename in the source folder that doesnt exist in the text file.
the findstr code:
for /f %%o in ('findstr %name% old.txt') do (
echo o=%%o >> result.txt
if %%o==%name% (
echo %name% exists
) ELSE (
echo %name% does not exists
)
)
Again, the problem occurs when FINDSTR searches for a filename that is not in the text file.
when it reaches that point it outputs the variable %%o as being '%o' and echos nothing. So it sends nothing to the results.txt.
This doesnt trigger an ERRORLEVEL change but also will not echo anything. I have tried outputing the errorlevels but they are also empty. I just dont understand what FINDSTR is doing in this instance.
the FULL batch file: (its my first one. forgive any mistakes)
::return the raw (/b) list of files
FORFILES /p %~dp0source\ /s /m "*.cr2" /C "cmd /c echo #path" > new.txt
::pull file path for each file and send to subroutine
for /f %%n in ('FORFILES /p %~dp0source\ /s /m "*.cr2" /C "cmd /c echo #path"') do (
call :dequote %%n
)
::subroutine for removing quotes
::and returning the filename, extension, and path
:dequote
set fullPath=%~f1
set fileName=%~n1
set fileExt=%~x1
set filePath=%~dp1
set name=%fileName%& set npath=%filePath%& set ext=%fileExt%& set fpath=%fullPath%
echo %fpath%
echo %npath%
echo %name%
echo %ext%
for /f %%o in ('findstr %name% old.txt') do (
echo o=%%o >> result.txt
if %%o==%name% (
echo %name% exists
) ELSE (
echo %name% does not exists
)
)
This only happens on the last filename sent to findstr. Any suggestions or direction would be very appreciated. Ive tried and read everything I can get my hands on.
Thank You for your time.
UPDATE: 9-9-15
Here is the working final batch file i created using the help on this page. It creates a hotfolder that will edit any new files added to it until you stop the script from running:
:start
:: return the raw (/b) list of files and full path to source text
FORFILES /p %~dp0source\ /s /m "*.cr2" /C "cmd /c echo #path" > source.txt
IF %ERRORLEVEL% EQU 1 goto :start
::join new and old data, return only what is shared in common (/g)
findstr /I /L /G:"source.txt" "output.txt" > found.txt
IF %ERRORLEVEL% EQU 1 copy /y source.txt notFound.txt
::join found file names and source filenames, return those that do not have a match
findstr /I /L /V /G:"found.txt" "source.txt" >> notFound.txt
IF %ERRORLEVEL% EQU 2 echo error no match
::for each line of notFound.txt, dequote and break apart
for /f %%n in (notFound.txt) do (
echo n=%%n
call :dequote %%n
)
:dequote
set fullPath=%~f1
set fileName=%~n1
set fileExt=%~x1
set filePath=%~dp1
set name=%fileName%& set npath=%filePath%& set ext=%fileExt%& set fpath=%fullPath%
echo %fpath%
echo %npath%
echo %name%
echo %ext%
cd %nPath%
if NOT [%1]==[] (
echo converted %name%
convert -negate -density 600 -colorspace gray flatField.cr2 %name%%ext% -compose Divide -composite %name%.tif
move %name%.tif %~dp0output
cd %~dp0
del notFound.txt
copy /y source.txt output.txt
) ELSE (
echo end of batch else
cd %~dp0
)
Loop variables must be referenced with %% in a batch file because percent sign has a special meaning and must be therefore escaped with another percent sign in a batch file to specify it literally. This is the reason why on running the batch file with echo on in a command prompt window results in getting %%o in the batch file displayed as %o on execution.
Command FOR as used in
for /f %%o in ('findstr %name% old.txt') do
processes the output written to stdout by the called command findstr. But findstr does not write anything to standard output when it searched for one or more strings in a file and could not find any matching string in any line of the file.
So command for can't process anything and therefore none of the commands after do are processed at all in this case.
Assuming the list file contains only file names without path, the following commented batch file can be used to get with 1 execution of command dir and just 1 or 2 executions of console application findstr the two lists containing the file names in folder being found and being not found in the list file. The batch file is written for not producing empty files.
#echo off
setlocal
set "ListFile=C:\Temp\List.txt"
if not exist "%ListFile%" goto NoListFile
set "SourceFolder=C:\Temp\Test"
if not exist "%SourceFolder%\*" goto NoSourceFolder
set "AllFileNames=%TEMP%\AllFileNames.txt"
set "FoundFileNames=%TEMP%\FoundFileNames.txt"
set "NotFoundFileNames=%TEMP%\NotFoundFileNames.txt"
rem Get alphabetic list of files in source folder without path.
dir /A /B /ON "%SourceFolder%" >"%AllFileNames%"
rem Find all file names in list file with a case-insensitive
rem search matching completely a file name in list file and
rem output the found file names to another list file.
%SystemRoot%\system32\findstr.exe /I /L /X "/G:%AllFileNames%" "%ListFile%" >"%FoundFileNames%"
if errorlevel 1 goto NoFileNameFound
rem Find all file names with a case-insensitive search found
rem before in all file names list and output the lines not
rem containing one of the file names to one more list file.
%SystemRoot%\system32\findstr.exe /I /L /V "/G:%FoundFileNames%" "%AllFileNames%" >"%NotFoundFileNames%"
if errorlevel 1 goto AllFileNamesFound
rem Some file names are found in list file and others not.
del "%AllFileNames%"
goto :EndBatch
:NoFileNameFound
move /Y "%AllFileNames%" "%NotFoundFileNames%"
del "%FoundFileNames%"
goto EndBatch
:AllFileNamesFound
del "%AllFileNames%"
del "%NotFoundFileNames%"
goto EndBatch
:NoListFile
echo %~f0:
echo Error: No list file %ListFile%
goto EndBatch
:NoSourceFolder
echo %~f0:
echo Error: No folder %SourceFolder%
:EndBatch
endlocal
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.
del /?
dir /?
findstr /?
goto /?
if /?
move /?
set /?
This is a method to give you a list of filenames which don't exist in the file.txt
#echo off
cd /d "c:\folder\to\check"
for %%a in (*) do findstr /i "%%~nxa" "file.txt" >nul || echo "%%a" is missing
pause
It uses %%~nxa instead of %%a in case subdirectories are used at some point.

Gathering list of file extensions - "The command line is too long" workaround

I am currently using this batch file to scan through a Windows file system and save a .txt document of all the file extensions in that system:
Cmd Line Command:
NameOfBatchFile.bat >List.txt
BatchFile Code:
#echo off
set target=%1
if "%target%"=="" set target=%cd%
setlocal EnableDelayedExpansion
set LF=^
rem Previous two lines deliberately left blank for LF to work.
for /f "tokens=*" %%i in ('dir /b /s /a:-d "\\PathOfMyWindowsDirectory"') do (
set ext=%%~xi
if "!ext!"=="" set ext=FileWithNoExtension
echo !extlist! | find "!ext!" > nul
if not !ERRORLEVEL! == 0 set extlist=!extlist!!ext!:
)
echo %extlist::=!LF!%
endlocal
The code works great on small folders but if I provide it a folder with too many subfolders, the command line will process then provide the following error:
The command line is too long.
The command line is too long.
The command line is too long.
The command line is too long.
The command line is too long.
The command line is too long.
The command line is too long.
The input line is too long.
I can't edit the filesystem to decrease subfolders, does anyone know another way to get this to work?
The problem in your code is the concatenation of elements inside a variable, that can generate a long list of extensions that will end generating a excesively long command line.
#echo off
setlocal enableextensions disabledelayedexpansion
set "target=%~1"
if "%target%"=="" set "target=%cd%"
for /r "%target%" %%a in (*) do if not defined "\%%~xa\" (
if "%%~xa"=="" (echo(FileWithNoExtension) else (echo(%%~xa)
set ""\%%~xa\"=1"
)
endlocal
This uses the environment to store the information of seen extensions by setting a variable for each one. If the variable is not set, this is the first time the extension is found and is echoed to console.
I think this is the fastest way to get the result to this problem.
#echo off
setlocal
set target=%1
if "%target%"=="" set target=%cd%
for /R "%target%" %%a in (*.*) do set ext[%%~Xa]=1
for /F "tokens=2 delims=[]" %%a in ('set ext[') do (
if "%%a" equ "=1" (
echo FileWithNoExtension
) else (
echo %%a
)
)
Previous method may be easily modified in order to get the number of files that have each extension; just modify the set ext[%%~Xa]=1 by set /A ext[%%~Xa]+=1 and modify the tokens in the for /F accordingly.
This gives you a sorted list of all the extensions very quickly.
#echo off
set "target=%~1"
if "%target%"=="" set target=%cd%
dir "%target%" /b /s /a-d |repl ".*(\..*)" "$1" |repl ".*\\.*" "FileWithNoExtension"|sort|uniq >file.txt
This uses a helper batch file called repl.bat (by dbenham) - download from: https://www.dropbox.com/s/qidqwztmetbvklt/repl.bat
This uses a helper batch file called uniq.bat (by aacini) - download from: https://www.dropbox.com/s/71o38a4ljnqgqjh/uniq.bat
Place repl.bat and uniq.bat in the same folder as the batch file or in a folder that is on the path.

Resources