Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to conditionally take action if FINDSTR fails to find a string

I have a batch file as follows;

CD C:\MyFolder findstr /c:"stringToCheck" fileToCheck.bat IF NOT XCOPY "C:\OtherFolder\fileToCheck.bat" "C:\MyFolder" /s /y 

I am getting an error ("C:\OtherFolder\fileToCheck.bat" was unexpected at this time.) when trying to execute this.

Please let me know what I am doing wrong.

like image 401
copenndthagen Avatar asked Dec 16 '11 07:12

copenndthagen


People also ask

Does Findstr set Errorlevel?

FINDSTR will set %ERRORLEVEL% as follows: 0 (False) a match is found in at least one line of at least one file. 1 (True) if a match is not found in any line of any file, (or if the file is not found at all). 2 Wrong syntax An invalid switch will only print an error message in error stream.

What is the difference between find and Findstr?

The find program supports UTF-16, which findstr doesn't; on the other hand, the findstr program supports regular expressions, which find does not. The reason why their feature sets are unrelated is that the two programs are unrelated. The find program came first.

Does Findstr support regex?

Search for a text string in a file (or multiple files) unlike the simple FIND command FINDSTR supports more complex regular expressions.

What does the Findstr command do?

The findstr (short for find string) command is used in MS-DOS to locate files containing a specific string of plain text.


2 Answers

I presume you want to copy C:\OtherFolder\fileToCheck.bat to C:\MyFolder if the existing file in C:\MyFolder is either missing entirely, or if it is missing "stringToCheck".

FINDSTR sets ERRORLEVEL to 0 if the string is found, to 1 if it is not. It also sets errorlevel to 1 if the file is missing. It also prints out each line that matches. Since you are trying to use it as a condition, I presume you don't need or want to see any of the output. The 1st thing I would suggest is to redirect both the normal and error output to nul using >nul 2>&1.

Solution 1 (mostly the same as previous answers)

You can use IF ERRORRLEVEL N to check if the errorlevel is >= N. Or you can use IF NOT ERRORLEVEL N to check if errorlevel is < N. In your case you want the former.

findstr /c:"stringToCheck" "c:\MyFolder\fileToCheck.bat" >nul 2>&1 if errorlevel 1 xcopy "C:\OtherFolder\fileToCheck.bat" "c:\MyFolder" 

Solution 2

You can test for a specific value of errorlevel by using %ERRORLEVEL%. You can probably check if the value is equal to 1, but it might be safer to check if the value is not equal to 0, since it is only set to 0 if the file exists and it contains the string.

findstr /c:"stringToCheck" "c:\MyFolder\fileToCheck.bat" >nul 2>&1 if not %errorlevel% == 0 xcopy "C:\OtherFolder\fileToCheck.bat" "c:\MyFolder" 

or

findstr /c:"stringToCheck" "c:\MyFolder\fileToCheck.bat" >nul 2>&1 if %errorlevel% neq 0 xcopy "C:\OtherFolder\fileToCheck.bat" "c:\MyFolder" 

Solution 3

There is a very compact syntax to conditionally execute a command based on the success or failure of the previous command: cmd1 && cmd2 || cmd3 which means execute cmd2 if cmd1 was successful (errorlevel=0), else execute cmd3 if cmd1 failed (errorlevel<>0). You can use && alone, or || alone. All the commands need to be on the same line. If you need to conditionally execute multiple commands you can use multiple lines by adding parentheses

cmd1 && (    cmd2    cmd3 ) || (    cmd4    cmd5 ) 

So for your case, all you need is

findstr /c:"stringToCheck" "c:\MyFolder\fileToCheck.bat" >nul 2>&1 || xcopy "C:\OtherFolder\fileToCheck.bat" "c:\MyFolder" 

But beware - the || will respond to the return code of the last command executed. In my earlier pseudo code the || will obviously fire if cmd1 fails, but it will also fire if cmd1 succeeds but then cmd3 fails.

So if your success block ends with a command that may fail, then you should append a harmless command that is guaranteed to succeed. I like to use (CALL ), which is harmless, and always succeeds. It also is handy that it sets the ERRORLEVEL to 0. There is a corollary (CALL) that always fails and sets ERRORLEVEL to 1.

like image 117
dbenham Avatar answered Oct 17 '22 02:10

dbenham


You are not evaluating a condition for the IF. I am guessing you want to not copy if you find stringToCheck in fileToCheck. You need to do something like (code untested but you get the idea):

CD C:\MyFolder findstr /c:"stringToCheck" fileToCheck.bat IF NOT ERRORLEVEL 0 XCOPY "C:\OtherFolder\fileToCheck.bat" "C:\MyFolder" /s /y 

EDIT by dbenham
The above test is WRONG, it always evaluates to FALSE.
The correct test is IF ERRORLEVEL 1 XCOPY ...

Update: I can't test the code, but I am not sure what return value findstr actually returns if it doesn't find anything. You might have to do something like:

CD C:\MyFolder findstr /c:"stringToCheck" fileToCheck.bat > tempfindoutput.txt set /p FINDOUTPUT= < tempfindoutput.txt IF "%FINDOUTPUT%"=="" XCOPY "C:\OtherFolder\fileToCheck.bat" "C:\MyFolder" /s /y del tempfindoutput.txt 
like image 25
Luke Kim Avatar answered Oct 17 '22 02:10

Luke Kim