21

I'm working with a batch file to delete archived documents older than 14 days, and I'm calling the file from an automation process (Lansa Composer) that reads the return code of the script to see if there was a problem. Here's the script:

@echo off
@Echo Deleting files older than 14 days...
cd /d C:\Windows\System32
FORFILES /P "[file path...]\IDOC_ARCHIVE" /M *.* /D -14 /C "cmd /c del @file"

The issue is that the script returns an error code and prints "ERROR: No files found with the specified search criteria" if it doesn't find any files to delete, when I really only want it to return an error if there is a problem accessing the directory or running the del command, etc. Is there some way I can get this script to suppress the "no files found" error, but allow others to pass through?

After some Googling I tried the solutions on this page, but they won't work for what I want, since in the first case it suppresses ALL errors, and in the second the text of the error message is passed, but the actual return code is still suppressed (which is what the automation process reads).

Konrad Morawski
  • 8,307
  • 7
  • 53
  • 91
Malcolm
  • 510
  • 3
  • 5
  • 19
  • 1
    I don't know what you need. Suppressing the error message with `2>nul` does not delete the `℅errorlevel%` . – Endoro May 29 '13 at 18:06
  • @Endoro But it's indiscriminate as to what KIND of error it was. I need a solution that will suppress only the "no matching files found" error, and not other types of errors. I don't actually care about the error message at all (STDERR or STDOUT), except for the fact that it seems to be the only way to distinguish the different types. – Malcolm May 29 '13 at 18:31
  • So catch the error message in a for loop and store it in a variable for further analyses. – Endoro May 29 '13 at 18:46
  • 2
    try `FORFILES /P "[file path...]\IDOC_ARCHIVE" /M *.* /D -14 /C "cmd /c del @file" | find /V "No files found"` that should exclude that error message, but probably will not affect the `errorlevel` – Patrick Meinecke May 29 '13 at 22:03

8 Answers8

15

This should solve that issue:

@echo off
Echo Deleting files older than 14 days...
cd /d C:\Windows\System32
copy /b forfiles.exe "[file path...]\IDOC_ARCHIVE" >nul
FORFILES /P "[file path...]\IDOC_ARCHIVE" /M *.* /D -14 /C "cmd /c del @file"

What it does is provide a file older than 14 days - so it will always be deleted and the 'no files found' message won't appear. I chose the forfiles.exe to copy but you can use any file older than 14 days. All other error messages will appear as normal.

VLL
  • 9,634
  • 1
  • 29
  • 54
foxidrive
  • 40,353
  • 10
  • 53
  • 68
  • I'm not sure I understand what this is doing. Won't this suppress all errors? – Malcolm May 30 '13 at 20:40
  • What it does is provide a file older than 14 days - so it will always be deleted and the 'no files found' message won't appear. I chose the forfiles.exe to copy but you can use any file older than 14 days. All other error messages will appear as normal. – foxidrive May 31 '13 at 01:03
  • 1
    very good solution, since it is independent of the OS language – Thomas Franz Nov 03 '16 at 10:36
11

Adding 2>nul did the trick. Thanks!

forfiles /p d:\todayfiles /d +0 /c "cmd /c echo @path" 2>nul | find ":" /c

This basically suppresses the Error Stream of this command. So even if other errors appeared while doing this operation, they won't appear!

Hazem Elraffiee
  • 453
  • 7
  • 16
Andrey Lopatin
  • 111
  • 1
  • 2
  • That's brilliant! I just want to add that this basically suppresses the Error Stream of this command. So even if other errors appeared while doing this operation, they won't appear! – Hazem Elraffiee Jul 18 '19 at 08:23
7

To reliably affect the ERRORLEVEL you need to run a subsequent command which is guaranteed to set ERRORLEVEL to 0. I use the command interpreter itself (cmd.exe) to do this as in the following snippet:

FORFILES  /M:somefiles /D -14 2>nul | cmd /c ""

Hope this helps someone.

Nigel
  • 1,291
  • 11
  • 7
6

The solution is to capture the output of the FORFILES command in a FOR loop, search it for strings starting with ERROR, and store the result in a variable. From there, you can use IF/ELSE directives to set the errorlevel accordingly. Here's the code (minus some logging and comments):

cd /d C:\Windows\System32
SET _CmdResult=NONE
FOR /F "tokens=*" %%a IN ('FORFILES /P "[file path...]\IDOC_ARCHIVE" /M *.* /D -14 /C "cmd /c DEL @file" 2^>^&1 ^| FINDSTR ERROR') DO SET _CmdResult=%%a
IF "%_CmdResult%" == "ERROR: No files found with the specified search criteria." ( 
    SET errorlevel=0 
 ) ELSE ( 
    SET errorlevel=1
 )
IF "%_CmdResult%" == "NONE" SET errorlevel=0

Just make sure to escape any characters such as >&| in the FOR loop.

Malcolm
  • 510
  • 3
  • 5
  • 19
4

This is easily solvable with a one liner. Just append this to your forfiles command:

2>&1 | find /v /i "ERROR: No files found with the specified search criteria."

So you'd get:

FORFILES /P "[file path...]\IDOC_ARCHIVE" /M *.* /D -14 /C "cmd /c del @file" 2>&1 | find /v /i "ERROR: No files found with the specified search criteria."

Only the specified error message is not displayed. All other messages are.

Here's how this works:

  • 2>&1 is used to send STDERR to the same place where we send STDOUT.
  • | find /v /i pipes the output from forfiles to find where /v means NOT containing the specified string and /i means case-insensitive
Christiaan Westerbeek
  • 10,619
  • 13
  • 64
  • 89
  • Thank you, but this is incomplete. As I stated in the question, the part or the error that needs to go through or get blocked is the `errorlevel` return code, not the message text. I only care about the text inasmuch as it differentiates the error types. – Malcolm Jul 03 '14 at 21:49
4

Might I add a humble contribution to this already valuable thread. I'm finding that other solutions might get rid of the actual error text but are ignoring the %ERRORLEVEL% which signals a fail in my application. AND I legitimately want %ERRORLEVEL% just as long as it isn't the "No files found" error.

Some Examples:

Debugging and eliminating the error specifically:

forfiles /p "[file path...]\IDOC_ARCHIVE" /s /m *.txt /d -1 /c "cmd /c del @path" 2>&1 |  findstr /V /O /C:"ERROR: No files found with the specified search criteria."2>&1 | findstr ERROR&&ECHO found error||echo found success

Using a oneliner to return ERRORLEVEL success or failure:

forfiles /p "[file path...]\IDOC_ARCHIVE" /s /m *.txt /d -1 /c "cmd /c del @path" 2>&1 |  findstr /V /O /C:"ERROR: No files found with the specified search criteria."2>&1 | findstr ERROR&&EXIT /B 1||EXIT /B 0

Using a oneliner to keep the ERRORLEVEL at zero for success within the context of a batchfile in the midst of other code (ver > nul resets the ERRORLEVEL):

forfiles /p "[file path...]\IDOC_ARCHIVE" /s /m *.txt /d -1 /c "cmd /c del @path" 2>&1 |  findstr /V /O /C:"ERROR: No files found with the specified search criteria."2>&1 | findstr ERROR&&ECHO found error||ver > nul

For a SQL Server Agent CmdExec job step I landed on the following. I don't know if it's a bug, but the CmdExec within the step only recognizes the first line of code:

cmd /e:on /c "forfiles /p "C:\SQLADMIN\MAINTREPORTS\SQL2" /s /m *.txt /d -1 /c "cmd /c del @path" 2>&1 |  findstr /V /O /C:"ERROR: No files found with the specified search criteria."2>&1 | findstr ERROR&&EXIT 1||EXIT 0"&exit %errorlevel%
Sting
  • 333
  • 2
  • 11
  • For SQL Server Agent CmdExec job, I changed the "On failure action" to "Quit the job reporting success," since it was the last step of the job and I did not want the failure to be reported. – llessurt Sep 06 '19 at 16:14
1

Try to add after the script

2>Nul 

Example

SET Days=14

FORFILES /S /M *.* /D -%Days% /C "CMD /C DEL @file" 2>Nul

Hope that helps.

Siya Matsakarn
  • 427
  • 4
  • 8
0

I had the same problem when trying to delete duplicates in yearly backups on my ext harddisk. None of the solutions found searching the internet (adding @path, leaving out cmd /c in the command parameter) worked for me. System asking 'Are you sure...' brought the follwing solution to my mind: use the /q parameter. The result wipes the 2015 files in my 2016 dir:

forfiles /p G:\YearlyBU\Mine\16-12-29\IMeMine\Documents /s /c "cmd /c del @path @file /q"  /d -1100
Stephan
  • 53,940
  • 10
  • 58
  • 91
Martin
  • 1