Counting the number of .txt files in a directory - batch-file

I need to count the number of .txt files in a Windows 10 directory.
I am starting with the following code as a batch-file:
#ECHO OFF
for %%f in (*.*) do echo %%f
Does anyone know how I can do it?

The method will most likely depend upon the rest of the script; but for the question only.
Probably the simplest method would be to use where.exe and find.exe together:
Where .:*.txt 2>Nul|Find /C /V ""
Should you wish to save the count as the value content of a variable, you can use a For /F loop incorporating either where.exe or the Dir command. Please note however that in both a standard For loop, (For %%A In (*.txt)), and when using the Dir command, (Dir *.txt), file extensions beginning with .txt are returned as opposed to those ending with .txt, returned by where.exe. In order to account for this, in my Dir version, I have piped the results through a findstr.exe to ensure that only .txt files are counted:
Where method:
#Echo Off
Set "#=0"
For /F %%A In ('"Where .:*.txt 2>Nul|Find /C /V """')Do Set "#=%%A"
Echo(%#%
Pause
Dir method:
#Echo Off
Set "#=0"
For /F %%A In ('"Dir/B/A-D-L *.txt 2>Nul|FindStr/I "txt$"|Find /C /V """'
)Do Set "#=%%A"
Echo(%#%
Pause

Related

Delete file with specific extension in batch file

I would like to recursively delete all files with a specific extension in a batch file.
I am aware of the following command:
del /s *.ext
However, this does on Windows also delete files with other extensions like e.g. .ext1 or .ext2 . The reason for this seems to be that the 8.3 file name of such a file ends with .ext and therefore also the files with longer extensions are matched.
I am looking for a replacement to the command above that recursively deletes all files with .ext extension but keeps files with longer extensions.
the where command works a bit differently (in regards to wildcards and short-names). Put a for /f loop around, and you're done. Your example would then translate to:
for /f "delims=" %%a in ('where /r . *.ext') do ECHO del "%%a"
Note: I disarmed the del command by just echoing it. Remove the ECHO after troubleshooting, when you are sure it does exactly what you want.
This also uses where.exe, but takes account of an issue not mentioned in another answer.
The issue is that where searches append each extension listed under %PATHEXT% to your .ext glob/spec. So whilst it will delete your target files, excluding files like .ext1 and .ext2 etc. it will now include for example, *.ext.com, *.ext.exe, *.ext.bat, *.ext.cmd, *.ext.vbs, *.ext.vbe, *.ext.js, *.ext.jse, *.ext.wsf, *.ext.wsh, and *.ext.msc etc.
The fix is to simply empty the content of %PATHEXT% before issuing the command. The following method does so within the For loop parenthsized command. As that is ran in another cmd.exe instance, it will not affect the instance in which the rest of your script resides:
#For /F "Delims=" %%G In ('"(Set PATHEXT=) & "%__APPDIR__%where.exe" /F /R "C:\SourceDir" "*.ext" 2>NUL"') Do #Del /A /F %%G
Obviously, you would modify, C:\SourceDir to contain the root location you require. The other current answers, use the current directory. If you want that, change it to ., or if you want the directory base as that of your batch file, change it to %~dp0.. Please do not remove any doublequotes.
Here are some alternative method examples, (please remember to adjust the drive/path/extension as needed)
If you wish to stick with the more traditional Dir command, then you could pipe the results through the findstr.exe utility, to exclude those matching the 8.3 names:
#For /F "Delims=" %%G In ('"Dir /B /S /A:-D "C:\SourceDir\*.ext" 2> NUL | "%__APPDIR__%findstr.exe" /I /L /E ".ext""') Do #Del /A /F "%%G"
You could also use the forfiles.exe utility for the task:
#"%__APPDIR__%forfiles.exe" /P "C:\SourceDir" /S /M "*.ext" /C "\"%__APPDIR__%cmd.exe\" /C \"If #IsDir==FALSE Del /A /F #File\""
Or this excruciatingly slow WMIC.exe utility method:
#"%__APPDIR__%wbem\WMIC.exe" DataFile Where "Drive='C:' And Path Like '\\SourceDir\\%%' And Extension='ext'" Delete 1> NUL 2>&1
Stephans answer is the shorter version, but you can use findstr's regex as well to match that the end of the name should be .ext
for /f "delims=" %%i in ('dir /b /s ^| findstr /IRC:"\.ext$"') do echo del "%%~i"

I need the filecount of each redTAG folder in a directory tree

I need to be able to report on the number of files in each redTAG folder within our 'shared drive'
each main directory in our departments shared drive has a redTAG folder. I need a batch file that will go through all folders and sub folders from a start point that contain 'redTAG' and report back a file count for those directories.
so the following structure:
root - 10 files,
root/redTAG - 2 files,
root/deliveries/ - 4 files,
root/deliveries/redTAG - 5 files,
root/deliveries/help - 4 files,
would report back:
root/redTAG 2,
root/deliveries/redTAG 5
code provided was my last successful attempt at any analysis of the folders etc.
#Echo off&SetLocal EnableExtensions EnableDelayedExpansion
(Echo Folders #Sub #Files ##Sub ##Files
FOR /D %%G in (*) DO (
PUSHD "%%G"
Set /A "Sub#=Files#=0,SUB##=Files##=0"
Set "Folders=%%~G "
FOR /F %%H in ('dir /a-d /b 2^>NUL^|find /C /V "" ') DO Set Files#=%%H
FOR /F %%I in ('dir /ad /b 2^>NUL^|find /C /V "" ') DO Set Sub#=%%I
if !Sub#! gtr 0 (
FOR /F %%H in ('dir /a-d /b /S 2^>NUL^|find /C /V "" ') DO Set Files##=%%H
FOR /F %%I in ('dir /ad /b /S 2^>NUL^|find /C /V "" ') DO Set Sub##=%%I
Set /A "Files##-=Files#,Sub##-=Sub#"
)
Set "Sub#= !Sub#!"
Set "Files#= !Files#!"
Set "Sub##= !Sub##!"
Set "Files##= !Files##!"
Echo !Folders:~,15! !Sub#:~-7! !Files#:~-7! !Sub##:~-7! !Files##:~-7!
POPD
)) > "count.txt"
start count.txt
any of my subsequent attempts have met with failure and hit the back of the bin. I don't need the export to a file but it helps. Some of this code was inherited from a previous colleague who wasn't great at annotation or help
This task could be done for example with:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
(for /F "delims=" %%I in ('dir redTAG /AD /B /S 2^>nul') do (
set "Folder=%%I"
set "FileCount=0"
for /F "eol=| delims=" %%J in ('dir "%%I" /A-D /B 2^>nul') do set /A FileCount+=1
call echo "%%Folder:\=/%%",%%FileCount%%
))> "count.csv"
endlocal
I don't know why output file count.csv should contain the folder paths with Linux/Mac directory separator / instead of Windows directory separator \, but the code replaces all backslashes by slashes in folder path before it is output.
The output file is a CSV file. The output format as posted in question would require much more code, but I don't see a real reason for this very special text format. The folder paths are enclosed in double quotes to produce a valid CSV file even if a folder path contains a comma.
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 /?
for /?
set /?
setlocal /?
Well, call is used here just to force Windows command processor to parse the echo command line a second time on each iteration of outer for loop in addition to first time parsing done already on parsing entire block starting with first ( and ending with last ).
See also: How does the Windows Command Interpreter (CMD.EXE) parse scripts?
This trick with call avoids usage of delayed expansion to process also redTAG folders correct containing one or more ! in folder path.
Read the Microsoft article about Using Command Redirection Operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on both 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 command line with using a separate command process started in background.

DOS CMD batch: Wrong full pathnames? (parameter extension ~f)

To list full pathnames of files in specified path I may use:
FOR /F "tokens=*" %G IN ('DIR /B "path\*.*"') DO echo %~fG
WRONG result: <current_directory>\*.*
ss64.com says: "If a filename with no drive letter/path is expanded to display a drive letter/path the command shell will assume; often incorrectly; that the file resides in the current directory."
This is quite a silly behaviour. However this is probably the problem as DIR here returns a bare filename.
IS THERE ANY WAY TO AVOID SUCH MISTAKE?
As it is very easy to make.
I know I can use /S option in DIR command, which makes the result be a full pathname but it also goes through subfolders which is undesired.
Using following syntax everything goes fine but I can't use the advantages of DIR command:
FOR %G IN ("path\*.*") DO echo %~fG
result: <path>\*.*
Do you have any tips or tricks how to work with DIR and full paths?
The environment variable CD contains at any time the path of current directory always without backslash at the end.
So you can use for your example:
#echo off
set "DirectoryPath=%CD%\path"
for /F "tokens=*" %%G in ('dir /B "path\*.*"') do echo %DirectoryPath%\%%G
Therefore whenever using DIR with bare output format without using also /S, it is necessary to determine first the directory path and reference this path within body of FOR loop.
Example on using fixed absolute paths:
#echo off
for /F "tokens=*" %%G in ('dir /B "C:\Temp\My Folder\*.*"') do echo C:\Temp\My Folder\%%G
Don't forget the double quotes with path or file name containing a space on other commands than echo!
How about using FORFILES? This will give you the full path for any desired folder:
forfiles /p C:\Some\Directory\ /c "cmd /c echo #path"
FORFILES is really mighty as it povides lots of options such as filters, rucursion into subfolders, etc. For more info check this website.
If you really need to use the dir command
#echo off
setlocal ENABLEDELAYEDEXPANSION
set _subdir=path
set _mask=*.*
call :get_absolute_path _prefix "%CD%\%_subdir%"
rem Iterate through a list of files, including files in subdirectories
for /f "tokens=*" %%A in ('dir /b /s /a:-d "%_prefix%\%_mask%"') do (
rem The current full file path
set _f=%%A
rem Cut the "%CD%\%_subdir%\" prefix from the current file path
set _f=!_f:%_prefix%\=!
rem Test whether the relative file path has a "subdir\" prefix:
rem split the relative file path by "\" delimiter and
rem pass %%B and %%C tokens (subdir and the remainder) to the loop
for /f "delims=\ tokens=1*" %%B in ("!_f!") do (
rem If the remainder is empty string then print the full file path
if "%%C"=="" echo %%A
)
)
endlocal
exit /b 0
:get_absolute_path
set %1=%~f2
exit /b 0

Batch find certain filenames then use the names in variable

I need help with a script that first finds all files in a directory with a certain string, then uses the filenames in a variable to be used in a script.
So:
Find files and filenames
Saves file?
Start some kind of loop? that changes a variable then executes the
belonging script
Repeat till all filenames have been used.
My code here..
#Echo off
For /r C:\work %%G In (*) Do #Findstr /M /S "string" > filenames.txt %%G
Set Var1=0
For %%G In (*) Do (
Var1=<filenames.txt (???)
script
script
I haven't writen "script" myself and friend help me with it, if you would like to see it do you need to wait until I can get to my other computer at home.
Thanks on beforehand!
Find files and filenames
Saves file
set "search=what I want to find"
(for /f "delims=" %%a in ('dir /a-d /b /s "C:\work" ^| findstr "%search%"') do echo (%%~fa)>filenames.txt
Start some kind of loop? that changes a variable then executes the belonging script
Repeat till all filenames have been used.
for /f "delims=" %%a in (filenames.txt) do (
REM here do something inside the loop
REM until all file names from filenames.txt were processed
)
This is designed to find files in c:\work that match a string, and echo the filenames.
#echo off
cd /d "c:\work"
for %%a in ("*string*") do (
echo "%%a"
)

batch file - counting number of files in folder and storing in a variable

I am very new to this. Please help me
I was trying to write a batch file program to count number of files in a folder and assign that to a variable and display it to verify that it has been stored
please help me with the syntax,
thank you in advance
-VK
I'm going to assume you do not want to count hidden or system files.
There are many ways to do this. All of the methods that I will show involve some form of the FOR command. There are many variations of the FOR command that look almost the same, but they behave very differently. It can be confusing for a beginner.
You can get help by typing HELP FOR or FOR /? from the command line. But that help is a bit cryptic if you are not used to reading it.
1) The DIR command lists the number of files in the directory. You can pipe the results of DIR to FIND to get the relevant line and then use FOR /F to parse the desired value from the line. The problem with this technique is the string you search for has to change depending on the language used by the operating system.
#echo off
for /f %%A in ('dir ^| find "File(s)"') do set cnt=%%A
echo File count = %cnt%
2) You can use DIR /B /A-D-H-S to list the non-hidden/non-system files without other info, pipe the result to FIND to count the number of files, and use FOR /F to read the result.
#echo off
for /f %%A in ('dir /a-d-s-h /b ^| find /v /c ""') do set cnt=%%A
echo File count = %cnt%
3) You can use a simple FOR to enumerate all the files and SET /A to increment a counter for each file found.
#echo off
set cnt=0
for %%A in (*) do set /a cnt+=1
echo File count = %cnt%
#echo off
setlocal enableextensions
set count=0
for %%x in (*.txt) do set /a count+=1
echo %count%
endlocal
pause
This is the best.... your variable is: %count%
NOTE: you can change (*.txt) to any other file extension to count other files.....
The mugume david answer fails on an empty folder; Count is 1 instead of a 0 when looking for a pattern rather than all files. For example *.xml
This works for me:
attrib.exe /s ./*.xml | find /v "File not found - " | find /c /v ""
This might be a bit faster:
dir /A:-D /B *.* 2>nul | find /c /v ""
`/A:-D` - filters out only non directory items (files)
`/B` - prints only file names (no need a full path request)
`*.*` - can filters out specific file names (currently - all)
`2>nul` - suppresses all error lines output to does not count them
To build for statement you should know some details at first.
for /F %%i in ('dir /A:-D /B *.* 2^>nul ^| find /c /v ""') do set "COUNT=%%i"
The example above would work, but if you want to copy paste it into another for-expression - might not.
The for /F ... expression by default has ; character as EOL character and space+tabulation characters as line separators.
If you use a file path as input in for-expression, then you can override these characters:
for /F "eol= delims=" %%i in (";My file path") do echo.Value: %%i
Where the end of eol= might not visible here. It is just a file path invalid not printable character, in this case - code 04. In most consoles and editors (except stackoverflow itself) you can type it as:
press ALT
type 04 from numeric keypad
release ALT
Another issue avoid here is always reset variable you want to use before the for-expression in case if for-expression is not executed:
set FILE=undefined
for /F %%i in (";My file path") do set "FILE=%%i"
echo.FILE=%FILE%
The fastest code for counting files with ANY attributes in folder %FOLDER% and its subfolders is the following. The code is for script in a command script (batch) file.
#for /f %%a in ('2^>nul dir "%FOLDER%" /a-d/b/-o/-p/s^|find /v /c ""') do set n=%%a
#echo Total files: %n%.
Change into the directory and;
attrib.exe /s ./*.* |find /c /v ""
EDIT
I presumed that would be simple to discover. use
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "batchfile.bat";
p.Start();
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
I run this and the variable output was holding this
D:\VSS\USSD V3.0\WTU.USSD\USSDConsole\bin\Debug>attrib.exe /s ./*.* | find /c /v "" 13
where 13 is the file count. It should solve the issue
for /F "tokens=1" %a in ('dir ^| findstr "File(s)"') do echo %a
Result:
C:\MyDir> for /F "tokens=1" %a in ('dir ^| findstr "File(s)"') do #set FILE_COUNT=%a
C:\MyDir> echo %FILE_COUNT%
4 // <== There's your answer
FOR /f "delims=" %%i IN ('attrib.exe ./*.* ^| find /v "File not found - " ^| find /c /v ""') DO SET myVar=%%i
ECHO %myVar%
This is based on the (much) earlier post that points out that the count would be wrong for an empty directory if you use DIR rather than attrib.exe.
For anyone else who got stuck on the syntax for putting the command in a FOR loop, enclose the command in single quotes (assuming it doesn't contain them) and escape pipes with ^.
I have used a temporary file to do this in the past, like this below.
DIR /B *.DAT | FIND.EXE /C /V "" > COUNT.TXT
FOR /F "tokens=1" %%f IN (COUNT.TXT) DO (
IF NOT %%f==6 SET _MSG=File count is %%f, and 6 were expected. & DEL COUNT.TXT & ECHO #### ERROR - FILE COUNT WAS %%f AND 6 WERE EXPECTED. #### >> %_LOGFILE% & GOTO SENDMAIL
)
With a for loop:
FOR /F %i IN ('dir /b /a-d "%cd%" ^| find /v /c "?"') DO set /a count=%i
echo %count%
Without/avoiding for loop:
(dir /b /a-d ^| find /v /c "?") | (set /p myVar=& cmd /c exit /b %myVar%)
set count=%errorlevel%
echo %count%
Tested in Win 10 cmd
Solution
Requires enabling Windows Subsystems For Linux
Ensure directoryToCount is set to the respective directory
SET directoryToCount=C:\Users\
dir %directoryToCount% > contentsOfDir.txt
echo cat contentsOfDir.txt ^| grep File > countFiles.sh
sh countFiles.sh
del countFiles.sh
del contentsOfDir.txt
Explanation
In both bash and batch environments, the output of a command can be redirected to a file using the > operator.
For example, echo hello world > myFile.txt will produce a file named myFile.txt with hello world as its text.
In a bash environment, one can cat the contents of a File and grep a particular line from the file containing a specified pattern.
For example, cat myFile.txt | grep hello will return lines containing hello
If Windows Subsystems for Linux is enabled, then one can execute sh from a Command Prompt to access a linux-like environment.
Therefore, we can solve this by doing the following
Use dir to acquire a list of files in the directory, as well as the number of files
Redirect the output of dir to a file (perhaps named contentsOfDir.txt).
Create a .sh file to grep for File from contentsOfDir.txt
Call the .sh file from command prompt to invoke the grep
Delete the .sh file
Delete contentsOfDir.txt

Resources