Finding filename by its count in a directory using cmd - windows

I have a directory with thousands of files, and I need to find specific filenames by file count (files are sorted by name or date).
Is there an easy way to make it using cmd commands?
Thank you.

If you want the 11th file then you want to skip the first 10. Here is a simple batch file that does the trick. Change the DIR command in the FOR IN() clause to get the results you need.
#echo off
for /f "skip=10 eol=: delims=" %%F in ('dir /b /a-d') do set "chosenFile=%%F" & goto break
:break
echo The 11th file is %chosenFile%
exit /b
If all you want to do is list the 11th file to the screen, then you can do this on the command line:
cmd /c "for /f "skip=10 eol=: delims=" %F in ('dir /b /a-d') do echo %F&exit"

Related

Windows CMD/BATCH Keep newest date stamped file

I have some files that I would like to sort through and keep the newest file.
I cannot do it by file attributes date modified or created, which I could do no problem.
Here is the naming convention of the files. FileABC_YYYYMMDD.txt
FileABC_20190201.txt
FileABC_20190125.txt
FileABC_20190118.txt
FileABC_20190111.txt
FileABC_20190104.txt
You can see that the date stamp is in the filename itself. These files are generated weekly. So I'd like to have a batch file loop through them and delete all but most currently dated file. I have really searched for how to do this best and I'm not finding much so I need ideas. I prefer a pure cmd solution but I'm open to powershell solutions as well.
What I am trying on my own is to parse out the date with...
#echo off
setlocal enabledelayedexpansion
for /f "tokens=* delims= " %%G IN ('dir/b /a-d "C:\Users\thomas.maus\Documents\Tom\dev\Test Batch Files\dev\sortbyFileDateName\FileABC_*.txt"') do (
set fileName=%%G
Set theDate=!fileName:~8,8!
echo !theDate!
)
Then I want to take those dates somehow from the results of the loop and do something like
if "%theDate%" GEQ "*****not sure what to put here*****" (
del *all the old files, also not sure what to put here*
)
How about this?
#echo off
for /f "skip=1" %%i in ('dir /o-n /b *.txt') do del %%i
If you just want to test it (see what it would delete) first, do:
#echo off
for /f "skip=1" %%i in ('dir /o-n /b *.txt') do echo %%i
If you do not care about the file dates but only the dates in the file names, you could do the following, given that the part FileABC is always the same and does not contain any _ on its own:
pushd "C:\Users\thomas.maus\Documents\Tom\dev\Test Batch Files\dev\sortbyFileDateName" && (
for /F "skip=1 delims= eol=|" %%F in ('
dir /B /A:-D "FileABC_????????.txt" ^
^| sort /R
') do (
del "%%F"
)
popd
)
Although sort /R does alphabetic sorting, this works because of your chosen date format, which ensures that alphabetic order equals alphanumeric one.
We just loop through the files, sorted by date in decending order, then skip the first file, now being the latest:
#for /f "skip=1" %%a in ('dir /b /o-d *.txt') do #echo #del %%a
Important!
This example will only echo the delete command as a safe measure so you do not delete files you should not have. To perform the actual delete, remove #echo from the line.
To understand more about the functions we used, run the following from cmd.exe
for /?
dir /?
As an additional option, just in case the filename prefix changes throughout and only the _YYYYMMDD.txt remains constant, you can still peform the task using that date as it is already alphabetically sortable.
Here's an example:
#Echo Off
Set "SrcDir=%UserProfile%\Documents\Tom\dev\Test Batch Files\dev\sortbyFileDateName"
For /F "Delims==" %%A In ('Set $ 2^>Nul') Do Set "%%A="
Set "_="
For /F Delims^=^ EOL^= %%A In ('Where "%SrcDir%":*_????????.txt 2^>Nul'
) Do Set "_=%%~nA" & Call Set "$%%_:~-8%%=%%A"
If Not Defined _ Exit /B
For /F "Tokens=1* Delims==" %%A In ('Set $ 2^>Nul') Do Set "_=%%B"
For /F Delims^=^ EOL^= %%A In ('Where "%SrcDir%":*_????????.txt^|Find /V "%_%"'
) Do Del /A /F "%%A"
This uses the fact that the Set command will output variables in alphabetical order.
Lines 2 to 4 just define and undefine the variables we will be using.
Lines 5 and 6 is a single line split over two lines for readability. This will set variables using the last eight characters of the files basenames, to the value of the full filename.
Line 7 is included to exit the script, just in case no .txt files with a basename ending with an underscore followed by eight characters were found in the directory set at line 2.
Line 8 is the special one here, it outputs each variable and corresponding value in alphabetical order. The output is set to a variable, which overwrites itself until the loop ends. This means that the newest file, last one alphabetically, is held with the value of the file named with the newest date.
Lines 9 & 10 are once again a single line split over two for readability. This loops over all matching files in the directory again and uses the Find command to exclude outputting the one which matches that held in the variable as the file with the newest date. Each file output is simply deleted using the Del command.
Please note that this script assumes you only have a single file with each date, as you've only stated that the files are generated weekly.

Batch file to count file types in sub directories

I need a batch file that counts certain file types in sub directories. In this case it's .txt and .xls files. At the end of the file it reports this back.
#echo off
REM get script directory
set scriptdir=%~dp0
REM change directory to script directory
cd /d %scriptdir%
setlocal
set txtcount=0
set xlscount=0
for %%x in ('dir *.txt /s ) do set /a txtcount+=1
for %%x in ('dir *.xls /s ) do set /a xlscount+=1
echo %txtcount% text files
echo %xlscount% .xls files
endlocal
pause
My batch file doesn't report back the correct count of files. I thought it might be continually counting but I've set the count variables to local so I'm not sure what's up.
There's three problems with your script:
You want to iterate over command output, so you need FOR /F
You're not using the "bare" /B format, i.e. DIR outputs more than just filenames
You're missing the closing single quote twice
Replace your loops with this:
FOR /F %%X IN ('DIR /S /B *.txt') DO SET /A "txtcount+=1"
FOR /F %%X IN ('DIR /S /B *.xls') DO SET /A "xlscount+=1"
You are very close, but you are missing the switch /B of the dir command, so the output contains a header and a footer, which are both included in the count. Therefore, change dir *.txt /s to dir *.txt /s /b (same for *.xls) and the count is going to be correct.
Besides that, there are typos: the closing ' is missing -- for %%x in ('dir *.txt /s') do .... In addition, the /F switch at for is missing, which is needed to capture the output of a command. (I assume these things are present in the true script as you would receive errors otherwise.)
Alternative Approach
To count the number of files, you could also do the following:
for /F "delims=" %%X in ('dir /B /S "*.txt" ^| find /C /V ""') do set "COUNT=%%X"
find /V "" searches for non-empty lines, hence all lines returned by dir /B /S are considered as matches; the /C switch simply lets find return the total amount of matching lines.

How to return the newest file from each sub-directory in Windows command line using batch

I am using batch script for windows command line on windows 7. I am currently trying to get the newest file from each sub directory and print them to the screen. For example, if I have:
C:\Home\Hi\Folder1\a 01/05/2016
C:\Home\Hi\Folder1\b 01/10/2016
C:\Home\Hi\Folder2\x 03/05/2016
C:\Homeh\Hi\Folder2\y 03/1/2016
It would return: folders b and x.
I have written some script to attempt this, but it only returns the newest file in the last directory which in my example would be x. The script is:
FOR /R "C:\Users\Maxx\Desktop\tools" %%G in (.) DO (
Pushd %%G
FOR /F %%I IN ('DIR %%G /B /O:D') DO SET NEWEST=%%I
ECHO %NEWEST%
Popd )
Echo "back home"
If anyone knows how to get the newest file from each subdirectory that would be great.
Note: I have looked at various other examples such as: Generate a list of the newest file in each subdirectory in windows batch, which has been very helpful in building what I have now, but ultimately it did not work.
You need to apply delayed expansion as you are writing and reading variable NEWEST within the same block of code:
setlocal EnableDelayedExpansion
for /R "C:\Users\Maxx\Desktop\tools" %%G in (.) do (
pushd "%%~G"
for /F %%I in ('dir "%%~G" /B /O:D') do set "NEWEST=%%I"
echo !NEWEST!
)
popd
echo back home
endlocal
Alternatively, replace echo %NEWEST% by call echo %%NEWEST%%:
for /R "C:\Users\Maxx\Desktop\tools" %%G in (.) do (
pushd "%%~G"
for /F %%I in ('dir "%%~G" /B /O:D') do set "NEWEST=%%I"
call echo %%NEWEST%%
)
popd
echo back home
In addition, I improved quoting.
#ECHO OFF
SETLOCAL
FOR /R "C:\106x" %%G in (.) DO (
Pushd "%%G"
SET "first="
FOR /F "delims=" %%I IN ('DIR . /a-d /B /O:-D 2^>nul') DO IF NOT DEFINED first SET first=Y&ECHO %%~dpI
Popd
)
Echo "back home"
GOTO :EOF
For each directory, go to the directory, clear a flag first, scan the directory for files (not directories), basic format, reverse-date order, suppressing any "file not found" reports from empty directories.
On finding the first (ie youngest) file set the flag first and report the filename - or parts of the filename you require.
Once first has been set, the report mechanism will not be invoked as if defined works on the current value of the variable.
Please note that when specifying dates, it's advisable to state the format that you are using - or at least use a date where the day number is >12, which should be adequate. For instance, your date "01/10/2016" may be interpreted as Jan 10th or Oct 1st, depending on the respondent's locale. "13/10/2016" or "10/13/2016" would make the issue obvious.

What's wrong with my batch script that moves the newest file from one folder to another?

I'm trying to put together a Windows batch script that moves the most recent file to a different directory. Here's my batch script mostly stolen from here:
FOR /F "tokens=*" %%G IN ('dir /b *.*') DO move %%G C:\Users\jrobinson\Desktop\ & exit /b
When I run this it moves every file in the folder. Interestingly, when I replace the MOVE command with a COPY command, the script copies only one file:
FOR /F "tokens=*" %%G IN ('dir /b *.*') DO copy %%G C:\Users\jrobinson\Desktop\ & exit /b
REM ---------------------------------------^^^^
Why is the move script moving every file while the copy script is only copying one file? Is it possibly because my script file is also in that folder and because of my edits, it is the most recent file?
Edit: Here are the contents of my source folder:
myBatchFile.bat
newest.txt
oldest.txt
second.txt
Of the *.txt files, newest.txt has the most recent modified date. Of all of the files regardless of extension, myBatchFile.bat has the most recent modified date given that I keep making edits to it to try to get it to work.
Edit #2: Here's a screenshot of my command window after running the first command above. This shows that all of the files in my source folder are copied when I only expect the newest file to be copied.
I'd use dir /b /o:-d /a:-d *.*, so the items are sorted by date (newest first) and directories are excluded. Otherwise the sort order is not clear, and directories like . (current) or .. (parent) might be returned unintentionally.
Instead of %%G I recommend using "%%~fG" to provide the full path, surrounded by doublequotes. Also the destination path should be enclosed in "" to avoid troubles with whitespaces.
The FOR /F should be changed to "delims=" in case the file name starts with a space (which I think is valid in Windows). "tokens=*" removed them.
Furthermore, I'd put parenthesis () around the code after do (so it is guaranteed and obvious that both commands move and exit /b are part of the loop context).
So all in all this leads to the following code:
FOR /F "delims=" %%G IN ('dir /b /o:-d /a:-d *.*') DO (move "%%~fG" "C:\Users\jrobinson\Desktop\" & exit /b)
Since the newest file is enumerated first and the for body contains exit /b (exit batch file), only that file is moved.
If you need to execute some other code after this line, replace exit /b by goto :SKIP (or any other valid label), and state the label (:SKIP) immediately after the FOR command block.
If the batch script containing the code herein is located in its working directory, moving it (in case it is the newest file) most likely results in unexpected behaviour. You can exclude the batch script itself by filtering it out using find like this:
FOR /F "delims=" %%G IN ('dir /b /o:-d /a:-d *.* ^| find /v /i "%~nx0"') DO (move "%%~fG" "C:\Users\jrobinson\Desktop\" & exit /b)
%~nx0 therein expands to the file name and extension of this script (see call /?).
I'm not sure I believe what you say. Because when I type the same command, is a file that I see first followed by the PAUSE command (or exit)
FOR /F "tokens=*" %G IN ('dir /b *.*') DO #echo %G & pause
So it always goes first action on the first file and the script will stop.
See this 5 secs gifv: http://i.imgur.com/kyHdN1Y.gifv with the following code:
#echo off
if exist ..\destination-test-folder\nul rd /s /q ..\destination-test-folder
if not exist ..\destination-test-folder\nul md ..\destination-test-folder
copy nul newest.txt>nul
copy nul oldest.txt>nul
copy nul second.txt>nul
dir /b .
pause>nul
echo: &echo For loop command: &echo:
for /f "tokens=*" %%g in ('dir /b "*.*"') do if "%%g" neq "%~nx0" move %%g ..\destination-test-folder>nul & echo pause is stated after each iteration & echo 1 file(s) moved. &pause>nul
echo: &echo list destination:
dir /b "..\destination-test-folder" &echo: &echo list source: &echo:
dir /b .
Just wanted to say thanks person: aschipfl
You are my hero.
here is the command I used to move all read only files to a sub folder "temp"
md temp
FOR /F "delims=" %%G IN ('dir /b /o:-d /a:R *.*') DO (move "%%~fG" "temp" )

Exclusion of files of certain extension

In a Windows cmd batch script named my.bat, I want to execute a command for all the files in the current directory except for the batch file my.bat.
I use below command in my.bat currently to run the command only for *.txt *.ppt, but really as new files of different extensions might be added to the folder and hence execution of this command by excluding one type of file extension (in my case *.bat) would be more readable/helpful.
FOR /F "delims=|" %%i IN ('dir /b *.txt *.ppt') DO echo %%i
Question is: How do I exclude that file alone with that particular file extension and make the for command execute on all files of all extensions except the excluded one?
FOR /F "tokens=* delims=|" %%i IN ('dir /b *.*') do if not %%~xi==.bat echo %%i
I have added tokens=* in as well otherwise you won't get full filenames if they have spaces.
To echo without the dot
setlocal enabledelayedexpansion
FOR /F "tokens=* delims=|" %%i IN ('dir /b *.*') do (
set e=%%~xi
set e=!e:.=!
echo !e!
)
This is providing that the file doesn't have any other dots, otherwise it will remove them too. This is a bit more sturdy than just removing the 4th character from the end though, as not all files have a 3 character extension.
You could pass the output of the dir /b command through findstr, like so:
FOR /F "delims=|" %%i IN ('dir /b ^| findstr /v /r "^my.bat$"') DO echo %%i
The /v option to findstr prints anything that doesn't match the parameter. The match is based on a regular expression that matches only lines that contain my.bat and nothing else.

Resources