I'm trying to get the name and time of the oldest file in a folder (By modification date).
I can get the name without any problem using this code
for /f "delims=" %%x in ('dir /b /o-d /a-d %currentfolder% ^| grep -v / ') do (SET FILEINFO=%%x )
From my understanding swapping the %%x for %%~tx should return the modified time instead of the filename. But I get a blank instead.
for /f "delims=" %%x in ('dir /b /o-d /a-d %currentfolder% ^| grep -v / ') do (SET FILEINFO=%%~tx )
The following code returns the time of a file in the folder but not the oldest one.
for %%a in (%currentfolder%\*) do (set LAST_TIME=%%~ta)
I tried to combine the first and last code to get the time of the oldest file but it also returns a blank.
for %%b in (%currentfolder%\%FILEINFO%) do (set MAXDATE=%%~tb)
What is the error here ? How can I solve this ?
Thank you very much for the help
You are almost there:
#echo off
set "currentfolder=D:\some directory\"
pushd "%directory%"
for /f "delims=" %%i in ('dir /b /a-d /od') do (
set "file=%%i"
set "moddate=%%~ti"
goto :done
)
popd
:done
echo %file% %moddate%
So we sort by date (oldest first) then set the first filename as %file% and it's date to %moddate% then we exit the loop so it does not do the same for the other files in the folder.
The problem is caused by the fact that your current working directory referred to by for /F is not the same as the directory you are searching files in by dir.
This can be fixed like this (omitting grep as I do not understand its purpose here):
rem // Temporarily change to the directory containing the files of interest:
pushd "%currentfolder%"
rem /* The current working directory is now the target directory;
rem thus both `dir` and `for /F` work in the same directory: */
for /F "delims=" %%x in ('dir /B /A:-D /O:-D') do (set "FILEINFO=%%~tx")
rem // Restore the former working directory:
popd
rem // Just output the gathered information:
echo/%FILEINFO%
Alternatively, the pushd command line could be replaced by cd /D "%currentfolder%" when popd is removed, given that you do not need the original working directory to be restored.
To understand what was going on in your original code, let us assume:
the current working directory is C:\TEST;
the content of variable currentfolder is D:\DATA;
the directory C:\TEST contains nothing but the batch file;
the directory D:\DATA contains a file called some.txt;
The command line dir /b /o-d /a-d %currentfolder% returns only pure file names (due to its option /B), so based on the predefined sample data, the output would be:
some.txt
Now this text is captured by the for /F loop. Now the last modification date/time is queried by %%~tx, which of course requires access to the file system. Remember that the current working directory is C:\TEST, so the for /F loop tries to gather the information from the following file:
C:\TEST\some.txt
Since such a file does not exist, the output is blank.
To prove that, simply place a new file some.txt into the directory C:\TEST, then you would receive the last modification date/time of that file.
Related
I have a windows directory which contains folders with names like:
Lot 1
Lot 2
Lot 5
Lot A
Block A
Block C
Each of these folders contains PDF survey drawings. The names of the files are inconsequential. My goal is to prefix each PDF in ONLY LOT FOLDERS with an edited version of the name of its parent folder. Instead of adding the prefix Lot 1_ to the filenames of files in folder Lot 1 I would like to add L1_ to the filename.
Currently, I have a batch file which will add any prefix entered into a prompt to all PDFs in current folder. This means I have to go into each folder & run the batch script. This is tedious as I have thousands to deal with.
This is what the code looks like:
Set /p prefix="Enter Prefix to add to file names: "
FOR /f "delims=" %%F IN ('DIR /a-d /b *.PDF') DO (RENAME "%%F" %prefix%_"%%F")
I have been messing around trying to create a batch file to iterate through all folders with Lot and a space in their names and so far all I can do is use a for loop to get all the Lotwhatevernumber names and output them to a text file.
This is what that code looks like:
for /f "delims=" %%F in ('dir /A:D /b Lot*') do echo %%F >> folders.txt
and then I get text file with:
Lot 1
Lot 2
Lot 5
Lot A
I can also output just the number portion of the Folder name. That code:
for /f "tokens=2" %%F in ('dir /A:D /b Lot*') do echo %%F >> folders2.txt
and then I get text file with:
1
2
5
A
I felt like I was real close with that last one, but what I tried to do was instead of echoing to folders2.txt I wanted to enter another for loop where I would rename each file in Lot %%F and add a prefix of L%%F and the rest of the filename.
Anyone has any ideas?
Someone from another forum gave me this which works but the first file in each Lot folder gets named twice...I can't figure out why.
Someone on another forum provided the following which works but the first file in each Lot folder gets labelled L_ twice and I don't know why....
#echo off & setlocal
for /f "tokens=*" %%a in ('dir /b /ad lot*') do (
for %%b in ("%%a"\*.pdf) do call :xx "%%~dpb" "%%~nxb"
)
goto :eof
:xx
set z=%~1
set z=%z:~0,-1%
for %%c in ("%z%") do set k=%%~nc
set k=%k:lot =L%
echo ren %1%2 %k%_%2
ren %1%2 %k%_%2
What about this:
#echo off
rem // Switch to the target directory:
pushd "D:\Target" && (
rem /* Loop through all directories whose names begin with `Lot` + SPACE;
rem the `findstr` portion further filters the directory names so that
rem they must begin with `Lot` + SPACE + a character other than SPACE;
rem everything starting at a potential following SPACE is ignored: */
for /F "tokens=1-2" %%C in ('
2^> nul dir /B /A:D "Lot *" ^| findstr /I "^Lot [^ ]"
') do (
rem /* Loop through all `*.pdf` files in the currently iterated directory;
rem the `findstr` portion further filters the file names so that they must
rem not equal `L` + the second token from the outer loop + something containing
rem a `_` + `.pdf`, because such files are considered as already renamed: */
for /F "delims=" %%F in ('
2^> nul dir /B /A:-D "%%~C %%~D\*.pdf" ^| findstr /I /V "^L%%~D_.*\.pdf$"
') do (
rem // Check whether target file name already exists:
if exist "%%~C %%~D\L%%~D_%%F" (
rem // Collision, hence skip file and return error message:
>&2 echo Collision: cannot rename "%%~C %%~D\%%F" to "L%%~D_%%F"!
) else (
rem // No collision, so actually rename the currently iterated file:
ECHO ren "%%~C %%~D\%%F" "L%%~D_%%F"
)
)
)
rem // Return to original working directory:
popd
)
After having tested for the correct output, remove the upper-case ECHO from the ren command!
How do you all delete the newest file in a folder using batch script?
All results I have found ONLY show how to delete the oldest files or delete them after N days.
Links are : Batch file to delete files older than N days and Batch Script to delete oldest folder in a given folder
Thank you
for /F %%a in ('dir /B /O-D /A-D %the_directory%') do echo("%the_directory%\%%a"&goto deldone
:deldone
would be my approach. It rudely escapes from the for loop having deleted the first filename encountered in a sorted-in-reverse-date-order (/o-d) list.
This saves having to read the entire list. Not such a problem with a few files, but can be a pain with thousands.
The required DEL command is merely ECHOed for testing purposes. After you've verified that the command is correct, change ECHO(DEL to DEL to actually delete the files.
I would do this:
#echo off
set latest=
set the_directory=your_directory
for /F %%a in ('dir /B /OD /A-D %the_directory%') do set latest=%%a
del %the_directory%\%latest%
run dir on files only, with sorting on modification date. Then loop and keep last echoed file. Delete it (replace by echo to test!)
The following code snippet does what you want:
set "FILE="
pushd "\path\to\folder" || exit /B 1
for /F "eol=| delims=" %%F in ('
dir /B /A:-D /O:D /T:C "*.*"
') do (
set "FILE=%%F"
)
if defined FILE del "%FILE%"
popd
The dir command returns files only (/A:-D) sorted by date in ascending order (/O:D) using the creation date (/T:C), which are located in \path\to\folder and match the pattern *.*.
The for /F loop walks through all the files returned by dir and assigns its name to variable FILE, overwriting it in each iteration, hence the final value is the name of the newest file.
The del command finally deletes the found file. The if query covers the case when no files are found in the given location.
Here is a slightly modified variant as recommended by Magoo's comment, which might be a bit more performant than the aforementioned one:
set "FILE="
pushd "\path\to\folder" || exit /B 1
for /F "eol=| delims=" %%F in ('
dir /B /A:-D /O:-D /T:C "*.*"
') do (
if not defined FILE set "FILE=%%F"
)
if defined FILE del "%FILE%"
popd
This avoids multiplicately overwriting of variable FILE by querying whether it has already been defined. Note the reversed sort order of dir here.
However, the approach shown in Magoo's answer is still better in performance.
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.
Windows, Command Prompt, need to generate a .txt file output containing of all files from a big and complex dir tree with one (1) line for each files as:
CreationDateYYYYMMDD-HHMMSS, LastModifiedYYYYMMDD-HHMMSS, filesize[no K commas], filename.ext
for example:
20100101-174503, 20120202-191536, 1589567, myfile.ext
The list should not contain lines of dir name entries, etc., only filenames, even if the same file is present in more than once. Time in 24 hours format.
dir /s/t:c/t:w/-c > filelist.txt
command does not exactly works this way.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "sourcedir=c:\program files"
FOR /f "delims=" %%a IN (
'dir /s /b /a-d "%sourcedir%\*" '
) DO (
FOR %%d IN (timewritten timecreated) DO SET "%%d="
FOR %%k IN (-d s h) DO (
IF NOT DEFINED timewritten FOR /f "tokens=1,2 delims= " %%d IN ('dir /tw %%~k "%%a" 2^>nul ^|find "%%~nxa"') DO SET "timewritten=%%d %%e"
IF NOT DEFINED timecreated FOR /f "tokens=1,2 delims= " %%d IN ('dir /tc %%~k "%%a" 2^>nul ^|find "%%~nxa"') DO SET "timecreated=%%d %%e"
)
ECHO !timecreated! !timewritten! %%~za %%~nxa
)
)
GOTO :EOF
You would need to change the setting of sourcedir to suit your circumstances.
Interesting problem. This code processes it by
First, applying the standard directory-list for filenames on the tree from the relative root (%sourcedir%) to %%a
Using the full filename in %%a, set timewritten and timecreated from an ordinary dir list targeting the file in question.
It appeared that %%~ta didn't play nicely to extract the timestamp for hidden and system files, so I decided to build them from the ordinary dir listing with the appropriate t setting, specifically listing with /a-d, /as and /ah and filtering for the line which matched the filename, which seemed to extract the data appropriately.
I left the date/time in raw format. It should be an easy task to extract the various elements and construct the report in the format you want.
This question is a dupe of the SO post cmd dir /b/s plus date, but posting what worked for me:
#echo off
REM list files with timestamp
REM Filename first then timestamp
for /R %I in (*.*) do #echo %~dpnxI %~tI
#echo off
REM list files with timestamp
REM Timestamp first then name
for /R %I in (*.*) do #echo %~tI %~dpnxI
The above are the versions that you would directly paste into a command prompt.
If you want to use these in a batch file and log the output, you could do something like:
rem: Place the following in a batch file such as DirectoriesBareWithTS.cmd.
rem: As the first step in the batch file, net use to the directory or share you want the listing of
rem: Change to your target directory
Y:
for /R %%I in (*.mp4) do #echo %%~tI %%~dpnxI
Then you can pipe the output to a log file when you execute:
DirectoriesBareWithTS.cmd > C:\temp\GiantLongDirListing.log
You could then import that log into Excel.
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" )