Page 1 of 2

IF condition is completly ignored, but why?

Posted: 06 Jun 2011 09:02
by NoNameFound
Hi there :-)

I've been trying to write a small programm that checks if one or more services are running and if so, terminates these services. Apart from trying it on my own, I also looked up some examples in google and finally came up with the following mixture of own code and found code:

Code: Select all

setlocal
@echo off 
cls

rem ====================================================================== 
:: 
::  Service Searcher And Terminator 
:: 
rem ---------------------------------------------------------------------- 
::  2011-06-06  v1.0  NoNameFound 
rem ======================================================================

rem ---------------------------------------------------------------------- 
::  CONFIG 
rem ---------------------------------------------------------------------- 
   set lServices= 
   set lServices=%lServices% "Spooler"
    
   set tmpfile=%temp%\services_.tmp
     
     
rem ---------------------------------------------------------------------- 
:: MAIN 
rem ---------------------------------------------------------------------- 
   color 08 
   echo. 
   echo ===== SERVICE SEARCH AND DESTROY ===== 
   echo. 
   call :getStatus 
   echo Stopped - %Stopped% ..  Running - %Running% 
        if "%Stopped%" == "N" call :stopServices
   echo. 
   color cf 
   echo. 
   echo --- INFO --- 
   echo Service is not running. 
   echo. 
   goto end 

rem ---------------------------------------------------------------------- 
::  SUBS 
rem ---------------------------------------------------------------------- 
   :getStatus 
   set Stopped=N 
   set Running=N 
   echo.
   echo Reading service state ... 
   net start >"%tmpfile%" 
   for %%a in (%lServices%) do call :checkService %%a 
   del "%tmpfile%" 
   echo. 
   goto end2   

   :checkService 
   echo.
   findstr /c:%1 "%tmpfile%" >nul && ( echo YES: %1 is running && set Running=Y && goto end2) 
   echo NO: %1 is stopped && set Stopped=Y 
   goto end2

   :stopServices 
   color 17 
   echo --- Stopping service --- 
   pause 
   for %%a in (%lServices%) do ( 
      echo ... stopping %%a ...
      echo.
      net stop %%a 
   ) 
   call :getStatus 
   goto end 


rem ---------------------------------------------------------------------- 
::  END 
rem ---------------------------------------------------------------------- 

   :end   
   echo --- done ---
   endlocal
   pause 

   :end2 

rem ---------------------------------------------------------------------- 
::  EOF 
rem ---------------------------------------------------------------------- 


The first if condition under :Main "if "%Stopped%" == "N" call :stopServices" is completly ignored, although the variable is infact set to "N".

Can someone shed some light on why this is the case?

Cheers and thanks,

Fred

Re: IF condition is completly ignored, but why?

Posted: 06 Jun 2011 10:08
by Ed Dyreen

Right right, so you want to do something like this right ?

Code: Select all

@echo off &setLocal EnableDelayedExpansion

set "AntiVirus.STATE=Disabled"
::
for /f "skip=1 tokens=*" %%! in (

   'net start'

) do (
   set "STATE=%%~!"
   ::
   set "STATE=!STATE:~0,8!"
   ::
   for %%! in (

      "Symantec"

   ) do    if /i ["!STATE!"] == ["%%~!"] (
      ::
      set "AntiVirus.STATE=Enabled"
   )
)

if /i ["!AntiVirus.NAME!"] == ["Norton Internet Security"] if /i ["!AntiVirus.STATE!"] neq ["Disabled"] (
   ::
   echo.
   for %%! in (

      "Symantec AppCore Service"
      "Symantec Core LC"
      "Symantec Event Manager"
      "Symantec Lic NetConnect service"
      "Symantec Settings Manager"
      "System Event Notification"

   ) do    net start |>nul findstr.EXE /i /c:"%%~!" &&(
      ::
      echo. Sending '%%~!' the KILL signal...
      ::
      net stop "%%~!" /y ||(
         ::
         set /a ERR = !ErrorLevel!

         set /p "?= [ERROR:!ERR!]" <nul &echo.
      )
   )
)
pause
exit /b

That is a nogo ! Change this first :
"if "%Stopped%" == "N"

if /i ["%Stopped%"] == ["N"]

Change this too:
set lServices=%lServices% "Spooler"
set tmpfile=%temp%\services_.tmp

set "lServices=%lServices% "Spooler""
set "tmpfile=%temp%\services_.tmp"

Try to always use set like this: set "var=something"
and if like: if /i ["some"] == ["some"]

A a aaa! NO goto like that
goto end

goto :end

You've got a lot to learn my friend, that's ok, we'll teach you :wink:

Re: IF condition is completly ignored, but why?

Posted: 06 Jun 2011 10:16
by dbenham
NoNameFound wrote:The first if condition under :Main "if "%Stopped%" == "N" call :stopServices" is completly ignored, although the variable is infact set to "N".
No it isn't. You have spaces after the N in your assignmet :!:

You can avoid this problem by using quotes around the entire assignment like so:
set "Running=N"

Extra spaces after the closing quote will be ignored.

Dave Benham

Re: IF condition is completly ignored, but why?

Posted: 06 Jun 2011 10:17
by Ed Dyreen
'
Take this through will you ? You'll then be able to solve this problem with your eyes closed.
MS-DOS/MSDOS Batch Files: Batch File Tutorial and Reference :arrow:
http://www.allenware.com/icsw/icswidx.htm

Re: IF condition is completly ignored, but why?

Posted: 06 Jun 2011 12:59
by orange_batch
Jeez Ed :?

You know, the brackets [ ] in these situations are useless:

if /i ["some"]==["some"]

The brackets themselves are just a character choice, it could be any other character. They don't even need to be on both sides of each condition. As for the technique, it's only useful for optional argument checking where quotations are optional so as to prevent either a blank argument error or undoing the quotation deactivation of command characters within the argument.

Re: IF condition is completly ignored, but why?

Posted: 07 Jun 2011 01:25
by NoNameFound
Hey guys,

thanks for the really quick answers! I'm impressed :-) I'll read the linked infos right away - thanks for that aswell :-)

I'll change my script and post the results then - in any case thank you very much :-)

Cheers,

Fred

EDIT:

*YaY* it worked! The tip with the empty spaces did the trick, although I also used all other tips to clean up the script. The result is this:

Code: Select all


setlocal
@echo off 
cls

rem ====================================================================== 
:: 
::  Service Searcher And Terminator 
:: 
rem ---------------------------------------------------------------------- 
::  2011-06-06  v1.1  NoNameFound 
rem ======================================================================

rem ---------------------------------------------------------------------- 
::  CONFIG 
rem ---------------------------------------------------------------------- 
   set "lServices=" 
   set "lServices=%lServices% "Druckwarteschlange""
    
   set "tmpfile=%temp%\services_.tmp" 

   set "MaxCount=5"
   set "Count=0"
     
     
rem ---------------------------------------------------------------------- 
:: MAIN 
rem ---------------------------------------------------------------------- 
   color 08 
   echo. 
   echo ===== SERVICE SEARCH AND DESTROY ===== 
   echo. 
   call :getStatus 
   echo Stopped - %Stopped% ..  Running - %Running% 
      if /i ["%Stopped%"]==["N"] call :stopServices
   echo. 
   color cf 
   echo. 
   echo --- INFO --- 
   echo Service is not running. 
   echo. 
   goto :end 

rem ---------------------------------------------------------------------- 
::  SUBS 
rem ---------------------------------------------------------------------- 
   :getStatus 
   set "Stopped=N" 
   set "Running=N" 
   echo.
   echo Reading service state ... 
   net start >"%tmpfile%" 
   for %%a in (%lServices%) do call :checkService %%a 
   del "%tmpfile%" 
   echo. 
   goto :end2   

   :checkService 
   echo.
   findstr /c:%1 "%tmpfile%" >nul && ( echo YES: %1 is running && set "Running=Y" && goto :end2) 
   echo NO: %1 is stopped && set "Stopped=Y" 
   goto :end2

   :stopServices 
   color 17 
   echo --- Stopping service --- 
   pause 
   for %%a in (%lServices%) do ( 
      echo ... stopping %%a ...
      echo.
      net stop %%a 
   ) 
   call :getStatus 
   goto :end 


rem ---------------------------------------------------------------------- 
::  END 
rem ---------------------------------------------------------------------- 

   :end   
   echo --- done ---
   endlocal
   pause 

   :end2 

rem ---------------------------------------------------------------------- 
::  EOF 
rem ---------------------------------------------------------------------- 



Next step: add logging to the script, but that's easy :-)

Re: IF condition is completly ignored, but why?

Posted: 07 Jun 2011 04:29
by Ed Dyreen

Ok, I can't explain this. Maybe Jeb can explain it.
You know, the brackets [ ] in these situations are useless:

But I have seen this fail
if "" == ""
I've not seen this fail yet
if [""] == [""]

And I don't even know if it's WinXP that needs if [""] == [""] :|

Re: IF condition is completly ignored, but why?

Posted: 07 Jun 2011 06:03
by dbenham
EdDyreen wrote:But I have seen this fail
if "" == ""
I've not seen this fail yet
if [""] == [""]
I think you may have fooled yourself. If 1st method fails, then 2nd will fail as well. IF statements typically fail because of unquoted, un-escaped special characters, or because of undefined variables. Simple logic should tell us what works and what doesn't.

This fails because quoted & in variable becomes unquoted in IF:

Code: Select all

set str="A&B"
if "%str%"=="" (echo empty) else echo not empty
As does this:

Code: Select all

set str="A&B"
if ["%str%"]==[""] (echo empty) else echo not empty


This succeeds because quoted & in variable remains quoted in IF:

Code: Select all

set str="A&B"
if [%str%]==[] (echo empty) else echo not empty
But this fails because unquoted & in variable remains unquoted in IF:

Code: Select all

set "str=A&B"
if [%str%]==[] (echo empty) else echo not empty


This fails because quoted & in variable becomes unquoted in IF:

Code: Select all

set str="A&B"
if "%str%"=="" (echo empty) else echo not empty
But this succeeds because unquoted & in variable becomes quoted in IF:

Code: Select all

set "str=A&B"
if "%str%"=="" (echo empty) else echo not empty


When variable contains both quoted and unquoted special character - we really have problems. Note that in these examples the unquoted & is not escaped within the variable.
This fails at the 2nd &:

Code: Select all

set str=A^&"B&C"
if "%str%"=="" (echo empty) else echo not empty
This fails at the 1st &:

Code: Select all

set str=A^&"B&C"
if [%str%]==[] (echo empty) else echo not empty


The only way I know to guarantee an IF statement will work is to use delayed expansion (or else escape special characters as needed via a preprocess - too complicated)
These all succeed:

Code: Select all

setlocal enableDelayedExpansion
set str1="A&B"
set "str2=A&B"
set str3=A^&"B&C"
set "str4="
if "!str1!"=="" (echo empty) else echo not empty
if "!str2!"=="" (echo empty) else echo not empty
if "!str3!"=="" (echo empty) else echo not empty
if "!str4!"=="" (echo empty) else echo not empty
if [!str1!]==[] (echo empty) else echo not empty
if [!str2!]==[] (echo empty) else echo not empty
if [!str3!]==[] (echo empty) else echo not empty
if [!str4!]==[] (echo empty) else echo not empty
if x!str1!==x (echo empty) else echo not empty
if x!str2!==x (echo empty) else echo not empty
if x!str3!==x (echo empty) else echo not empty
if x!str4!==x (echo empty) else echo not empty


You need something added in case the string is empty. This fails:The statement in red is FALSE. The code below works as would be expected! Thanks jeb for pointing out the error of my ways.

Code: Select all

setlocal enableDelayedExpansion
set "str="
if !str!==test (echo match) else echo no match

In summary:
With delayed expansion DISABLED, quotes guard against empty string but fail with quoted special characters.
With delayed expansion DISABLED, non quotes guard against empty string but fail with unquoted special characters.
With delayed expansion ENABLED, empty strings and special characters are not a concern.

Note however that delayed expansion with substring or search and replace expression does not work if the variable is undefined. (for example !str:~1,3! and !str:a=b! both give undesired result if str is undefined).

Dave Benham

Re: IF condition is completly ignored, but why?

Posted: 07 Jun 2011 06:10
by Ed Dyreen
And I don't even know if it's WinXP that needs if [""] == [""] :|

@dbenham Did you also try this in WinME :?:

I need WinME's Command.COM for my NetBootDisk installation of XP.
http://www.netbootdisk.com/download.htm

Re: IF condition is completly ignored, but why?

Posted: 07 Jun 2011 08:05
by dbenham
Everything in my last post should remain true for command.com, up until the delayed expansion part. Command.com does not support command extensions so delayed expansion is not available.

Dave

Re: IF condition is completly ignored, but why?

Posted: 07 Jun 2011 08:41
by Ed Dyreen
Maybe you are right, dunno, but I still gona fool myself for awile then ey :twisted:

Re: IF condition is completly ignored, but why?

Posted: 07 Jun 2011 13:02
by jeb
dbenham wrote:You need something added in case the string is empty. This fails:
Code:
setlocal enableDelayedExpansion
set "str="
if !str!==test (echo match) else echo no match


I got you :!: you didn't test it.

It works as expected even with an empty string.

This is an effect of the IF parser, the parser split the line at then "==" and when the !str! is expanded it isn't longer important if it is empty.

But as the parser isn't very smart, it fails with something like

Code: Select all

if !str:the=it!==test_it  (echo match) else echo no match

jeb

Re: IF condition is completly ignored, but why?

Posted: 07 Jun 2011 13:37
by dbenham
jeb wrote:I got you :!: you didn't test it.

Yes you did :!: :oops:

I could have sworn I had tested that before, though obviously not that specific bit of code. This certainly demonstrates the danger of posting code based on memory, and without testing. My bad.

Are you aware of a situation where the delayed expansion of a variable needs quotes :?: I thought I had run accross this, but now I'm not so sure.

Dave

Re: IF condition is completly ignored, but why?

Posted: 07 Jun 2011 15:46
by jeb
dbenham wrote:Are you aware of a situation where the delayed expansion of a variable needs quotes :?: I thought I had run accross this, but now I'm not so sure.
No, I believe that there isn't any situation you need quotes for a delayed expansion.
But there are situations, where the delayed expansion fails, always.

Code: Select all

setlocal EnableDelayedExpansion
set "myDelims=ab"
for /F "tokens=1,2,3 delims=!myDelims!" %%x in ("**a**b**m**???") do echo x="%%x" y="%%y"

set "conditionA=1 EQU 1"
if !conditionA! (echo condition is true)

The delims are set to "!eDilms" not to "ab"
The condition fails completly.

Both failures seems to be an effect of the specialized parser of FOR and IF,
as both parsers splits the line into different parts, and some parts supports delayed expansion, but not all.

jeb

Re: IF condition is completly ignored, but why?

Posted: 07 Jun 2011 23:04
by dbenham
jeb wrote:Both failures seems to be an effect of the specialized parser of FOR and IF,
as both parsers splits the line into different parts, and some parts supports delayed expansion, but not all.
Yes, I ran into a variation of that recently. The following fails:

Code: Select all

setlocal enableDelayedExpansion
set option=/I
if !option! a==A echo OK


jeb wrote:No, I believe that there isn't any situation you need quotes for a delayed expansion.

I found a case that requires quotes :!: (vindication ? :lol: )

Code: Select all

setlocal enableDelayedExpansion
cmd /c exit 0

rem this succeeds
if "!=exitCode!"=="00000000" echo OK

rem this fails!
if !=exitCode!==00000000 echo OK
The problem exists for all of the = variables. The only way I have gotten any of them to work is with quotes. No other character(s) seem to work. Very odd :?

Dave Benham