Changing command to exclude subfolders - windows

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.

Related

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.

Recursively search files with filter on full path in batch file

I can use dir /s /b *.Tests.*.dll to recursively find all files that match that pattern, but I need to also find them only if they are in \bin\Debug\ instead of \obj\Debug\ or \bin\Release.
So I tried this command:
dir /s /b Tests\Unit\*\Debug\bin\*.Tests.*.dll
But it fails with The filename, directory name, or volume label syntax is incorrect.
I couldn't find any previous SO question that addresses this problem but if one exists please point it to me.
Is there any way to achieve the desired result (apply filter on entire path)? My intent is to use the list to run NUnit on each unit test assembly in my project under jenkins using this command from Use NUnit Console Runner to run all tests under a folder
for /f %%f in ('dir .\test\ /b /s *.Test.dll') do nunit-console /nologo /noshadow /framework:net-4.0 /xml:.\test\TestResults.xml "%%f"
On linux I would have used ls -r ... | grep ... | xargs ... and I'm trying to achieve something similar here.
I only need to apply this additional filter on the parent folders as well. If it's not possible I'll have to use PowerShell.
FOR /d %%a IN ("%sourcedir1%\*") DO DIR /s /b "%%~a\%sourcedir2%\*.exe" 2>nul
where sourcedir1 is the part of the required path before the \*\ and sourcedir2 the part after.
simply assign each dirname in turn to %%a and use that as the start point for the second dir
I found DOS batch script with for loop and pipe, and using the idea there I constructed this command:
for /f %f in ('dir /s /b Tests\Unit ^| findstr \\bin\\Debug\\.*\.Tests\..*\.dll$"') do echo %f
No I only need to replace %f with %%f for batch files, and I can replace echo %f with the command to run nunit.

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 "".

I need a batch file to generate a list with *only* file names

I need it to work on Win10 and Win7 machines. If I can get this to work I'll make a batch file.
Winkey, "cmd"
cd "e:\media\trainingvids"
dir *.* /s /b /a -d > c:\temp\dork.txt
So, to state the obvious but make sure I'm getting it, I'm opening a command prompt, changing to the correct directory, doing a directory listing of all files (including sub-directories (/s), no headers or footers so 'bare' format (/b), and trying to NOT display the directory (/a -d) – and then sending/piping that (>) to a file I've designated to be named and created (dork.txt) in a temporary directory (\temp) that already exists on my c:.
The problem is that it doesn't work. I'm not able to find a way to NOT include the full path along with the file names. I need a nudge with the syntax. Or maybe I've got it all wrong and it can't be done in this way.
What does my Basic batch file look like that can do this?
You will need the for /F command to accomplish this:
> "D:\temp\dork.txt" (
for /F "eol=| delims=" %%F in ('
dir /B /S /A:-D "E:\media\trainingvids\*.*"
') do #(
echo(%%~nxF
)
)
You placed a SPACE between /A and -D in your dir command line, which must be removed.
Since I stated the full path to the target directory in the dir command and also to the output file, you can save this script at any location and run it from anywhere.
for /f "delims=" %%a in ('dir /s/b/a-d') do echo %%~nxa
should accomplish that task.
If you can tolerate double quoted names this batch file works well.
set myPath=c:\temp
set myMask=*.pdf
set myLog=c:\temp\myLogFile.log
FORFILES /P %myPath% /S /M %myMask% /C "CMD /C ECHO #file >> %myLog%"
Alter the values to meet your needs.
You're almost there with:
dir /s /w /a-d | find "."
The only drawback is that you get the file names in columns, and possibly a Volume line which you can remove with another find filter.

How to run *.exe /key from the .bat in loop

I have directory structure:
DIR
|-UNINSTALL.BAT
|-component_name
|-source
|-setup.exe
|-uninst.bat
|-another_component_name
|-source
|-setup.exe
|-uninst.bat
|-yet_another_component_name
|-source
|-setup.exe
|-uninst.bat
and so on...
In every directory like "component_name" I have setup.exe file which installs current component to the palette component in Delphi.
uninst.bat contains only this string:
"setup.exe" /uninstall
So I need to write UNINSTALL_ALL.bat in DIR that would run the uninst.bat in all component directories.
Thank you in advance.
you could do it with this line:
for /f %%a in ('dir /b /s uninst.bat') do call %%a
note that the '%%' is necessary for batch files. if you are testing this on the command line, only use one '%'
That is kind of akward in a batch file. Though you could probably do it with the foreach statement. I would suggest though that you have a look at Powershell which will definitely give you the power to do this simply and a whole lot more if you want it.
You want to use the "for" construct. Something like this:
for %%i in (component_name another_component_name yet_another_component_name) do %%i\uninst.bat
The double-escaping (%%) is necessary if you put the "for" loop in a batch file. If you are just typing it out in a command prompt, only use 1 %.
Also, you may be able to use a wildcard to match against the directory names, if they follow some convention. Open up a command prompt and run "for /?" to see everything it can do...I believe there is a /d option to match against directories. That would look something like:
for /D %%d in (component_*) do %%d\uninst.bat
(obviously, adjust the wildcard to match your component directories.)
This should work:
FOR /F %%a IN ('dir /b /s uninst.bat') DO START /B %%a
if you want them to wait each other, use this:
FOR /F %%a IN ('dir /b /s uninst.bat') DO START /B /WAIT %%a
The way you describe your problem, you have only one level of sub-directories and you always call the same batch, from the root. Therefore:
Uninstall_all.cmd
#echo off
for /F "delims=" %%d in ('dir /b /ad') do cd "%%d"& start /b /w ..\uninstall.bat& cd ..
Should do the trick.

Resources