Reputation: 158
I'm trying to rename the last created file (only that file) in a directory full of files using a batch file.
The directory has files like this:
2020-06-21 23-56-26.mp4
2020-06-21 23-54-30.mp4
2020-06-21 23-48-40.mp4
2020-06-21 23-34-06.mp4
I want to take the last created file and append a suffix to the existing filename.
So for example 2020-06-21 23-56-26.mp4
becomes 2020-06-21 23-56-26_test.mp4
I've found a lot of examples online, however I'm having some problems.
Test 1:
for /f "delims=" %%i in ('dir /b /a-d /od /t:c "C:\vids\*.mp4"') do set LAST=%%i
echo ren "C:\vids\%LAST%" "%%~nLAST_test%%~xLAST"
This almost does what I want, but the renaming section "%%~nLAST_test%%~xLAST"
doesn't work. It seems like the variable substitutions are being ignored.
I get the output: ren "C:\vids\2020-06-21 23-57.mp4" "%~NLAST_test%~XLAST"
which means the file gets literally renamed %~nLAST_test%~xLAST
Test 2:
for /f "delims=" %%a in ('dir /b /a-d /od /t:c "C:\vids\*.mp4"') do echo ren "%%~a" "%%~Na_test%%~Xa"
The variable substitutions used in this renaming command works, however it renames every file in the folder, as opposed to only the most recently created one.
Am I missing some brackets or other syntax?
Upvotes: 0
Views: 1115
Reputation: 49096
The simple solution is:
@for /F "eol=| delims=" %%I in ('dir "C:\vids\????-??-?? ??-??-??.mp4" /A-D /B /O-N 2^>nul') do @ren "C:\vids\%%I" "%%~nI_test.%%~xI" & goto :EOF
The file names with date/time in file name in international date format makes it possible to let DIR output the file names matching the wildcard pattern ordered reverse by name which results in getting output first 2020-06-21 23-56-26.mp4
.
FOR runs in background one more command process with %ComSpec% /c
and the command line between '
appended as additional arguments. So executed is with Windows installed to C:\Windows
:
C:\Windows\System32\cmd.exe /c dir "C:\vids\????-??-?? ??-??-??.mp4" /A-D /B /O-N 2>nul
DIR searches in specified directory C:\vids
for
/A-D
(attribute not directory)????-??-?? ??-??-??.mp4
and/B
just the file names without path/O-N
which means in this case the MP4 file with newest date/time in file name first.It could be that DIR does not find any file matching these criteria in which case DIR would output an error message to STDERR which is suppressed by redirecting it to device NUL.
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 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.
FOR captures everything written to handle STDOUT of background command process and processes this output line by line after started cmd.exe
terminated itself after finishing the execution of DIR.
FOR with option /F
ignores empty lines which do not occur here. All other lines would be split up by default into substrings using normal space and horizontal tab as string delimiters. This split behavior is not wanted here as the file names definitely contain a space character. For that reason the option delims=
is used to define an empty list of string delimiters which disables line splitting behavior completely and so the entire file name is assigned to specified loop variable I
.
FOR with option /F
would ignore also lines on which first substring after splitting the line up starts with a semicolon which is the default end of line character. The option eol=|
redefines the end of line character to a vertical bar which no file name can contain ever. eol=|
is not really needed here as no file name starts with a semicolon.
The first file name output by DIR is assigned completely to loop variable I
and FOR runs the command REN to rename the file with appending _test
left to the file extension.
FOR would process next the next file name which is not wanted in this case. For that reason goto :EOF
is added as second command to execute unconditionally after command ren
to exit batch file processing.
It would be also possible to use something like goto FileRenamed
and have as one of the next lines a line :FileRename
to just exit from the loop and continue processing the batch file with the line below the line with :FileRename
, for example:
@echo off
for /F "eol=| delims=" %%I in ('dir "C:\vids\????-??-?? ??-??-??.mp4" /A-D /B /O-N 2^>nul') do ren "C:\vids\%%I" "%%~nI_test.%%~xI" & goto FileRenamed
echo ERROR: Found no MP4 file in folder C:\vids to rename!
echo(
pause
exit /B
:FileRenamed
echo Newest file renamed, continue batch file processing ...
To understand the commands used and how they work, open a command prompt window, execute there the following commands, and read the displayed help pages for each command, entirely and carefully.
dir /?
echo /?
for /?
goto /?
pause /?
ren /?
Upvotes: 2
Reputation: 17638
for /f "delims=" %%a in ('dir /b /a-d /od /t:c "C:\vids\*.mp4"') do echo ren "%%~a" "%%~Na_test%%~Xa"
The variable substitutions used in this renaming command works, however it renames every file in the folder, as opposed to only the most recently created one.
Assuming the above works as described (which is not obvious since there seems to be more context missing), try the following to reverse the dir
order and ren
the first item, only.
set "DONE="
for /f "delims=" %%a in ('dir /b /a-d /o-d /t:c "C:\vids\*.mp4"') do if not defined DONE set "DONE=1" & echo ren "%%~a" "%%~Na_test%%~Xa"
[ EDIT ] As pointed out in a comment, OP's code quoted above only worked if the current directory was C:\vids
at the time the for
loop was executed, otherwise ren
would be looking for the %%~a
file in the wrong directory.
That unnecessary assumption can be removed, either by replacing "%%~a"
with "C:\vids\%%~a"
on the ren
line, or by temporarily making C:\vids
the current directory as follows.
pushd "C:\vids"
set "DONE="
for /f "delims=" %%a in ('dir /b /a-d /o-d /t:c "*.mp4"') do if not defined DONE set "DONE=1" & echo ren "%%~a" "%%~Na_test%%~Xa"
popd
Upvotes: 1