0

In another topic I found the following code snippet to check if a string contains a substring.

if not x%str1:bcd=%==x%str1% echo It contains bcd

Now I am trying to implement this in my FORFILES method. FORFILES should delete XML files that are in a subfolder that contains the substring 'IMG'. I adapted the code as follows:

set loglocation=C:\Tools\PurgeOldFiles\log\DELETEOLD_XML_IMG.txt
set olderthan=30
set source=X:\Test
set extension=XML

FORFILES -p%source% -s -m*.%extension% -d-%olderthan% -c"CMD /C if not x@RELPATH:img=%==x@RELPATH DEL @PATH\@FILE /q & echo @PATH\@FILE deleted." >> %loglocation%

It does not delete the old (older than 30 days) XML files in an IMG subfolder.

I guess that I have some kind of (syntax) error in "x@RELPATH:img=%==x@RELPATH".

Community
  • 1
  • 1
Malawirel
  • 115
  • 6
  • 16

2 Answers2

1

You will need an interim environment variable, say VAR, and delayed expansion to accomplish that.


At first let us build the code that needs to be executed in the forfiles loop:

if @isdir==FALSE (
    set VAR=@relpath
    if not #!VAR:%search%=!==#!VAR! (
        del /Q @path
        echo @path deleted.
    )
)

This does the following steps:

  • check whether the matched item is a file, skip the rest otherwise;
  • assign the value of @relpath to the variable VAR; note that @relpath is expanded to a relative path enclosed in "";
  • check whether the expanded relative path contains at least one instance of the search string, skip the rest if not; note that the search is done in a case-insensitive manner;
  • delete the matched path, return the related log message; @path already contains the file name plus extension, so you do not need @file;

Now let us write the above code as a single line and put it together with forfiles:

set "loglocation=C:\Tools\PurgeOldFiles\log\DELETEOLD_XML_IMG.txt"
set "olderthan=30"
set "source=X:\Test"
set "extension=XML"
set "search=img"

forfiles /S /P "%source%" /M "*.%extension%" /D -%olderthan% /C "cmd /V:ON /C 0x22if @isdir==FALSE ((set VAR=@relpath) & if not #!VAR:%search%=!==#!VAR! (del /Q @path & echo @path deleted.))0x22" >> "%loglocation%"

The /V switch of cmd enables delayed expansion; the !VAR! syntax makes use of it (opposed to %VAR%). Type cmd /? for more information on that.


Notes:

The search for the img substring does not care about where (at which level in the path) a match is found, nor does it detect how many matches occur.

Be aware that the switch /S of forfiles makes it to enumerate the given directory recursively.

aschipfl
  • 33,626
  • 12
  • 54
  • 99
  • 1
    You can use FINDSTR to be precise about where IMG appears. Also, the delete message should only be printed if the delete was successful. See [my answer](http://stackoverflow.com/a/33586110/1012053) – dbenham Nov 07 '15 at 19:20
  • Good idea to use `findstr`, @dbenham! unfortunately, the question does not clearly say which part of the relative path needs to be searched for the substring `img`... – aschipfl Nov 07 '15 at 20:25
1

You cannot do a find/replace directly on a FORFILES variable. I would use FINDSTR with a regular expression to determine if the folder path includes IMG. You can redirect the output to NUL and conditionally execute commands only when found by using &&.

Other issues:

  • You only need @PATH in your DEL and log statements - it contains the full path, including file name.
  • The DEL /Q option is not needed since there is no wildcard.
  • You should only echo the delete message if the DEL is successful. But DEL does not set the errorlevel or activate || if it fails, even though it prints an error message to stderr. You can redirect the DEL stderr to stdout and pipe to FINDSTR to determine if there was an error message, and use || and && to take appropriate action.

You are not clear if you want to delete the file if IMG is anywhere within the path, or only if it is in the parent folder.

The following deletes files if IMG appears anywhere in the folder path:

set loglocation=C:\Tools\PurgeOldFiles\log\DELETEOLD_XML_IMG.txt
set olderthan=30
set source=X:\Test
set extension=XML

forfiles /p "%source%" /s /m "*.%extension%" /d -%olderthan% /c "cmd /c echo @RELPATH|findstr /i IMG.*[\\] >nul &&(del @PATH 2>&1|findstr 0x22^0x22>nul&&echo unable to delete @PATH||echo deleted @PATH)"  >>"%loglocation%"

A bit more complex regex restricts deletes to only when IMG appears in the parent folder

set loglocation=C:\Tools\PurgeOldFiles\log\DELETEOLD_XML_IMG.txt
set olderthan=30
set source=X:\Test
set extension=XML

forfiles /p "%source%" /s /m "*.%extension%" /d -%olderthan% /c "cmd /c echo @RELPATH|findstr /i 0x22IMG[^\\]*[\\][^\\]*$0x22 >nul &&(del @PATH 2>&1|findstr 0x22^0x22>nul&&echo unable to delete @PATH||echo deleted @PATH)"  >>"%loglocation%"
dbenham
  • 127,446
  • 28
  • 251
  • 390
  • Thank you very much! The file should be deleted if IMG is anywhere in the path. Currently, it is not working out for me. I have four files in the directory: X:\2015\10\13\IMG Filenames are like 1234567890.xml. Although the path contains IMG, the files were not deleted. By the way, I have modified the forfiles line (otherwise only the forfiles help dialog was showing): `FORFILES -p%source% -s -m*.%extension% -d-%olderthan% -c"CMD /C echo @RELPATH|findstr /i IMG.*[\\] >nul &&(del @PATH 2>&1|findstr 0x22^0x22>nul&&echo unable to delete @PATH||echo deleted @PATH)" >>"%loglocation%"` – Malawirel Nov 09 '15 at 14:08
  • @Malawirel - It has not been 30 days, so the files should not be deleted. I don't understand the HELP issue. I tested my code. What version of Windows are you using? – dbenham Nov 09 '15 at 15:05
  • I am using Windows Server 2008 R2. I pasted some >30 day old XML files into the folder. To verify if the last modified date is the issue, I tested it with the following code: `FORFILES -p%source% -s -m*.%extension% -d-%olderthan% -c"CMD /C DEL @PATH\@FILE /q & echo @PATH\@FILE deleted." >> %loglocation%` With this code, the files were deleted (of course not paying attention if 'IMG' is in the path name). – Malawirel Nov 09 '15 at 15:28