I am writing a batch script to backup files and want to include logic that deletes the oldest file in the folder if the number of backups ever exceeds a certain number set by a variable. Pretty new to batch and my current code deletes all files once it exceeds the number.
Any ideas how to do this?
SET Count=0
FOR %%A IN ("%SNAPSHOTNAME%*.*") DO SET /A Count += 1
IF %Count% gtr %NumberOfBackups% FOR %%A IN ("%SNAPSHOTNAME%_PBCS_Test_*.*") DO del "%%A"
I suggest the following single command line for this task:
for /F "skip=%NumberOfBackups% eol=| delims=" %%I in ('dir "%SNAPSHOTNAME%_PBCS_Test_*.*" /A-D-H /B /O-D 2^>nul') do del "%%I"
FOR executes in a separate command process started with cmd.exe /C in background the command line:
dir "%SNAPSHOTNAME%_PBCS_Test_*.*" /A-D-H /B /O-D 2>nul
DIR outputs to handle STDOUT line by line
just non-hidden files because of /A-D-H (not attribute directory or hidden)
in bare format because of /B which means file name only
ordered by last modification (write) time with newest file first and oldest file last.
An error message output by DIR to handle STDERR is suppressed by redirecting it to device NUL with 2>nul.
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.
FOR captures this output and processes it line by line according to the options specified in the double quoted string with ignoring empty lines which do not exist in this output of DIR.
The first %NumberOfBackups% lines are skipped by FOR which means the newest %NumberOfBackups% are always kept in current directory.
FOR by default ignores also lines starting with a semicolon because of ; is the default for end of line character. For that reason eol=| is used to change end of line character to vertical bar which is not possible in a file or folder name and so it is impossible that a file name output by DIR starts with |.
FOR by default splits a line into substrings using normal space and horizontal tab character as string delimiters and assigns just first space/tab separated string to loop variable I. This string splitting behavior can be disabled by specifying an empty list of delimiters with delims= at end of the options string to get the entire line (= file name) assigned to the loop variable I.
So DIR outputs the names all non-hidden files matching pattern "%SNAPSHOTNAME%_PBCS_Test_*.*" line by line with newest file first and oldest file last and FOR ignores the first/newest %NumberOfBackups% files and deletes all other older files.
FOR does nothing if DIR outputs less or exactly %NumberOfBackups% file names.
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 /?
for /?
Note: This is nearly the same answer as written by Squashman, but with full explanation how it works.
If you change to using a FOR /F command with the SKIP option, you can get rid of the IF comparison.
set "NumberOfBackups=6"
FOR /F "SKIP=%NumberOfBackups% DELIMS=" %%G IN ('DIR /A-D /B /O-D "%SNAPSHOTNAME%_PBCS_Test_*.*"') DO DEL "%%G"
Your second for loop has no sort and no break condition so as mentioned by you it will delete all files.
A dir command can sort the files so instead of taking the for over all files take a for over the sorted output of an dir command. Option /OD will sort for file timestamp.
To let for loop handle the output use for /f. The break condition is to only delete the first (in this case the oldest) file and than jump out the for loop.
IF %Count% gtr %NumberOfBackups% for /f "delims=" %%f in ('dir /B /OD "%SNAPSHOTNAME%_PBCS_Test_*.*"') do del "%%f" & goto :gotIt
:gotIt
Related
I am trying to convert a number of .doc files into .docx files and I found a solution:
for %F in (*.doc) do "C:\Program Files\Microsoft Office\Office12\wordconv.exe" -oice -nme "%F" "%Fx"
For the detailed info see: Automation: how to automate transforming .doc to .docx?
Now I want to use the absolute path of wordconv.exe as an input parameter.
Then my approach is like this:
The contents of doc2docx.bat:
for %F in (*.doc) do (%1 -oice -nme "%F" "%Fx")
Run doc2docx.bat in console with:
doc2docx.bat "C:\Program Files\Microsoft Office\Office12\wordconv.exe"
I got the result below:
D:\book\work\temp\5. SPEC_NEW>D:\book\doc2docx.bat "C:\Program Files (x86)\Microsoft Office\Office12\Wordconv.exe"
此时不应有 1。
D:\book\work\temp\5. SPEC_NEW>for 1 -oice -nme "Fx")
D:\book\work\temp\5. SPEC_NEW>
The message 此时不应有 1。 means '1' was unexpected at this time.
How could I solve it?
I know little about batch script coding.
I recommend to open a command prompt, run for /? and read the output help from top of first to bottom of last page. There is already written in fourth paragraph that in a batch file the loop variable must be referenced with doubling the percent sign in comparison to usage of command FOR directly on Windows command prompt.
So the solution could be:
for %%F in (*.doc) do %1 -oice -nme "%%F" "%%~nF.docx"
But I can't recommend to use this command line in the batch file because of following reasons.
Reason 1 is explained in detail by this answer by the chapter Issue 7: Usage of letters ADFNPSTXZadfnpstxz as loop variable. It is possible to use these letters for a loop variable, but it is advisable not doing that. There are lots of other ASCII characters with no special meaning which are always safe to use as loop variable.
Reason 2 is that command FOR searches with *.doc in current directory for files with .doc in long or in short file name. So if the directory contains Test1.doc and Test2.docx, FOR runs the converter executable with both file names as it can be seen on running in the command prompt window the command line:
for %I in (*.doc) do #echo Long name: %I - short name: %~snxI
The output for a directory containing Test1.doc and Test2.docx is:
Long name: Test1.doc - short name: TEST1.DOC
Long name: Test2.docx - short name: TEST2~1.DOC
Reason 3 is often problematic on FAT32 and exFAT drives, but is sometimes even a problem on NTFS drives. FOR accesses the file system on processing the files matched by the wildcard pattern after each iteration. There is executed in background _findfirst, _findnext, _findnext, ..., _findclose. The problem is that the directory entries change because of the conversions of the Microsoft Word files as the *.docx files are created in same directory as the processed *.doc files. All file systems return the file names as stored in their table. The difference is that the NTFS master file table is locale specific sorted by name while the table of FAT32 and exFAT is not sorted at all and so changes dramatically with each creation or deletion of a file or folder in a directory. For that reason it could happen that some .doc files are processed more than once and others are skipped and even an endless running loop could be the result. In other words the FOR loop behavior is undefined in this case and so the loop could work by chance, but could also fail.
The solution is using the command line:
for /F "delims=" %%I in ('%SystemRoot%\System32\where.exe *.doc 2^>nul') do %1 -oice -nme "%%I" "%%~dpnI.docx"
Problem 1 is avoided by using I as loop variable. It would be also possible to use # or B or J and lots of other ASCII characters.
FOR with option /F and a set enclosed in ' results in starting in background one more command process with %ComSpec% /c and the command line within ' appended as additional arguments. Therefore it is executed in background with Windows installed into C:\Windows:
C:\Windows\System32\cmd.exe /c C:\Windows\System32\where.exe *.doc 2>nul
WHERE is different to FOR or DIR. It searches only in long file name for files with extension .doc. So problem 2 with matching also files with file extension .docx is avoided by using command WHERE which outputs the found files matching the wildcard pattern with full qualified file name (drive + path + name + extension).
Read the Microsoft documentation 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 where command line with using a separate command process started in background.
Everything written by where to handle STDOUT (standard output) of started background command process is captured by cmd.exe processing the batch file. The captured lines are processed after started cmd.exe terminated itself after where.exe finished. For that reason the problem 3 is avoided as the list of file names with file extension .doc does not change anymore on running the conversion. The file names list is already completely loaded into memory of cmd.exe before starting processing them.
FOR with option /F results by default in ignoring empty lines, splitting up each line into substrings using normal space and horizontal tab as string delimiters, ignoring the line if the first space/tab delimited string starts with a semicolon, and otherwise assigning just first space/tab delimited string to the specified loop variable. This default line processing behavior is not wanted here because of the full qualified file names can contain one or more spaces. The option string "delims=" defines an empty list of delimiters which results in disabling the line splitting behavior completely. where outputs the file names with full path and so no captured line can have a ; at beginning and for that reason the implicit default eol=; can be kept in this case. Otherwise on using a different command line resulting in captured lines being just the names of the files matching a wildcard pattern eol=| or eol=? could be used as neither | nor ? can be used in a file name to avoid that files of which name starts unusually with ; are ignored by FOR.
I suggest to use the following batch file which searches itself for wordconv.exe by using the path stored in Windows registry for winword.exe or excel.exe or powerpnt.exe added by the installer of Office for Application Registration on being started with no file name of an executable.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
goto Main
:GetConvertToolName
for %%# in (winword excel powerpnt) do (
for /F "skip=2 tokens=1,2*" %%I in ('%SystemRoot%\System32\reg.exe query "%~1\%%#.exe" /v Path') do (
if /I "%%I" == "Path" if exist "%%~K\wordconv.exe" for %%L in ("%%~K\wordconv.exe") do set "ConvertTool=%%~fL" & goto :EOF
)
)
goto :EOF
:Main
set "ConvertTool="
if not "%~1" == "" if exist "%~1" if /I "%~x1" == ".exe" set "ConvertTool=%~1"
if not defined ConvertTool call :GetConvertToolName "HKLM\Software\Microsoft\Windows\CurrentVersion\App Paths"
if not defined ConvertTool call :GetConvertToolName "HKCU\Software\Microsoft\Windows\CurrentVersion\App Paths"
if not defined ConvertTool (
echo ERROR: Failed to find the program wordconv.exe.
echo/
echo Please run %~nx0 with full name of wordconv.exe as argument.
echo/
pause
) else for /F "delims=" %%I in ('%SystemRoot%\System32\where.exe *.doc 2^>nul') do "%ConvertTool%" -oice -nme "%%I" "%%~dpnI.docx"
endlocal
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 /?
echo /?
endlocal /?
for /?
goto /?
if /?
pause /?
reg /?
reg query /?
set /?
setlocal /?
where /?
The command line:
for %F in (*.doc) do (%1 -oice -nme "%F" "%Fx")
should read:
for %%F in (*.doc) do ("%~1" -oice -nme "%%F" "%%Fx")
to fixe syntax errors (doubled %-symbols in a batch file as stated in the help of for /?) and to properly handle quotation.
But there is still room for improvement:
The pattern *.doc may even match *.docx files when you have short 8.3 file names enabled on your system (because a file called some long name.docx has got a short name like SOMELO~1.DOC, which dir regards too).
Files may already have been converted, hence a check if there already exists a respective *.docx file might be helpful.
There might no argument be provided.
The following code regards these issues:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Check whether first argument points to an existing file:
if exist "%~1" (
rem // Change into target directory:
pushd "D:\path\to\root\directory" && (
rem /* Instead of a standard `for` loop, use `for /F` over `dir /B` to gain the possibility
rem to apply an additional filter by `findstr` to avoid `*.docx` to match: */
for /F "delims= eol=|" %%F in ('dir /B /A:-D-H-S "*.doc" ^| findstr /I "\.doc$"') do (
rem // Check whether there is already a respective `*.docx` file:
if not exist "%%~nF.docx" (
rem // Attempt to convert the current `*.doc` file to `*.docx`:
"%~1" -oice -nme "%%F" "%%Fx"
)
)
rem // Return from target directory:
popd
)
) else (
rem // Raise an error in case the first argument does not point to an existing file:
>&2 echo "%~1" not found!
exit /B 1
)
endlocal
exit /B
for %%F in (*.doc) do (%1 -oice -nme "%F" "%Fx")
Batch is interpreting %F in (*.doc) do (% as a variable which, unsurprisingly, has no value hence it executes
for 1 -oice -nme "%F" "%Fx")
Which explains your error message as 1 is not expected after for.
The metavariable (F in this case) within a batch must be %%F. Only if run directly from the prompt, is it %F.
I have the batch file below:
FOR /F "delims=|" %%I IN ('DIR "%C:\TeamCity\buildAgent\work\53bba593f5d69be\public\uploads\*.xlsx" /B /O:D') DO SET NewestFile=%%I
FOR /F "delims=" %%a IN ('wmic OS Get localdatetime ^| find "."') DO SET DateTime=%%a
set Yr=%DateTime:~0,4%
set Mon=%DateTime:~4,2%
set Day=%DateTime:~6,2%
setlocal enableDelayedExpansion
set "baseName=InventoryReport%Yr%-%Mon%-%Day% V1.%n%"
set "n=0"
FOR /f "delims=" %%F in (
'DIR /b /ad "%baseName%*"^|findstr /xri "\\192.168.0.141\Medisun\28 - Business Development\30 - Product Inventory\InventoryReport\"%baseName%[0-9]*""'
) do (
set "name=%%F"
set "name=!name:*%baseName%=!"
if !name! gtr !n! set "n=!name!"
)
set /a n+=1
md "%baseName%%n%"
copy "%C:\TeamCity\buildAgent\work\53bba593f5d69be\public\uploads\%NewestFile%" "\\192.168.0.141\Medisun\28 - Business Development\30 - Product Inventory\InventoryReport\%baseName%%n%.xlsx"
cmd /k
I cannot get it to find the greatest version number of previously copied file between V1. and file extension .xlsx in file name and increment it but one. The batch file finds the file V1.1, but overwrites it instead of copying newest file with V1.2 in target file name.
How can I get the previous file version first and increment that number?
The file copying task can be done with following batch file:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "SourceFolder=C:\TeamCity\buildAgent\work\53bba593f5d69be\public\uploads"
set "TargetFolder=\\192.168.0.141\Medisun\28 - Business Development\30 - Product Inventory\InventoryReport"
for /F "eol=| delims=" %%I in ('dir "%SourceFolder%\*.xlsx" /A-D /B /O-D 2^>nul') do set "NewestFile=%%I" & goto CheckTarget
echo ERROR: Found no *.xlsx file in the folder:
echo "%SourceFolder%"
exit /B 1
:CheckTarget
if not exist "%TargetFolder%\" md "%TargetFolder%\" 2>nul
if exist "%TargetFolder%\" goto GetDateTime
echo ERROR: Failed to access or create the folder:
echo "%TargetFolder%"
exit /B 2
:GetDateTime
for /F "tokens=2 delims==." %%I in ('%SystemRoot%\System32\wbem\wmic.exe OS GET LocalDateTime /VALUE') do set "DateTime=%%I"
set "BaseName=InventoryReport%DateTime:~0,4%-%DateTime:~4,2%-%DateTime:~6,2% V1"
set "FileNumber=-1"
setlocal EnableDelayedExpansion
for /F "tokens=2 delims=." %%I in ('dir "!TargetFolder!\!BaseName!.*.xlsx" /A-D /B 2^>nul ^| %SystemRoot%\System32\findstr.exe /I /R /X /C:"!BaseName!\.[0123456789][0123456789]*\.xlsx"') do if %%I GTR !FileNumber! set "FileNumber=%%I"
endlocal & set "FileNumber=%FileNumber%"
set /A FileNumber+=1
copy /B /V "%SourceFolder%\%NewestFile%" "%TargetFolder%\%BaseName%.%FileNumber%.xlsx" >nul || exit /B 3
endlocal
The first FOR loop runs in background one more command process with %ComSpec% /c and the command line between the round brackets appended as additional arguments. So executed is with Windows installed to C:\Windows in background:
C:\Windows\System32\cmd.exe /c dir "C:\TeamCity\buildAgent\work\53bba593f5d69be\public\uploads\*.xlsx" /A-D /B /O-D 2>nul
The background command process executes internal command DIR which
searches in the specified directory
just for file names because of option /A-D (attribute not directory)
matching the wildcard pattern *.xlsx and
outputs them in bare format with just file name + extension because of option /B
ordered reverse by last modification date because of option /O-D which means the file name of newest file is output first and the file name of the oldest file is output last.
It is possible that either the source directory does not exist at all or the source directory does not contain any file matching these criteria. DIR would output in this case an error message to handle STDERR of background command process which would be redirected by the command process processing the batch file to own handle STDERR and so displayed most likely in console window. This error message is not wanted as there is a better one output below the FOR loop if there is not found any file for copying. For that reason the error message is redirected already by background command process to device NUL to suppress it.
Read the Microsoft documentation 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 captured output line by line after the executed background cmd.exe terminated itself.
FOR with option /F ignores always empty lines which do not occur in this case. Every other line would be first split up into substrings using normal space and horizontal tab character as delimiters. The line would be ignored if the first space/tab delimited string starts with default end of line character ; (semicolon). Otherwise just the first space/tab delimited string would be assigned to loop variable I and the command respectively command block would be executed next.
A *.xlsx file name can contain one or more spaces. For that reason the FOR option delims= is used to define an empty list of string delimiters to disable line splitting completely. It is unusual, but nevertheless possible, that a file name starts with a semicolon. Therefore FOR option eol=| is also used to define the vertical bar as end of line character which no file name can contain as described by Microsoft in the documentation about Naming Files, Paths, and Namespaces. So the result is that every file name output by DIR in background command process is assigned one after the other completely to the loop variable I.
The file name of the newest file is output first and so its name is assigned to environment variable NewestFile. Then the first FOR loop is exited with using command GOTO to jump to the first line below label CheckTarget as processing the other file names would be a waste of time and CPU power.
There is a meaningful error message output on no *.xlsx file found to copy and batch file processing is exited with exit code 1 to indicate an error condition to parent process starting this batch file.
Next, with having file name of newest file in source folder, an existence check of target folder is done with creating the target folder if not already existing. A meaningful error message is output if the target folder is still not existing because of other computer or storage device is not running or is not reachable at all or the creation of the target folder failed for whatever reason.
The next two command lines get the current date/time in a region independent format and define the base file name for target file using the current date. For a full description of these two lines see my answer on Time is set incorrectly after midnight.
Then the file number is defined with value -1 and delayed expansion is enabled as required for the number comparison done by the next FOR loop.
The third FOR loop is similar to first FOR loop. There is additionally the output of command DIR redirected to handle STDIN of FINDSTR to be filtered for verification if the file name of found file contains really just one or more digits between the dot after V1 and the dot of the file extension, i.e. this part of the file name is a valid number. It can be assumed that FINDSTR outputs the same lines as output by DIR on target folder not used for something different than the Excel files with the defined pattern for the file name. The two dots in name of each file must be escaped with a backslash in case-insensitive interpreted regular expression search string on which the space character is interpreted as literal character because of using /C: and /R and not as OR expression as on omitting /C:. For 100% safety on processing later only correct file names /X is additionally used to output only file names on which entire file name is matched by the search expression.
This time the FOR loop should not assign the entire file name to loop variable I. There is of interest only the string between the first dot after V1 and the file extension .xlsx. For that reason the FOR option delims=. is used to split the file names on dots and option tokens=2 is used to instruct command FOR to assign the second dot delimited string to loop variable I which is the incremented file number.
A simple integer comparison is done to determine if the file number of current file name is greater than file number assigned currently to environment variable FileNumber in which case this greater file number is assigned to the environment variable FileNumber.
The local environment with enabled delayed expansion is no longer needed after knowing the greatest file number of the existing files if there is one at all. So this environment is destroyed which would mean the environment variable FileNumber would have again the number -1 as assigned to the environment variable in initial environment. Please read this answer for details about the commands SETLOCAL and ENDLOCAL. So to pass the current value of FileNumber in current environment to FileNumber in previous environment the command line with endlocal contains additionally the command set "FileNumber=%FileNumber%" which is processed by cmd.exe, for example, to set "FileNumber=12" before executing the command ENDLOCAL. That simple trick is used to pass the greatest file number value to FileNumber in previous environment.
See also:
How does the Windows Command Interpreter (CMD.EXE) parse scripts?
Single line with multiple commands using Windows batch file
The greatest file number of an existing file or -1 is incremented by one before copying the newest file in source folder with this number and current date in file name to the target folder with verification that the file data were really correct written on target storage media.
The batch file is exited with exit code 3 in case of file copying failed for whatever reason.
Finally the batch file processing ends with explicitly restoring initial execution environment. The last command ENDLOCAL would be not really necessary because of Windows command processor runs it implicit on exiting processing of this batch file as done for example on execution of one of the three commands exit /B.
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.
copy /?
dir /?
echo /?
endlocal /?
exit /?
findstr /?
for /?
goto /?
set /?
setlocal /?
wmic /?
wmic os /?
wmic os get /?
wmic os get localdatetime /?
PS: The greatest possible file number is 2147483647. But a day has only 86400 seconds and more than 65535 files in one directory would be a real problem, too. So the maximum file number 2147483647 should be never reached if no user renames a file in target folder to exceed that maximum number.
I need to rename a filename like this 7612372 filename 50x50.jpg into this filename 50x50.jpg, removing all digits at the beginning of the filename.
The number of digit can be variable.
I need to integrate this into an existing batch file run from the Windows command prompt.
If the format of the filename would be the same for all the files in the folder, then you can try:
#echo off
for /F "delims=" %%A IN ('dir /b /A-D') do (
for /F "tokens=2-3" %%B IN ("%%A") do (
ren "%%~fA" "%%B %%C"
)
)
This is the shortest way, but not the most accurate one. It is unsecure, because if the filename contains spaces, the file will be rename incorrectly. I suggest the following code for the task:
#echo off
setlocal EnableDelayedExpansion
for /F "delims=" %%A IN ('dir /b /A-D') do (
set filename=%%A
for /F "tokens=1" %%B IN ("%%A") do (
ren "%%~fA" "!filename:%%B =!"
)
)
which is more accurate and renames all files correctly only if they have the format mentioned in the beginning.
#echo off turns command-echoing off.
setlocal EnableDelayedExpansion enables delayed expansion. We use it only here, as we have to access variables inside a for loop which is a code block. You must use delayed expansion always inside these code blocks.
Now we make a for loop to parse the output (/F) of the dir /b /A-D command which lists all items in current working directory (%cd%), excluding directories (/A-D).
We need to set a variable here with the filename. We could use the variable name of the loop (%%A), but variables have an advantage: %var:search=replace%, or even !var:search=replace! which we need here.
Now we make another for loop to parse a string (/F): the filename (%%A). We need to access the first token to substract it later. We don't really need to specify it here, but it is good to make it clearer.
We rename files now: %%~fA is the full path where filename currently processed is and !filename:%%B =! means to take filename environment variable, search for string "%%B " (first part of filename [digits] and a space) and replace it with an empty string; actually nothing!
An easier solution is to use
all digits and space as delims and
tokens=*
:: Q:\Test\2019\01\06\SO_54054587.cmd
for /F "delims=" %%A in (
'dir "* *" /A-D-H /B 2^>nul'
) do for /F "tokens=* delims=0123456789 " %%B in (
"%%A"
) do ren "%%A" "%%B"
this will remove all leading delimiters while not splitting the remainder of the file name.
Like the other answers this will not account for the shorted file name already being present.
Your question is not specific enough for us to provide a solution, you really need to provide the section of code into which you wish this to be integrated.
This one expects only one file, as in your question, and that file must be named in the format you've indicated, i.e. the required part is separated from the non-required part by a space:
#Set "name=7612372 filename 50x50.jpg"
#Ren "%name%" "%name:* =%"
[Edit /]
I have noted from your comments that you were indeed looking to parse several files and those files did not match the naming scheme you provided in your question.
Here therefore is an updated potential solution based on those changed parameters.
#For %%A In (*.*) Do #For /F "Tokens=* Delims=0123456789 " %%B In ("%%A") Do #Ren "%%~A" "%%B"
Apologies to LotPings, who I've noticed has posted a very similar method/solution
It's very simple with the basic DOS command rename.
7612372 filename 50x50.jpg
If this is your sample file in the folder, it contains 7 digits and 1 blank space. Totally 8 characters.
We can do this by simply running this command on the particular folder
rename "*.mp3" "////////*.mp3"
each / represents a character you want to remove. That's it.
I suggest following batch code for this task:
#echo off
for /F "delims=" %%A in ('dir "* *" /A-D-H /B 2^>nul') do for /F "tokens=1*" %%B in ("%%A") do ren "%%A" "%%C"
pause
The command FOR runs with cmd.exe /C (more precise %ComSpec% /C) in a separate command process in background the command line:
dir "* *" /A-D-H /B 2>nul
DIR outputs to handle STDOUT of this background command process
just the names of all non-hidden files because of option /A-D-H (attribute not directory and not hidden)
in bare format because of option /B without file path
matching the wildcard pattern * * which matches any file name with at least one space inside
in current directory which can but must not be the directory of the batch file.
DIR would output an error message to handle STDERR if it can't find any directory entry matching these criteria. This error message is redirected to device NUL to suppress it.
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 all lines output to handle STDOUT of started command process and processes those lines after started cmd.exe terminated itself. It is very important for this file renaming task that FOR runs on a list of file names captured before doing the file renames as otherwise the directory entries would change while FOR is accessing them. For that reason for can't be used directly in this case because of for would process the list of * * directory entries while this list changes on each successful file rename. The result would be files not renamed or renamed multiple times or even an endless running loop depending on file system (NTFS or a FAT file system like FAT32 or ExFAT).
FOR with option /F ignores empty lines which do not occur here. FOR ignores also lines starting with a semicolon because of end of line option eol=; is the default. But all lines output by DIR should start with a number and for that reason the default end of line definition can be kept for this task.
FOR with option /F splits up a line by default to substrings using normal space and horizontal tab as delimiters and assigns just first space/tab separated string to specified loop variable. This line splitting behavior is not wanted here in outer FOR loop because loop variable A should hold complete file name with all spaces. Therefore delims= is used to define an empty list of delimiters to disable the line splitting behavior. Safer would be "delims= eol=" which defines also no end of line character.
The file name assigned to loop variable A is referenced with %%A as string in inner FOR loop which splits up the file name into two substrings (tokens). The first substring is the number assigned to specified loop variable B. The second substring after first sequence of spaces (tabs not possible in a file name) is assigned without any further splitting to next loop variable C according to ASCII table. In other words on file name 7612372 filename 50x50.jpg loop variable B holds 7612372 and filename 50x50.jpg is assigned to loop variable C.
The command REN renames the file by referencing complete file name as assigned to loop variable A to the part after first sequence of spaces as assigned to loop variable C.
The command PAUSE at end is added to see the error message output by command REN if renaming a file failed. There is nothing output except the prompt by PAUSE on all files could be renamed successfully.
The batch code can be enhanced further by using FINDSTR as filter to make sure that a file to rename starts really with one or more digits up to first space by using this code:
#echo off
for /F "delims=" %%A in ('dir "* *" /A-D-H /B 2^>nul ^| %SystemRoot%\System32\findstr.exe /R /C:"^[0123456789][0123456789]* "') do for /F "tokens=1*" %%B in ("%%A") do ren "%%A" "%%C"
pause
One more variant for renaming a file with name 03T30 NAME T ALL 40X40X2 - Copy.JPG to T30 NAME T ALL 40X40X2 - Copy.JPG:
#echo off
for /F "delims=" %%A in ('dir /A-D-H /B 2^>nul ^| %SystemRoot%\System32\findstr.exe /R "^[0123456789][0123456789]*"') do for /F "tokens=* delims=0123456789 " %%B in ("%%A") do ren "%%A" "%%B"
pause
DIR outputs the names of all non-hidden files in current directory. This output is redirected as input for FINDSTR which checks if the file name starts with one or more digits. Only those file names are output to STDOUT of background command process to be processed next by FOR.
The inner FOR interprets all digits and space character as string delimiters because of delims=0123456789 and assigns everything after first sequence of digits or spaces to loop variable B because of tokens=*. So loop variable B holds filename 50x50.jpg with 7612372 filename 50x50.jpg assigned to A and T30 NAME T ALL 40X40X2 - Copy.JPG for file name 03T30 NAME T ALL 40X40X2 - Copy.JPG.
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 /?
findstr /?
for /?
pause /?
ren /?
PS: I recommend the usage of the shareware file manager Total Commander which has a built-in multi-rename tool for renaming files and folders for people with no coding experience. Download, install and start Total Commander, navigate to the folder containing all these files, press Ctrl+A to select the files, press Ctrl+M to open multi-rename tool window and the rest is self-explaining. If you need nevertheless help, press key F1 to open the help page for multi-rename tool.
First of all thank you in advance for the assistance. What I was trying to do is this:
1) I have a folder containing files with names:
122098_482056_1453458.xls
122098_482057_1453459.jpg
122098_482057_1453460.xls
122098_482056_1453457.jpg
2) I want to move these files to folders that I have created with names:
PO_90_122118_0_US
PO_90_122122_0_US
PO_90_122098_0_US
Note: The 3rd part of the folder's name matches with first part of the name of the files.
I have tried the following script which resulted in an error respectively has done nothing.
I have used delims=_ as my file names are delimited by the character _.
tokens=1 is used so that the first part of the file name is used.
#ECHO OFF
SETLOCAL
SET "sourcedir=D:\2009\2nd step batch - Copy"
SET "destdir=D:\2009\1st step batch"
FOR /f "delims=_" %%I IN (
'dir /b /ad "%destdir%\*" '
) DO (
FOR /f "tokens=1delims=(" %%s IN ("%%~I") DO (
IF EXIST "%sourcedir%\%%s*" ECHO(MOVE "%sourcedir%\%%s*" "%destdir%\%%I\"
)
)
GOTO :EOF
This batch file does not output any line which means there is no file found to move and I don't know why.
What is wrong in batch code to move all 122098_* files to folder PO_90_122118_0_US?
Here is your batch code rewritten for this task.
#ECHO OFF
SETLOCAL
SET "SourceDir=D:\2009\2nd step batch - Copy"
SET "DestDir=D:\2009\1st step batch"
FOR /F "tokens=1-3* delims=_" %%A IN ('DIR /AD /B "%DestDir%\*" 2^>nul') DO (
IF EXIST "%SourceDir%\%%C_*" MOVE "%SourceDir%\%%C_*" "%DestDir%\%%A_%%B_%%C_%%D\"
)
ENDLOCAL
You might insert ECHO left to MOVE for testing the batch file before really moving the files in a second run without ECHO.
For each subdirectory found in destination directory the directory name is split up into 4 tokens using underscore as delimiter.
PO is assigned to loop variable A as defined on FOR command line.
90 is assigned to next loop variable in ASCII table which is B.
122098 or the other numbers of real interest are assigned to loop variable C.
And last everything after third underscore in subdirectory name is assigned to loop variable D without further splitting up.
The IF condition checks if there is any file starting with the number from subdirectory name assigned to loop variable C and an underscore. The appropriate files are moved if this condition is true.
It is important to specify as destination directory all 4 parts of the subdirectory name, i.e. the complete name of the current subdirectory.
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.
echo /?
endlocal /?
for /?
if /?
move /?
set /?
setlocal /?
2^>nul redirects the confusing error message output by command DIR to handle STDERR in case of no subdirectory found to the device NUL to suppress it. The redirection operator > must be escaped here with ^ to be interpreted as redirection operator on execution of command DIR and not as misplaced redirection operator for command FOR. See also the Microsoft article Using command redirection operators.
I need to get the names of all files within a folder to do a compare in Excel. I have this working and set up as a Send To feature. However, if the folder I right click on contains a space, it fails. Here is what I have:
#echo off
for /f "tokens=2 delims=:." %%x in ('chcp') do set cp=%%x
chcp 1252>nul
set dirpath=%1
dir %dirpath% dir /b /a | sort > "%dirpath%\FolderContents.txt"
chcp %cp%>nul
exit
Why are the file names not written to "Selected Folder\FolderContents.txt" if folder path contains 1 or more spaces?
There are several mistakes in those few lines of batch code.
The line with command DIR contains the command twice.
As the last paragraph output after several pages on running cmd /? in a command prompt window explains, a file/folder name (and other parameter strings) must be enclosed in double quotes if there is in name or path a space or one of the following characters: &()[]{}^=;!'+,`~
Therefore first argument of batch file on execution is enclosed in quotes if folder name contains a space. set dirpath=%1 assigns the folder name with the quotes to the environment variable dirpath. This results on next line in ""C:\Folder With Space"\FolderContents.txt" which can't be processed by command processor as expected by you.
A number left to redirection operator > could easily result in getting it interpreted as handle number. Although code page numbers are large enough to be not interpreted as handle number, it is better to have a space left to last redirection operator > in your code as %cp% is replaced by a code page number.
A really working and additionally simplified code for your task is:
#echo off
for /F "tokens=2 delims=:." %%x in ('chcp') do set "cp=%%x"
chcp 1252 >nul
dir "%~f1" /A-D /B /ON >"%~f1\FolderContents.txt"
chcp %cp% >nul
exit
The command DIR outputs just
the names of files because of option /A-D
in bare format because of option /B
ordered by name because of option /ON
and without path because of not using option /S for getting a list with all subdirectories included.
%~f1 is replaced by command processor by name of folder with full path without quotes.
Well, determining active code page of this and only this command process and restoring the code page before exiting entire command process is also not really needed in my point of view and therefore second and last but one line are also not necessary.
This variant of above writes the file names with path into the text file.
#echo off
chcp 1252 >nul
del "%~f1\FolderContents.txt" 2>nul
for /F "delims=" %%I in ('dir "%~f1" /A-D /B /ON 2^>nul') do (
>>"%~f1\FolderContents.txt" echo %~f1\%%I
)
exit
The redirection operator >> is now left to command echo to avoid that a file name ending very unlikely with 1, 2, ... is interpreted as handle number. A separating space can't be used here as this space would be also written into the file as being taken by command echo which would result in a trailing space on each file name in text 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 /?
chcp /?
dir /?
echo /?
exit /?
for /?
set /?
See also Microsoft article about Using command redirection operators.