I'm trying to write a command script (.cmd file) that will find the newest file and rename its extension.
So if there is:
file1.txt
file2.txt
file3.txt
And file3.txt is the newest, the script should change the extension to .xml, so the end result will be file3.xml.
If I do the following it will rename the file's extension:
move file3.txt file3.xml
But I don't know how to find the newest file, and then change its extension.
You could use following batch code:
#echo off
for /F "eol=| delims=" %%F in ('dir /B /O-D /TW "C:\Temp\Test\*.txt" 2^>nul') do (
ren "C:\Temp\Test\%%F" "%%~nF.xml"
goto :EOF
)
The command DIR returns a list of file names matching pattern *.txt without path and without any other data because of /B (bare format) sorted reverse according to last modification date (newest first) because of /O-D /TW.
This list is processed line by line by command FOR which executes for first file name the rename command to change the file extension for newest *.txt file in the specified directory. The loop and the batch file processing is exited after renaming first file because of goto :EOF. EOF is a predefined label which means End Of File.
If the current directory on running the batch file is always the directory with the text files, the batch file could be coded also as:
#echo off
for /F "eol=| delims=" %%F in ('dir /B /O-D /TW *.txt 2^>nul') do (
ren "%%F" "%%~nF.xml"
goto :EOF
)
delims= turns off splitting the file name returned by command DIR into tokes by spaces in case of the newest file contains 1 or more spaces in file name.
2^>nul redirects any error message because of no *.txt file in current respectively specified directory to device nul to suppress this error message whereby the redirection operator > is escaped here with ^ because of using it within command FOR.
%%~nF means file name only without file extension and dot separating the file extension from file name.
For understanding the used commands even better and how they work here, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
dir /?
echo /?
for /?
goto /?
ren /?
Related
I try to merge *.mp3 files in a folder together into a single MP3 file by using command COPY and merge the files using option /b.
I have this command so far, but I am struggling to understand how to make it loop for each file in the folder.
for /f "tokens=*" %a in ('"dir /b *.mp3"') do echo copy /b %a+%a final.mp3
Mn my folder are:
D:\data\mp3_files\song one.mp3
D:\data\mp3_files\song two.mp3
I used to be able to do this before on multiple files compressing each file as you go along, but I don't know how to merge files using copy /b because the amount of files is unknown. So I don't know how many +%a I would use.
The syntax is: copy /b file1.mp3 + file2.mp3 targetfile.mp3
My issue is I don't know how to write file1.mp3 + file2.mp3 as variables.
I have this: copy /b %a+%a final.mp3
I don't know how many times to put the %a as I would not know how many files there are in the directory.
I also don't know why I would write the same variable twice.
Not sure how to code this properly.
That file merging task can be done with a batch file using following code:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "eol=| delims=" %%I in ('dir *.mp3 /A-D /B /ON 2^>nul') do copy /B "%%I" "TempFile.tmp" >nul & goto MergeFiles
:MergeFiles
for /F "skip=1 eol=| delims=" %%I in ('dir *.mp3 /A-D /B /ON 2^>nul') do copy /B "TempFile.tmp"+"%%I" "TempFile.tmp" >nul
if exist "TempFile.tmp" ren "TempFile.tmp" "final.mp3"
if exist "TempFile.tmp" del "TempFile.tmp"
endlocal
There is first just copied the first MP3 file in the current directory by command DIR ordered by file name to TempFile.tmp. It is important that the file extension of the temporary file is not .mp3 as otherwise the temporary file would be also in the list of MP3 files to process by the next FOR loop.
The command GOTO results in exiting the first loop after making the copy of the first MP3 file.
The second FOR loop runs like the first FOR loop in the background one more command process to execute DIR to get a list of file names with file extension .mp3 ordered by name which is captured by the command process processing the batch file and processed next line by line with ignoring empty lines not existing in output of DIR.
For each file name the command COPY is executed to merge together the current temporary file with the current MP3 file from the list to create a new temporary file on which the current MP3 file is appended.
Finally after appending one MP3 file after the other to the temporary file, the temporary file is renamed to the wanted name for the finally produced MP3 file or in an error case like final.mp3 is already existing in deletion of the temporary file.
There could be used also the following batch file if the number of MP3 files is not too large and so string assigned finally to the environment variable FileList does not become longer than 8182 characters because of the environment variable name plus equal sign plus length of string assigned to the environment variable plus string terminating null cannot be more than 8192 characters.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "FileList="
for /F "eol=| delims=" %%I in ('dir *.mp3 /A-D /B /ON 2^>nul') do call :AppendFileName "%%I"
goto MergeFiles
:AppendFileName
set FileList=%FileList%+%1
goto :EOF
:MergeFiles
if not defined FileList exit /B
copy /B %FileList:~1% "final.mp3" >nul
endlocal
That batch files concatenates the file names of all MP3 files found in the current directory enclosed in " together to a single command line with + between each file name (and also at beginning of FileList string value) and runs finally the command COPY with all the file names (without the first plus sign) to merge them all at once together to file final.mp3.
This second solution with the limitation of maximum string length is faster because of just one data copying is done on execution of the batch file.
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 /?
copy /?
del /?
dir /?
echo /?
endlocal /?
exit /?
for /?
if /?
goto /?
set /?
setlocal /?
Like the title suggests I want to batch rename files but keep the part of rar file.
Example:
File-01.part1.rar
File-01.part2.rar
Output:
Newfile__01.part1.rar
Newfile__01.part2.rar
Below is the rename part of the code.
SETLOCAL EnableDelayedExpansion
REM Set your Year, Month, Day variable values here.
REM They will be used for file renaming.
CD "D:\test\rename"
FOR /F "usebackq tokens=* delims=" %%A IN (`DIR "*.rar" /B /A:-D`) DO (
REM Extract the last 2 chars of the file name.
SET FileName=%%~nA
SET First4=!FileName:~0,5!
SET Last2=!FileName:~-2!
REM Rename the file, inserting the new data.
RENAME "%%A" "!First4!__!Last2!%%~xA"
)
ENDLOCAL
Here's an example script based on my assumption of what you wanted to do:
#Echo Off
SetLocal EnableDelayedExpansion
Set "sd=D:\test\rename"
Set "xf=.rar"
If Not Exist "%sd%\*%xf%" Exit /B
CD /D "%sd%" 2>Nul || Exit /B
Set "ds="
For /F "Tokens=1-3 Delims=/ " %%A In ('RoboCopy/NJH /L "\|" Null'
) Do If Not Defined ds Set "ds=%%A%%B%%C"
For %%A In ("*%xf%") Do (Set "fn=%%~nA"
For %%B In ("!fn!") Do (Set "fx=%%~xB"
If /I Not "!fx:.part=!"=="%%~xB" Set "fn=%%~nB")
Ren "%%A" "!fn:~,4!_%ds%_!fn:~-2!!fx!%xf%$")
Ren "*%xf%$" "*%xf%"
I have slotted the year, month, day variable, %ds% in between the two underscores, meaning:
File-01.part1.rar would be renamed to File_20180523_01.part1.rar
Testing18.part2.rar would be renamed to Test_20180523_18.part2.rar
Archive02.rar would be renamed to Arch_20180523_02.rar.
Try this batch file after modification of folder path in third line:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "Folder=D:\test\rename"
for /F "eol=| delims=" %%A in ('dir "%Folder%\File-01.part*.rar" /A-D-H /B /ON 2^>nul') do (
for /F "eol=| delims=" %%B in ("%%~nA") do ECHO ren "%Folder%\%%A" "Newfile__01%%~xB%%~xA"
)
endlocal
pause
Note: The command ECHO is used here on line 6 to just demonstrate what would be the rename command line. Run the batch file as is for verification. When everything looks okay, remove ECHO and run the batch file once again to really rename the files.
This batch file runs FOR which runs the command DIR with using a separate command process started in background with cmd.exe /C to output
just the names in bare format because of /B
of only non hidden files because of /A-D-H (attribute not directory and not hidden)
sorted by name because of /ON
matching in specified folder the wildcard pattern File-01.part*.rar.
Read also 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. 2>nul redirects the error message output on no file matching the criteria from handle STDERR to device NUL to suppress it.
FOR captures the output of started command process and processes it line by line with ignoring empty lines.
The default end of line character ; is modified with eol=| from semicolon to vertical bar. FOR ignores by default lines starting with a semicolon. A file name can start with a semicolon. But a file name can't contain a vertical bar.
FOR splits up by default a line on spaces/tabs and assigns just first part to specified loop variable A. The line splitting behavior is disabled by delims= which specifies an empty list of delimiters resulting in getting the file name with file extension but without file path as output by DIR assigned to the loop variable.
The inner FOR loop processes as string just the file name without file extension. This is the string from first character up to character before last dot, i.e. File-01.part1 and File-01.part2 and assigns this part to loop variable B. For the inner FOR the file extension is again everything after last dot which is .part*. The real file extension .rar of the file is unknown for the inner FOR loop processing just a file name string.
The command REN renames the current file referenced full path to new file name with keeping .part* referenced with %%~B from inner FOR loop and original file extension .rar from outer FOR loop.
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.
dir /?
echo /?
endlocal /?
for /?
pause /?
ren /?
setlocal /?
I have a list of IDs in a CSV file stored in a folder. Then I have files which contains these IDs. I want to move the files if it is present in the CSV file.
For example:
I have this documents in Docs folder: Jose_1234_CV.pdf, Jose_111_CV.doc, Jose_2323_CV.doc
I have IDs.csv file containing the following IDs: 1234, 111
When I run the batch job, the files with the IDs 1234 and 111 should be moved to a particular folder.
I have the below code working only if in the look up file contains the exact file name. I want it work even if it only find the ID:
#echo off
set "Source=C:\users\directory"
set "Target=C:\users\target"
set "FileList=C:\users\lookup\ID.csv"
echo/
if not exist "%Source%" echo Source folder "%Source%" not found & goto :Quit
if not exist "%FileList%" echo File list "%FileList%" not found & goto :Quit
2> nul md "%Target%"
for /F usebackq^ delims^=^ eol^= %%a in ("%FileList%") do (
for /F "delims=" %%b in ('dir /B /S /A:-D "%Source%\%%a"') do (
move "%%b" "%Target%"
)
)
:Quit
echo/
echo Press the Space bar to close this window.
pause > nul
This could be done with following batch file:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "BaseDirectory=C:\Users"
set "Source=%BaseDirectory%\directory"
set "Target=%BaseDirectory%\target"
set "FileList=%BaseDirectory%\lookup\IDs.csv"
set "TempFile=%TEMP%\%~n0.tmp"
if not exist "%Source%\" echo Source folder "%Source%" not found. & goto Quit
if not exist "%Source%\*_*_CV.*" echo Folder "%Source%" does not contain any *_*_CV.* file. & goto Quit
if not exist "%FileList%" echo File list "%FileList%" not found. & goto Quit
md "%Target%" 2>nul
if not exist "%Target%\" echo Folder "%Target%" could not be created. & goto Quit
set "FileMoved=0"
del "%TempFile%" 2>nul
rem Create a copy of list file with each identifer surrounded by underscores
rem to make sure that on an identifier like 111 just the file with _111_ in
rem name and not with _2111_ or _1114_ in name is moved to target folder.
for /F "usebackq delims=" %%I in ("%FileList%") do echo _%%~I_>>"%TempFile%"
rem Move all files containing one of the identifiers in
rem temporary file in its file name to the target folder.
for /F "eol=| delims=" %%I in ('dir "%Source%\*_*_CV.*" /A-D-H /B /S 2^>nul ^| %SystemRoot%\System32\findstr.exe /L /G:"%TempFile%" 2^>nul') do (
move /Y "%%I" "%Target%\%%~nxI" >nul
if not errorlevel 1 set /A FileMoved+=1
)
rem Delete the temporary file no longer needed.
del "%TempFile%"
rem Delete the target directory if being empty.
if %FileMoved% == 0 rd "%Target%" 2>nul
rem Inform user about number of moved files.
set "Plural_S=s"
if %FileMoved% == 1 set "Plural_S="
echo Moved %FileMoved% *.csv file%Plural_S% to "%Target%".
:Quit
endlocal
echo/
echo Press SPACE to close this window.
pause >nul
This batch code expects that the file C:\Users\lookup\IDs.csv contains the identifiers line by line like:
1234
111
The first FOR command creates a copy of IDs.csv with the lines:
_1234_
_111_
The second FOR executes in a separate command process started with cmd.exe /C in background (= not visible) the command line:
dir "C:\Users\directory\*_*_CV.*" /A-D-H /B /S 2>nul | C:\Windows\System32\findstr.exe /L /G:"C:\Users\UserName\AppData\Local\Temp\BatchFileName.tmp" 2>nul
So the command process in background with no console window is first running command DIR which outputs
all non hidden files because of /A-D-H (attribute not directory and not hidden)
matching the wildcard pattern *_*_CV.*
in bare format because of /B which means file name only
in specified directory and all its subdirectories because of /S
with full path also because of /S
to handle STDOUT.
DIR outputs an error message if it can't find any file matching the wildcard pattern. This error message written to handle STDERR is suppressed by redirecting it to device NUL with 2>nul.
The file names with full path output by DIR line by line to handle STDOUT are redirected with | to handle STDIN of next command FINDSTR.
FINDSTR searches in the list of file names for
any string listed in temporary file specified after /G:
case-sensitive because of not using /I
and literally because of using /L
and outputs the lines (= file names with full path) containing one of the strings in the temporary file.
That means no directory in path of a file should contain _ID_ or otherwise files are moved which do not contain the identifier in file name, but in its path.
It is possible that FINDSTR can't find any line matching the search criteria and therefore outputs an error message to handle STDERR which is suppressed by redirecting it with 2>nul to device NUL.
The command FOR captures the output written to handle STDOUT of the background command process which is the output of DIR filtered with FINDSTR and then processes this output line by line.
Empty lines are ignored by FOR. But that does not matter here as the list of file names each with full path does not contain empty lines.
Lines starting with a semicolon would be also ignored by FOR, but this behavior is modified with eol=| to ignore just lines starting with a vertical bar. A vertical bar is impossible here as no directory or file can contain a vertical bar in name. Well, it is also practically impossible that a file name with full path starts with a semicolon. So eol=| would not be really needed here.
FOR with parameter /F splits by default a line up into substrings using space and horizontal tab as string delimiters and assign only the first space/tab delimited string to specified loop variable I. This split behavior is not wanted here as needed in body command block of FOR is always the full qualified name of a file to move even on path or file name contains a space character. For that reason delims= is specified to define an empty list of delimiters which disables splitting up the lines into substrings.
MOVE is executed which moves the file and exits with 0 on success and with any value greater 0 on an error.
The exit code of an executed application or command is assigned by Windows command interpreter to environment variable ERRORLEVEL.
The IF condition checks if MOVE exited not with a value greater or equal 1, i.e. with 0 (or a negative value) for success. In this case file was moved successfully and the appropriate counter is increased by one.
If the source directory contains never subdirectories, it would be better to use for second FOR loop:
for /F "eol=| delims=" %%I in ('dir "%Source%\*_*_CV.*" /A-D-H /B 2^>nul ^| %SystemRoot%\System32\findstr.exe /L /G:"%TempFile%" 2^>nul') do (
move /Y "%Source%\%%I" "%Target%\%%I" >nul
if not errorlevel 1 set /A FileMoved+=1
)
DIR is here without /S and so output are the non hidden files matching the wildcard pattern without path. For that reason FINDSTR searches in file name only for _ID_. The command MOVE must contain %Source%\ as %%I is in this case just the name of a file without path.
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.
del /?
dir /?
echo /?
endlocal /?
findstr /?
for /?
goto /?
if /?
md /?
move /?
pause /?
rd /?
rem /?
set /?
setlocal /?
Read also the Microsoft article about Using Command Redirection Operators for an explanation of 2>nul and |. The redirection operators > and | 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 command line with using a separate command process started in background.
I am trying to zip only last modified file from a folder to help my workflow with bat file
but its giving an error
ERROR: No files found with the specified search criteria.
Here is my complete code
#ECHO ON
SET "SourceDir=C:\Users\user1\Documents\Work"
SET "ZipName=testing.zip"
SET "DestDir=C:\Users\user1\Documents\Work\result"
SET "now=%date:~4%"
CD /D "%DestDir%"
FORFILES /D %now% /m *.csv /c "cmd /c 7z.exe a -aoa -tzip %ZipName% %SourceDir% "
I am pretty sure there is file last modified today. I assume its didn't recognise the sourcedir? Am I missing in the quote?
I suggest not using command FORFILES, but use instead the commands FOR and DIR.
#echo off
set "SourceDir=%USERPROFILE%\Documents\Work"
set "ZipName=testing.zip"
set "DestDir=%USERPROFILE%\Documents\Work\result"
for /F "delims=" %%I in ('dir "%SourceDir%\*" /A-D /B /O-D 2^>nul') do 7z.exe a -aoa -tzip "%DestDir%\%ZipName%" "%SourceDir%\%%I" & goto Done
:Done
DIR searches in specified source directory with wildcard pattern * because of /A-D (attribute not directory) only for files and outputs them because of /B (bare format) with file name only ordered by last modification date in reverse order because of /O-D which means newest file is output first.
FOR process this output by DIR line by line. For the first line 7z.exe is called to compress the file into the ZIP archive file.
Then goto :Done is executed to exit the FOR loop as all other files found and output by DIR are of no interest.
I suggest to specify 7z.exe with full path in the batch file.
2^>nul redirects the error message output by DIR if no file is found in source directory to device NUL to suppress it. The redirection operator > must be escaped here with caret character ^ to be interpreted as literal character on Windows command interpreter parses the entire FOR command line. The escape character ^ is already removed later on execution of DIR command line in a separate command process opened by FOR in background.
Another version processing only files with archive attribute set and clear the archive attribute for each file compressed into the ZIP archive file.
#echo off
set "SourceDir=%USERPROFILE%\Documents\Work"
set "ZipName=testing.zip"
set "DestDir=%USERPROFILE%\Documents\Work\result"
for /F "delims=" %%I in ('dir "%SourceDir%\*" /AA-D /B 2^>nul') do (
7z.exe a -aoa -tzip "%DestDir%\%ZipName%" "%SourceDir%\%%I"
%SystemRoot%\System32\attrib.exe -a "%SourceDir%\%%I"
)
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.
attrib /?
dir /?
echo /?
for /?
goto /?
set /?
Read also the Microsoft article about Using Command Redirection Operators.
I am currently using the following line in my batch file to retrieve a list of pdf files in my subdirectory that contain the word "complete" in the title.
dir /b /s *COMPLETE*.PDF >Q:\"Personal Folders"\Advertising\"Data Updates"\ePrint\test.csv
Is there a way that I can change this to append the date created to the beginning of each file so that I can sort them by date in excel? Thank you.
How do I append the date created to the beginning of each file name?
Use the following batch file.
GetFileCreateDate.cmd:
#echo off
setlocal
for /f "tokens=*" %%f in ('dir /b /s "*COMPLETE*.PDF"') do (
for /f "tokens=1,2" %%g in ( 'dir "%%f" /tc ^| findstr /C: "%%~nxf"') do (
echo %%g,%%h,"%%f"
)
)>>Q:\"Personal Folders"\Advertising\"Data Updates"\ePrint\test.csv
endlocal
Notes:
Output lines will have the format:
create_date,create_time,"filename"
Where filename is the absolute name of the file
Modify echo %%g,%%h,"%%f" to suit the format you want in your csv file.
%%g is the create_date, %%h is the create_time and %%f is the absolute filename.
Example output (writing to just "test.csv"):
F:\test>dir /b /s "*COMPLETE*.PDF"
F:\test\1complete1.pdf
F:\test\2complete2.pdf
F:\test\complete1.pdf
F:\test\complete2(s).pdf
F:\test>GetFileCreateDate.cmd
F:\test>type test.csv
26/08/2016,21:28,"F:\test\1complete1.pdf"
26/08/2016,21:28,"F:\test\2complete2.pdf"
26/08/2016,21:28,"F:\test\complete1.pdf"
26/08/2016,21:28,"F:\test\complete2(s).pdf"
Further Reading
An A-Z Index of the Windows CMD command line - An excellent reference for all things Windows cmd line related.
dir - Display a list of files and subfolders.
findstr - Search for strings in files.
for /f - Loop command against the results of another command.
Next code snippet lists last written date & time and file paths:
>"Q:\Personal Folders\Advertising\Data Updates\ePrint\test.csv" (
for /F "delims=" %%G in ('dir /b /s *COMPLETE*.PDF') do echo %%~tG "%%~G"
)
Resources (required reading):
(command reference) An A-Z Index of the Windows CMD command line
(additional particularities) Windows CMD Shell Command Line Syntax
(%~tG etc. special page) Command Line arguments (Parameters)
(>, special page) Redirection