How to open the newest Folder with a batch file? - windows

I have a folder with some subfolders, like:
C:\Users\User\Desktop\ABC\V1_0_1_win64
C:\Users\User\Desktop\ABC\V1_1_1_win64
C:\Users\User\Desktop\ABC\V1_1_4_win64
C:\Users\User\Desktop\ABC\V1_2_1_win64
C:\Users\User\Desktop\ABC\V1_3_0_win64
I want to open with the .bat file the latest revision, here: V1_3_0_win64.
How can I open always the latest revision automatically with the .bat file?

Here's an example using the existing comments as a base.
This version additionally uses findstr to ensure that the dir command wildcards actually match single digits.
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
Set "BaseDir=%UserProfile%\Desktop\ABC"
PushD "%BaseDir%" 2>NUL&&(Set "LatestVer=")||Exit /B
For /F Delims^=^ EOL^= %%A In (
'"Dir /B/AD-L/O-N "V?_?_?_win64" 2>NUL|"%__AppDir__%FindStr.exe" /I "V[0-9]_[0-9]_[0-9]_win64""'
)Do If Not Defined LatestVer Set "LatestVer=%%A"&GoTo OpenIt
Echo Latest version directory not found!&"%__AppDir__%Timeout.exe" /T 3 /NoBreak>NUL&Exit /B
:OpenIt
Start "" "%SystemRoot%\Explorer.exe" "%LatestVer%"
The example above assumes by "open" you actually meant in Windows Explorer, so I have included that as a fully qualified command, despite Start "" "%LatestVer%" also being valid. You may need to adjust that command, as well as the path between the = and closing " on line 3, (to suit your chosen base directory source location).
To read the usage information for the commands used, open a Command Prompt window and enter the command name followed by its help option. e.g.
echo /?, setlocal /?, set /?, pushd /?, exit /?, for /?, dir /?, findstr /?, if /?, goto /?, timeout /? and start /?.

Related

Windows batch copy to sort folders into folders based on partial name

I have a directory full of folders beginning with 5-digit numbers:
\12611_Ants
\12866_Boats
\13898_Cats
\13898B_Misbehaving_Cats
I would like a batch script which will create (if necessary) folders in order to sort these folders in groups of 100, so in this example, \12600, \12800, and \13800 would be created, and:
\12611_Ants -> \12600
\12866_Boats -> \12800
\13898_Cats -> \13800
\13898B_Misbehaving_Cats -> \13800
Leaving me with:
\12600
\12800
\13800
At a later date, I may then have:
\12600
\12800
\13800
\12825_Bats
\14055_Pangolins
And I would want it to leave \12600, \12800, and \13800 alone, sorting only the \12825_Bats and \14055_Pangolins folders:
\12825_Bats -> \12800
\14055_Pangolins -> \14000
I am getting hung up on selecting the correct sorting folder based on the five digit number.
I do not usually post answers to off topic code requests, but there are too many individual parts to try to explain or link within the comment section. Here therefore is a quick example to assist you, which I will not be explaining further.
It uses the dir command to get your directory names which include an underscore, and the findstr utility to confirm that their names begin with exactly five numbers. Once it has the information it needs it uses the Robocopy utility to move the directories into their respective sorted parents.
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
If /I Not "%__CD__%" == "%~dp0" CD /D "%~dp0"
For /F "EOL=? Delims=" %%G In ('Dir *_* /B /A:D
^| %SystemRoot%\System32\findstr.exe
"^[0123456789][0123456789][0123456789][0123456789][0123456789][^0123456789]*_"
') Do (Set "DName=%%G" & SetLocal EnableDelayedExpansion
%SystemRoot%\System32\Robocopy.exe "%%G" "!DName:~0,3!00\%%G" /E /Move 1>NUL
EndLocal)
The batch file should be placed in the same location as your directories.
To learn how each of the used commands work, please open a Command Prompt window, and enter the following, pressing ENTER after each:
echo /?,
setlocal /?,
if /?,
cd /?,
dir /?,
findstr /?,
for /?,
set /?,
robocopy /?.

Using CMD on Windows to remove a specific substring from a directory of files

I frequently use a free online lossless file compressor to save space on my disk and make transferring and pushing repos easier. My main problem with the compressor is it appends "-min" to the end of every filename. For various reasons, I want to replace the original files by overwriting them; instead of deleting the old files and keeping the new files (with the "new" names).
For my PDF directory, I tried this:
FOR /R %f IN (*-min.pdf) DO REN "%f" *.pdf
And it seems to correctly find all the corresponding files, but their names remain the same. What am I doing incorrectly? Is there a single command that would be file-format-agnostic, so I wouldn't have to sub out the file extension for txt's, png's, etc?
I just need it to remove the -min from the end of each filename (before the file extension).
FOR /R %f IN (*-min.pdf) DO REN "%f" *.pdf
For a one liner (at the cmd prompt) remove echo from the following.
cmd /v:on /c "for /R %f in (*-min.pdf) do #set "nx=%~nxf" & echo ren "%~ff" "!nx:-min.pdf=.pdf!""
The above can be easily changed to perform other string manipulations, but it is not technically foolproof, for example it will rename a file named "a-min.pdf.b-min.pdf-c-min.pdf" to "a.pdf.b.pdf-c.pdf.". If that is a concern in this case, then use the following, which is essentially the same as in #Mofi's answer.
cmd /v:on /c "for /R %f in (*-min.pdf) do #set "nn=%~nf" & echo ren "%~ff" "!nn:~0,-4!%~xf""
The task can be done with a batch file with following command lines:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "delims=" %%I in ('dir "%~dp0*-min.*" /A-D /B /S 2^>nul') do (
set "FullFileName=%%I"
set "FileNameOnly=%%~nI"
set "FileExtension=%%~xI"
setlocal EnableDelayedExpansion
if /I "!FileNameOnly:~-4!" == "-min" ren "!FullFileName!" "!FileNameOnly:~0,-4!!FileExtension!"
endlocal
)
endlocal
The command DIR executed by a separate command process started by FOR in background with %ComSpec% /c and the command line between ' appended as additional arguments outputs also file names like Test-File!-min.x.pdf with full path. For that reason the IF condition makes sure to rename only files of which file name really ends case-insensitive with the string -min like Test-File!-MIN.pdf.
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 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 /? ... explains %~dp0 ... drive and path of argument 0 which is full path of the batch file which always ends with a backslash and for that reason concatenated with the wildcard pattern *-min.* without an additional backslash. %~dp0 can be removed to run DIR on current directory and all its subdirectories instead of batch file directory and all its subdirectories.
dir /?
echo /?
endlocal /?
if /?
ren /?
set /?
setlocal /?
See also this answer for more details about the commands SETLOCAL and ENDLOCAL.

Changing command to exclude subfolders

I am using this command line
for /r /d %F in (.) do #dir /b "%F" | findstr "^" >nul || echo %~fF
to find empty folders.
However this command is working for subfolders too. How can I change it to exclude the sub folders?
Remove the /r from the command, use this:
for /d %F in (*) do #dir /b "%F" | findstr "^" >nul || echo %~fF
As this is clearly for the current directory, I would off a slightly different alternative. This is because For /D doesn't pick up every directory, it ignores hidden ones, and Dir /B alone, does not select every file and directory.
For /F "EOL=? Delims=" %G In ('Dir /B/AD') Do #Dir /B/A "%G" 2>NUL|%__AppDir__%find.exe /V "">NUL||Echo %G
If you prefer a relative path for your results, just use Echo .\%G instead
The answer uses 2>NUL to redirect any File Not Found error messages to the NUL device. It also uses find.exe as an alternative to findstr.exe, to ensure that the answer is less similar than the existing one, and because you don't really need its special functionality.
To get more information about the commands used, please open a cmd window, and enter the following commands as necessary:
  For command for /?  or help for
  Dir command dir /?  or help dir
Find command find /? or help find
Echo command echo /? or help echo
The %__AppDir__% variable is a special dynamically created variable, the content of which cannot be modified. This will always point to your appropriate \System32 directory, whether running under a 32-bit or 64-bit process. The result is that the command will not fail to run the appropriate version of Microsoft's find.exe in its correct location, eliminating a failure, should your standard environment become corrupted or modified. In addition, I used the .exe extension for find, because it is not an internal command and should your %PATHEXT% variable become corrupted or modified, the command would still work as intended.
[Edit /]
As you've further clarified that you're looking for those without files, not without files and directories, I'd offer this alternative, using the Microsoft's where.exe, windows-vista minumum:
For /F "EOL=? Delims=" %G In ('Dir /B/AD') Do #%__AppDir__%where.exe /Q "%G":*>Nul||Echo %G
If you prefer a relative path for your results, just use Echo .\%G instead
To get more information about the where command, please open a cmd window, and enter either the following command, where /?, or this one help where.

How to delete *.bak files recursively older than a specific date depending on directory in file path?

I'm writing a batch file for Windows 7.
I currently have a code that deletes old backups from our masters folders within our site management folders. This is the code:
for /d %%A in ("Y:\*.*") do del /s /q /f "%%A\masters\*.bak"
However I need to code it to only delete things that are older than 3 years, which would be this code:
forfiles /P "Y:\" /S /D -1096 /M *.bak /C "cmd /C del #path"
However I need what is in the top code so that I can delete all *.bak files from the masters folders that exist within our 173 site management folders. I'm ripping my hair out figuring this out. I can't have it deleting *.bak files from our other folders.
I've tried combining the code, but below command line in batch file does not work as expected:
forfiles /S /D -1096 /M *.bak /C "cmd /C for /d %%A in ("Y:\*.*") do del /s /q /f "%%A\masters\*.bak"
How to delete all *.bak files older than 3 years anywhere in directory tree if second directory in file path is masters and keep all other *.bak files being newer or in a directory where second directory in file path is not masters?
Create first a batch file C:\Temp\DeleteBackup.bat with the following commands:
#echo off
set "BackupFileName=%~1"
if not "%BackupFileName:\masters\=%" == "%BackupFileName%" ECHO del "%BackupFileName%"
This batch code checks if the file name with full path and file extension contains anywhere \masters\ by removing this string case-insensitive from left argument of string comparison.
If the remaining string is not equal the unmodified file name string because of containing \masters\ in path, the IF condition is true and the backup file would be deleted if there would not be command ECHO which results in just displaying the DEL command line.
For example the complete list of backup files is:
Y:\masters\Level2\Level3\Level4\Level5\Test1.bak
Y:\Folder2\masters\Level3\Test2.bak
Y:\Folder3\Level2\masters\Level4\Test3.bak
Y:\Folder4\Level2\Level3\Level4\Level5\Test4.bak
Y:\Folder5\Level2\Test5.bak
Y:\Folder6\Level2\Level3\Level4\Level5\Level6\Test6.bak
Y:\Folder7\masters\Test7.bak
The files deleted would be:
Y:\masters\Level2\Level3\Level4\Level5\Test1.bak
Y:\Folder2\masters\Level3\Test2.bak
Y:\Folder3\Level2\masters\Level4\Test3.bak
Y:\Folder7\masters\Test7.bak
And the files remaining would be:
Y:\Folder4\Level2\Level3\Level4\Level5\Test4.bak
Y:\Folder5\Level2\Test5.bak
Y:\Folder6\Level2\Level3\Level4\Level5\Level6\Test6.bak
Then use in your batch file:
forfiles /P "Y:\" /S /D -1096 /M *.bak /C "C:\Temp\DeleteBackup.bat #PATH"
It is of course possible to modify DeleteBackup.bat to check if directory in second directory hierarchy level is masters.
#echo off
for /F "tokens=3 delims=\" %%I in ("%~1") do if /I "%%I" == "masters" ECHO del "%~1"
This code would delete from the complete list above the files:
Y:\Folder2\masters\Level3\Test2.bak
Y:\Folder7\masters\Test7.bak
And the files remaining would be:
Y:\masters\Level2\Level3\Level4\Level5\Test1.bak
Y:\Folder3\Level2\masters\Level4\Test3.bak
Y:\Folder4\Level2\Level3\Level4\Level5\Test4.bak
Y:\Folder5\Level2\Test5.bak
Y:\Folder6\Level2\Level3\Level4\Level5\Level6\Test6.bak
Robert Chizmadia Jr. asked in an already deleted comment:
Is it possible to use GOTO instead of calling another batch file on FORFILES command line?
The answer on this additional question:
FORFILES is not an internal command of cmd.exe like FOR. It is a console application stored in directory %SystemRoot%\System32 if used version of Windows has it pre-installed at all.
The command to execute as specified after FORFILES option /C must be an executable or script. That is the reason why cmd /C is always used when an internal command of Windows command interpreter cmd.exe like DEL should be executed by FORFILES whereby the really complete command would be %SystemRoot%\System32\cmd.exe /C.
So it is not possible to use a command like GOTO in FORFILES command as there is no executable or script with name GOTO.
Also GOTO in a FOR loop exits the loop and therefore interpreting of command lines of batch files continues on another position in batch file.
However, it is possible to use the same batch file for the file path evaluation and backup file deletion as used to run FORFILES command.
Example 1 with batch file not expecting any parameter for default operation:
#echo off
if not "%~1" == "" (
for /F "tokens=3 delims=\" %%I in ("%~1") do if /I "%%I" == "masters" ECHO del "%~1"
goto :EOF
)
%SystemRoot%\System32\forfiles.exe /P "Y:\" /S /D -1096 /M *.bak /C "%~f0 #PATH"
If this batch file is executed with an argument, it runs the FOR loop written to check if second directory in file path is masters and delete this file in this case after removing ECHO. Otherwise on starting the batch file without any parameter the batch file runs the FORFILES executable.
Example 2 with batch file expecting 1 or more parameters for default operation:
#echo off
if "%~1" == "#Delete:Backup#" (
for /F "tokens=3 delims=\" %%I in ("%~2") do if /I "%%I" == "masters" ECHO del "%~2"
goto :EOF
)
rem Other commands processing the parameters.
%SystemRoot%\System32\forfiles.exe /P "Y:\" /S /D -1096 /M *.bak /C "%~f0 #Delete:Backup# #PATH"
rem More commands executed after the deletion of the backup files.
This is nearly the same as example 1 with the difference that if first parameter used on running the batch file is case-sensitive the string #Delete:Backup#, the batch file expects as second parameter the name of a backup file with full path being deleted if second directory in file path is masters.
Like in all batch code examples the command ECHO must be removed before del command also in this code example to really execute the deletion of the backup files.
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 /?
for /?
forfiles /?
goto /?
if /?
set /?

Deleting all files and directories from desktop except .lnk

Im trying to write a script for keep clear my desktop. I want to delete all files and directories except the shortcuts.I use Windows 10. My batch code is the following:
#echo off
COLOR 0E
cd "C:/Users/DA/Desktop"
FORFILES /S /C "if #ext!=lnk del /F /Q /S"
rd /S /Q "."
pause
exit
Maybe it is a dumb error, but Im a newbie in Windows command line. Thanks in advance.
There are several issues in your code:
You must precede the command line after the /C switch of forfiles with cmd /C, because you are using internal console commands (if, del). If you omit cmd /C, forfiles tries to find a program file named if, which does not exist.
There is no comparison operator != for the if statement. You mean not equal, so you need to state if not <expression1>==<expression2> instead.
The #ext variable expands to the file extension enclosed in quotation marks, so you need to state them around lnk also. Since the "" are in the quoted command line behind forfiles /C, you need to escape them like \" in order to establish literal " characters.
You forgot to specify what to delete at the del command.
The switches /S of forfiles and also del mean to process also items in sub-directories, but I assume you do not want that, because you want to clean up your Desktop directory.
There is the rd command, so I assume you want to remove any directories from the Desktop either. However, rd /S /Q "." tries to remove the entire Desktop directory (which will fail as your batch file changes to that directory by cd). I would put the rd command into the forfiles command line as well, because there is the possibility to check whether or not the currently iterated item is a file or a directory (forfiles features the #isdir variable for that purpose).
The cd command works only if you are running the batch file from the same drive where the Desktop directory is located (unless you provide the /D switch). I would go for the pushd command, which changes to the Desktop directory temporarily, until a popd command is there.
Instead of hard-coding the location of the Desktop directory, I would use the built-in environment variable %USERPROFILE%, which points to the user profile directory of the currently logged on user, where the Desktop directory is located in.
The exit command without the /B switch does not only end the batch file, it also terminates the command interpreter instance the batch file is running in. This does not matter when you run the batch file by double-clicking, but it does matter when you execute it within command prompt.
Here is the corrected and improved code:
#echo off
title Clean Up Desktop & rem // (this is the window title, just for fun)
color 0E
pushd "%USERPROFILE%\Desktop" || exit /B 1 & rem // (the command after `||` runs if `pushd` fails, when the dir. is not found)
rem /* Here you can see how to distinguish between files and directories;
rem files are deleted with `del`, directories are removed with `rd`.
rem The upper-case `ECHO`s are there for testing purposes only;
rem remove them as soon as you actually want to delete any items: */
forfiles /C "cmd /C if #isdir==FALSE (if /I not #ext==\"lnk\" ECHO del /F /Q #relpath) else ECHO rd /S /Q #relpath"
pause
popd & rem // (this restores the previous working directory)
exit /B & rem // (this quits the batch file only; not necessary at the end of the script)
You can try something like that :
#echo off
COLOR 0E
CD /D "%userprofile%\Desktop"
Rem To delete folders
for /f "delims=" %%a in ('Dir /b /AD ^| find /v "lnk"') do echo rd /S /Q "%%a"
pause
Rem To Delete files
for /f "delims=" %%a in ('Dir /b ^| find /v "lnk"') do echo del /F /Q /S "%%a"
pause
exit
NB: When your execution is OK, just get rid of echo command
You can use the for and if commands to accomplish this:
#echo off
COLOR 0E
cd C:/Users/DA/Desktop
for /d %x in (*) do #rd /s /q "%x"
for %i in (*) do if not %i == *.lnk del "%i"
pause
Pretty simple and works great.
Make sure that %i and %x are in "".

Resources