Search code examples
windowsbatch-filecmdrename

Renaming the last created file with CMD / batch file (append suffix to original file name)


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?


Solution

  • 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

    • just files because of option /A-D (attribute not directory)
    • matching the wildcard pattern ????-??-?? ??-??-??.mp4 and
    • outputs to STDOUT in bare format because of option /B just the file names without path
    • ordered reverse by name because of option /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 /?