I need to get a list of empty folders in a given location, older then x days. Using "forfiles" I'm able to get all older folders, but not the empty ones. Using "for" I'm able to get all empty folders, but I can't seem to set the older ones.
Get empty folders:
#for /r "c:\FileStore" /d %F in (.) do #(dir /b "%F" | findstr "^" >nul || echo %~fF)
Get older folders:
ForFiles /p "C:\FileStore" /s /d -3 /c "cmd /c if #isdir==TRUE echo #path"
How do I combine these 2 commands?
You need to escape the quotation marks of the part findstr "^" for forfiles. There is the way \", but I do not recommend this, because the " are still recognised by the command interpreter cmd (user Ben Personick shows how to do this in his answer though). Anyway, I would use 0x22 instead in order to hide the quotes from cmd, like this:
forfiles /S /P "C:\FileStore" /D -3 /C "cmd /C if #ISDIR == TRUE (dir /B /A #PATH | findstr 0x22^0x22 > nul || echo #PATH)"
Instead of findstr "^" you could also use find /V "":
forfiles /S /P "C:\FileStore" /D -3 /C "cmd /C if #ISDIR == TRUE (dir /B /A #PATH | find /V 0x220x22 > nul || echo #PATH)"
But the easiest way is to use set /P:
forfiles /S /P "C:\FileStore" /D -3 /C "cmd /C if #ISDIR == TRUE (dir /B /A #PATH | set /P _= || echo #PATH)"
N. B.:
forfiles only regards the date (not the time) of the last modification, but not the creation date/time.
Your biggest hurdle is escaping the double quotes in the FindStr and the Carrot needing doubling too (or it will stop the following quote from being escaped.)
Hmm strange I thought you asked to delete these directories, since you haven't I'll amend it as such.
ForFiles /P "c:\FileStore" /d -3 /C "CMD /C if #isdir==TRUE ( DIR /B #Path | FindStr \"^^\" >NUL || ECHO Empty Folder: #Path )"
Also since you are only looking for a list of those it does make sense to kill the output from the FindStr so I added the >Nul back in.
Again not sure how I ot it into my head that you wanted to remove the empty folders older than 3 days old, since there isn't such a requirement, the portion about needing to re-run the command is moot and I've remove dit for now.
Related
I'm stuck with this script
echo off
SET pathAdobe="C:\Program Files\Adobe\Acrobat DC\Acrobat\Acrobat.exe"
SET pathDestination=T:\
cd %pathDestination%
(1)
forfiles /P %pathDestination% /M *8.pdf /D +0 /C "cmd /c echo #PATH"
(2)
"C:\Program Files\Adobe\Acrobat DC\Acrobat\Acrobat.exe" /o /h /s /t "%pathDestination%\pdf8.pdf" "MyPrinterName"
pause
(1) Work fine, i got a list of pdf according my forfiles
(2) Work fine, print my file
(3) But when i want to mix the 2 first step that doesn't work like i want
forfiles /P %pathDestination% /M *8.pdf /D +0 /C "CMD /C "%pathAdobe%" /o /h /s /t #PATH"
I got this error:
Error: Invalid argument or option - « Files\Adobe\Acrobat »
I try to escape with ^ " \ but don't change the result
Can't find a solution!
Thanks for any help you can give me :)
J
Your issue is that you are including double quotes, in the wrong places, and that those double quotes require escaping. You can escape those using backward slashes (\"), or by using their hexadecimal character code, (0x22).
Backward slash example:
#Echo Off
Set "pathAdobe=%ProgramFiles%\Adobe\Acrobat DC\Acrobat\Acrobat.exe"
Set "pathDestination=T:\"
CD /D "%pathDestination%" 2> NUL || Exit /B
%SystemRoot%\System32\forfiles.exe /M "*8.pdf" /D 0 /C "%SystemRoot%\System32\cmd.exe /D /C \"\"%pathAdobe%\" /o /h /s /t #Path \"MyPrinterName\"\""
Pause
Hexadecimal character example:
#Echo Off
Set "pathAdobe=%ProgramFiles%\Adobe\Acrobat DC\Acrobat\Acrobat.exe"
Set "pathDestination=T:\"
CD /D "%pathDestination%" 2> NUL || Exit /B
%SystemRoot%\System32\forfiles.exe /M "*8.pdf" /D 0 /C "%SystemRoot%\System32\cmd.exe /D /C 0x220x22%pathAdobe%0x22 /o /h /s /t #Path 0x22MyPrinterName0x220x22"
Pause
I am using the below to count the files number which created days is older than 10 days:
forfiles /m *.txt /d -10 /c "cmd /c echo #path" | find /c /v "" >count.tmp
for /f %%b in (count.tmp) do #set /a count=%%b
is there anyway that can assign return value without save a file?
for /f %%b in ('forfiles /m *.txt /d -10 /c "cmd /c echo #path" ^| find /c /v "" ') do set /a count=%%b
should assign count to the value output from forfiles.
See for/? from the prompt for documentation. The caret before the pipe is an escape character to inform cmd that the pipe is part of the command to be executed.
I want to write a batch that finds all docs less than 50 mb in c:\ and copy them in a folder but ignore system directory docs. I prefer it does not even search in the system dir.
Here is my batch that finds and copies all files less 50 mb in right directory but i can not make it to ignore system from searching or C:\Windows directory.
#ECHO off
:: variables
SET odrive=%odrive:~0,2%
SET backupcmd=xcopy /s /c /d /e /h /i /r /y
MKDIR "C:\Users\Documents\USBBackups\DOC\C"
forfiles /P C:\ /M *.DOC* /S /C "cmd /c if #fsize leq 50000000 echo #PATH " > "C:\Users\Documents\USBBackups\DOCC.txt"
FOR /F "tokens=*" %%a in (C:\Users\Documents\USBBackups\DOCC.txt) do xcopy %%a "C:\Users\Documents\USBBackups\DOC\C" /c /h /i /r /y
#ECHO off
There is no way to tell forfiles to exclude certain directories when switch /S is provided. You will have to write your own code that does that.
I would not use forfiles for that due to poor performance, but standard for instead:
#echo off
for /D %%D in ("%SystemDrive%\*.*") do (
if /I not "%%D"=="%SystemRoot%" (
pushd "%%D"
for /R %%F in ("*.doc?") do (
if %%~zF LEQ 50000000 (
echo %%F
)
)
popd
)
)
Here the root directory level is enumerated by for /D. All directories other than %SystemRoot% are enumerated recursively by for /R.
I changed the search pattern from *.doc* to *.doc? in order not to include files ending in .doc.lnk for example, which I guess you do not want to be retrieved.
Instead of the echo command you can directly place your xcopy command line with "%%F" provided as the copy source.
You can do the same directly in command prompt as a one-liner, like this:
for /D %D in ("%SystemDrive%\*.*") do #if /I not "%D"=="%SystemRoot%" pushd "%D" & (for /R %F in ("*.doc?") do #if %~zF LEQ 50000000 echo %F) & popd
I recommend not to walk through the entire directory tree and later filtering by something like findstr /V /I /L /B /C:"%SystemRoot%", because in that case you were wasting time enumerating a huge number of items which you ignore afterwards.
However, if you do want to rely on forfiles /S, the working command line looks like this:
2> nul forfiles /S /P "C:\\" /M "*.doc*" /C "cmd /C if #isdir==FALSE if #fsize LEQ 50000000 echo #path" | findstr /V /I /L /B /C:"\"%SystemRoot%"
Adapt this technique of using findstr to filter out certain names.
To see size of folders in Documents, excluding music, video, or pictures folders.
for /f "skip=3 tokens=3" %A in ('Reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" /v "Personal"') do set doc=%A
for /f "usebackq tokens=2* delims= " %i IN (`dir "%doc%" /a /s ^|findstr /i /v "\/"^|findstr /l /v "Pictures Music Video"`) DO #echo %j&echo.
However you could start the forfiles command in the c:\users or the particular users home folder (%userprofile%). You specify to start at c:\ which includes all folders.
forfiles /P %userprofile% /M .DOC /S /C "cmd /c if #fsize leq 50000000 echo #PATH "
forfiles /P c:\users /M .DOC /S /C "cmd /c if #fsize leq 50000000 echo #PATH "
i would like to know how you can delete multiple files in different folders with batch commands.
I have the following code, this code works fine for 1 map but i need to do it for multiple maps :
forfiles /p "D:\CHILI_Publisher\Data\Environments\Adecco\Cache_Data\Assets" /s /d -10 /c "cmd /c echo #file"
PAUSE
This is the code for the various maps and various file types with wildcards (this one gives an error : The directory name is invalid:
forfiles /p "D:\CHILI_Publisher\Data\Environments\*.*\Cache_Data\*.*" /s /d -10 /c "cmd /c echo #file"
PAUSE
Tl;DR : I have an error and would like to know how to use a wildcard correctly in batch files.
You can wrap FORFILES in a FOR loop:
for /d %D in (c:\temp\a*;c:\temp\b*;c:\temp\c*) do forfiles /p %D /s /c "cmd /c echo #file" /d -10
If you need to find all folders named CACHE_DATA under a super folder you can navigate to the super folder (cd D:\CHILI_Publisher\Data\Environments) and run this:
for /f %F in ('dir /B /S /AD cache_data') do for /d %D in (%F) do forfiles /p %D /s /c "cmd /c echo #file" /d -10
If you put the script in a BATCH file remember to escape % with %%.
The forfiles command establishes several variables, indicated by a leading #, which return data concerning the currently iterated item to the loop body.
All the variables related to the path and name of the iterated item return the value enclosed in "". Those are: #file, #fname, #ext, #path and #relpath.
So: how can you get rid of the enclosing double-quotes?
For example, the following code returns relative paths to text files in the given root directory:
forfiles /P "C:\root" /M "*.txt" /C "cmd /C echo #relpath"
Assuming that C:\root contains two files file1.txt and file2.txt, the output will be:
".\file1.txt"
".\file2.txt"
However, I want the list of files without the surrounding "".
I am working on Windows 7 64-bit.
One approach is to nest a for %I loop within the forfiles and use the %~I expansion -- use this code in a Command Prompt window:
forfiles /P "C:\root" /M "*.txt" /C "cmd /Q /C for %I in (#relpath) do echo %~I"
To use that code within a batch file you must double the %-signs:
forfiles /P "C:\root" /M "*.txt" /C "cmd /Q /C for %%I in (#relpath) do echo %%~I"
The returned list of files will be (relying on the sample files from the original question):
.\file1.txt
.\file2.txt
Another variant is to nest another forfiles in the body of the initial one, because forfiles removes (non-escaped) double-quotes within given strings like the command line after /C:
forfiles /P "C:\root" /M "*.txt" /C "cmd /C forfiles /P #path\.. /M #file /C \"cmd /C echo #relpath\""
Or alternatively (the doubled inner forfiles is intentional, this works around a bug -- see this post):
forfiles /P "C:\root" /M "*.txt" /C "forfiles forfiles /P #path\.. /M #file /C \"cmd /C echo #relpath\""
The inner forfiles will enumerate exactly one item, which is the one passed over by the outer loop. Since #relpath is already expanded when the inner loop is executed, the quotes are removed as they are not escaped.
So the returned list of files looks like (again taking the sample files from the original question):
.\file1.txt
.\file2.txt
The additional line-break between the lines is generated by forfiles. You can avoid that using redirection (dismiss forfiles output, but display only the echo output in the console window):
> nul forfiles /P "C:\root" /M "*.txt" /C "cmd /C forfiles /P #path\.. /M #file /C 0x22cmd /C > con echo #relpath0x22"
I remove the quotes like this:
#ECHO OFF
GOTO START
usage:
script.bat "*.txt" "c:\Documents"
script.bat "*.txt"
script.bat
If no arguments added it will crawl the current directory with wildcard mask (*)
Avoid root directory (c:\) because too many sub directories for the output console.
:START
IF "%~2"=="" (SET "_FD=%CD%") ELSE (SET "_FD=%~2")
IF "%~1"=="" (SET "_MA=*") ELSE (SET "_MA=%~1")
SETLOCAL ENABLEDELAYEDEXPANSION
FOR /F "usebackq delims=" %%A in (
`forfiles /p %_FD% /s /m %_MA% /C "cmd /c ECHO #relpath"`
) DO (
SET "myfile=%%~A"
ECHO !myfile:~2!
)
ENDLOCAL
GOTO :EOF
results:
thumbnails\A0-1.jpg
thumbnails\new folder\img.jpg