Page 1 of 2

what rem and if (and may be for) have against pipes?

Posted: 20 Apr 2014 09:46
by npocmaka_
I already know that for rem and if have some weird parsers and looks they have problems with pipes. Well ..for has no just is incapable to parse commands that end with pipe. But rem and if are weird:

@echo off
rem set errorlevel to o
color
echo ----------------
echo -- if tests --
echo ---------------

echo --if "a" equ "b"
echo pipe|if "a" equ "b" more

echo --if "a" equ "b"
echo pipe|if "a" equ "a" more

echo --if errorlevel 0
echo pipe|if errorlevel 0 more

echo --if errorlevel #
echo pipe|if errorlevel # more

echo --if errorlevel 0 break
echo pipe|if errorlevel 0 rem

echo --if exist c:\
echo pipe|if exist c:\ more


echo ----------------
echo -- rem tests --
echo ---------------

echo -- rem
echo pipe| rem


rem these two exist the script
rem echo -- (rem)
rem echo pipe| (call rem)& more



rem echo --call rem & more
rem echo pipe| call rem & more



echo -----------------
echo -- for tests ---
echo -----------------

echo --for /l
echo pipe|for /l %%t in (1,1,2) do more


echo --"for /f %%t in ('echo nopipe') do more"
echo pipe|for /f %%t in ('echo nopipe') do more



echo --"for /f %%t in ('more') do echo %%t"
echo pipe|for /f %%t in ('more') do echo %%t

echo --"for /f %%t in ('more^|') do more"
echo pipe|for /f %%t in ('more^|') do (echo %%t)


0. FOR is disappointing well behaving

1. REM breaks the script I have nothing to do with this

2.Take a look at IF errors (hint - with no pipe these errors should be printed only in case of comprison with wrong syntax)

Well I suppose the tiny hint above is not enough. IF is a little bit different when it comes to comparisons and other operations.So:

2.1 When something is piped to IF ERRORLEVEL / IF EXIST / IF CMDEXTVERSION / IF DEFINED the
(here starts the second list with slash delimited words) ERRORLEVEL/EXIST/CMDEXTVERSION/DEFINED are ignored and IF is forced to do a non working comparison with preserved pipe (and == comparison does not work )


Code: Select all

echo --if errorlevel "b" neq "b" more
echo pipe| if errorlevel "b" neq "b" more

echo --if errorlevel "b" neq "b" more
echo pipe| if errorlevel "b" neq "b" more



2.2 When something is piped to IF "a" equ/neq/.. "a" the IF wants two comparison commands and none of both works (and == is working )

Code: Select all

@echo off

echo --if errorlevel "b" neq "b" more
echo pipe| if errorlevel "b" neq "b" more

echo --if errorlevel "b" neq "b" more
echo pipe| if errorlevel "b" neq "b" more

echo --if  "z" equ equ "b" more
echo pipe|if  "z" equ equ "b" more

echo --if  "z" equ neq "b" more
echo pipe|if  "z" equ neq "b" more

echo --if  "z"=="b" more
echo pipe|if "z"=="b" echo pipe

echo --if  "b"=="b" more
echo pipe|if "b"=="b" echo pipe2

echo --if  "b"=="b" more
echo pipe|if "b"=="b" more



I'm scandalized !!! And excited :-D (btw. Could anybody else confirm this? Currently I'm testing on 32b XP Home/Laptop and for a while I'll have no access to my powerful Win 8.1 x64 - what are the results with you? )

Is this known behavior?

Of course I'm going to make more tests about comparisons , but wanted to share this so much :-)

Re: what rem and if (and may be for) have against pipes?

Posted: 20 Apr 2014 12:11
by npocmaka_
still on this..

if there's a composition of if and the first has something piped in the second works ok and preserves the pipe:

echo pipe |if 1 lss gtr 1 if 1 equ 1 more

Re: what rem and if (and may be for) have against pipes?

Posted: 20 Apr 2014 14:08
by penpen
Very interesting, i never had tried to get "if" to work when piped.
On syntax error, i always thought: "another thing not working with if... :cry: ".

But the the first two rem examples are working as expected, and none of them breaks the script:
First example:

Code: Select all

@echo off
echo -- rem
echo pipe| rem

Result (german version):

Code: Select all

Z:\>test.bat
-- rem
Ein Prozess hat versucht, zu einer nicht bestehenden Pipe zu schreiben.

Z:\>
(The process tried to write to a non-existent pipe.)
This result is ok, because the "echo pipe" command needs more time than the "rem" command.
After the "rem" finished, the pipe is closed.
Then the string "pipe" should be transferred through the (now closed) pipe => error.

Second example:

Code: Select all

@echo off
rem these two exist the script
echo -- (rem)
echo pipe| (call rem)& more
echo still working
This doesn't exit the script: The only way to exit the more is to use "ctrl + c".
This is because "echo pipe| (call rem)& more" is the same as
"(echo pipe| (call rem))& more" and not (as you seem to expect)
"echo pipe| ((call rem)& more)".
The more expects a "ctrl + c" to terminate.
It doesn't consume this signal, so "ctrl + c" is passed to the "actual batch" process, too. => the question to "abort the batch processing" (is this the correct translation?) pops up.
So you just have to choose "no" and the script resumes:

Code: Select all

Z:\>test.bat
-- (rem)
^CBatchvorgang abbrechen (J/N)? n
still working

Z:\>


I don't know if the third example is working correctly:

Code: Select all

echo --call rem & more
echo pipe| call rem & more
echo still working
Again "echo pipe| call rem & more" is the same as
"(echo pipe| call rem) & more" and not
"echo pipe| (call rem & more)".
I cannot explain the first "ctrl + c" cause; if i had to guess:
Somehow call executes the "more" command, but i have no idea, why... .
Then after the pipe block is fully performed the "more" command is executed:
All further is analoguous to the second example.
So you have to use "ctrl + c" and choosing "no" (both) two times:

Code: Select all

Z:\>test.bat
--call rem
^CBatchvorgang abbrechen (J/N)? n
^CBatchvorgang abbrechen (J/N)? n
still working

Z:\>

penpen

Edit: Removed some flaws.

Re: what rem and if (and may be for) have against pipes?

Posted: 20 Apr 2014 15:24
by npocmaka_
penpen wrote:
I don't know if the third example is working correctly:

Code: Select all

echo --call rem & more
echo pipe| call rem & more
echo still working
Again "echo pipe| call rem & more" is the same as
"(echo pipe| call rem) & more" and not
"echo pipe| (call rem & more)".
I cannot explain the first "ctrl + c" cause; if i had to guess:
Somehow call executes the "more" command, but i have no idea, why... .
Then after the pipe block is fully performed the "more" command is executed:
All further is analoguous to the second example.
So you have to use "ctrl + c" and choosing "no" (both) two times:

Code: Select all

Z:\>test.bat
--call rem
^CBatchvorgang abbrechen (J/N)? n
^CBatchvorgang abbrechen (J/N)? n
still working

Z:\>

penpen

Edit: Removed some flaws.


Interesting.To be honest I didn't pay much attention on rem tests.

Again "echo pipe| call rem & more" is the same as
"(echo pipe| call rem) & more" and not
"echo pipe| (call rem & more)".


Are sure about that. I always thought that the pipe creates a different process on the other side and has a higher priority than &.


And for the IF.

Here is a test script that I ran to check all the cases:


Code: Select all

@echo off


goto :end_legend

 EQU - equal
 NEQ - not equal
 LSS - less than
 LEQ - less than or equal
 GTR - greater than
 GEQ - greater than or equal

:end_legend

break > permutations.bat
break > permutations.txt
break > permutations2.txt

for %%z in (EQU NEQ LSS LEQ GTR GEQ) do (
   (echo(1 %%z 1)
   (echo(1 %%z 2)
   (echo(2 %%z 1)   
) >>permutations2.txt

for /f "tokens=* delims=" %%P in (permutations2.txt) do (
   echo set "temp="
   echo echo %%P
   echo for /f %%%%a in ^('break^^^|if defined %%P echo #'^) do set "temp=%%%%a"
   echo if defined temp ^( echo Y ^) else echo N
   echo echo -----
   echo/
) >> permutations.bat




for %%a in (EQU NEQ LSS LEQ GTR GEQ) do (
   for %%z in (EQU NEQ LSS LEQ GTR GEQ) do (
      (echo(1  %%a %%z 1)
      (echo(1  %%a %%z 2)
      (echo(2  %%a %%z 1)   
   )
) >> permutations.txt   


for /f "tokens=* delims=" %%P in (permutations.txt) do (
   echo set "temp="
   echo echo %%P
   echo for /f %%%%a in ^('break^^^|if %%P echo #'^) do set "temp=%%%%a"
   echo if defined temp ^( echo Y ^) else echo N
   echo echo -----
   echo/
) >> permutations.bat

call permutations.bat


and here is the result:

http://pastebin.com/raw.php?i=gkZZ3DN0
http://pastebin.com/raw.php?i=7MULa2Fs

At the moment I cant see any logic in this.Will try also with different numbers. I've hoped that this some kind of XOR ...

Also should refine the script as it is producing more results that I need :) (too much repeats.)

EDIT- New script and report.

Re: what rem and if (and may be for) have against pipes?

Posted: 20 Apr 2014 15:49
by penpen
The funniest about what you've found out:

Code: Select all

@echo
set "value1=0"
set "value2=0"
set "operator1=lss"
set "operator2=lss"

echo not %value1% %operator1% %operator2% %value2% | if not %value1% %operator1% %operator2% %value2% more
echo %value1% %operator1% %operator2% %value2% | if %value1% %operator1% %operator2% %value2% more
It seems the following is true for all cases:
- value1 and value2 two must be defined, and
- operator1 has to be in {lss, leq, equ, geq, gtr, neq} but doesn't change the result (ignored), and
- not reverses the execution of the ("more") command.


Now there are two cases; case 1:
- if value1 ">=" value2 then the ("more") command is executed if operator2 is in {geq, gtr, neq}
- if value1 "<" value2 then the ("more") command is executed if operator2 is in {neq, lss, leq}

penpen

Edit: Added red note (sorry actually to late).
Edit2: Removed the wrong information and the red note.
Edit3: Corrected a copy paste error.

Re: what rem and if (and may be for) have against pipes?

Posted: 20 Apr 2014 16:14
by penpen
npocmaka_ wrote:
Again "echo pipe| call rem & more" is the same as
"(echo pipe| call rem) & more" and not
"echo pipe| (call rem & more)".


Are sure about that. I always thought that the pipe creates a different process on the other side and has a higher priority than &.
Yes, i'm sure.
You may just try it out.
But here is an example where you can see that "&" has the higher priority in parsing:

Code: Select all

@echo off
: left side example
(echo 1 & echo 2 & echo 3) | pause
echo 1 & (echo 2 & echo 3) | pause
echo 1 &  echo 2 & echo 3  | pause

echo =======
: right side example
echo 123 | (pause & pause & more)
echo -------
echo 123 | (pause & pause)
echo -------
echo 123 | pause & pause
Result (german version win xp home 32 bit):

Code: Select all

Z:\>test
Drücken Sie eine beliebige Taste . . .
1
Drücken Sie eine beliebige Taste . . .
1
2
Drücken Sie eine beliebige Taste . . .
=======
Drücken Sie eine beliebige Taste . . .
Drücken Sie eine beliebige Taste . . .
3

-------
Drücken Sie eine beliebige Taste . . .
Drücken Sie eine beliebige Taste . . .
-------
Drücken Sie eine beliebige Taste . . .
Drücken Sie eine beliebige Taste . . .

Z:\>
(The last pause is the only that requires an input from keyboard.)

penpen

Re: what rem and if (and may be for) have against pipes?

Posted: 21 Apr 2014 01:15
by npocmaka_
1. redirection from files has no strange effects:

Code: Select all

(call rem & more) <test
(if 1 equ  1 more) <test


2.'Logic' of echo.|if defined/exist/.. is clear (set Y and X to whatever you want)

Code: Select all

ALWAYS TRUE
echo pipe|if defined X neq Y more
echo pipe|if defined X geq Y more
echo pipe|if defined X gtr Y more

ALWAYS FALSE
echo pipe|if defined X equ Y more
echo pipe|if defined X lss Y more
echo pipe|if defined X leq Y more


/I switch has no effect . NOT switch reverses the 'logic'.
Still investigating the more complicated case with the two operators...But seems there the first operator is always ignored.

Re: what rem and if (and may be for) have against pipes?

Posted: 21 Apr 2014 03:22
by penpen
I've changed my post above, and now it shows the "two operator logic".
In short (using this if-statement syntax: if condition statement):
- case 1: If the first value is greater or equal than the second value, then the second operator has to be in {geq, gtr, neq} to execute the statement.
-case 2: If the first value is lesser than the second value, then the second operator has to be in {neq, lss, leq} to execute the statement.

penpen

Edit: Corrected case 2 operand set.

Re: what rem and if (and may be for) have against pipes?

Posted: 21 Apr 2014 12:54
by npocmaka_
Yes.Confirms my observation that the first operator is ignored.With one addition.
In all cases it makes alphabetical comparison and cannot be driven to make number comparison:

Code: Select all

echo pipe|if  1234 equ gtr 124 more

Re: what rem and if (and may be for) have against pipes?

Posted: 22 Apr 2014 03:37
by npocmaka_
And one more addition :D

In two operators case comparison is alphabetical and ignores the case.The /I does cause an error but has no effect.

In two operators case the NOT reverses the logic.

In all cases (two and one operators) else works with preserved pipes:

Code: Select all

echo pipe|if  a equ gtr A more
echo pipe|if  not a equ gtr A (echo no pipe) else (more)
echo pipe|if defined X equ Y (echo no pipe) else (more)

Re: what rem and if (and may be for) have against pipes?

Posted: 22 Apr 2014 08:40
by penpen
npocmaka_ wrote:2.'Logic' of echo.|if defined/exist/.. is clear (set Y and X to whatever you want)

Code: Select all

ALWAYS TRUE
echo pipe|if defined X neq Y more
echo pipe|if defined X geq Y more
echo pipe|if defined X gtr Y more

ALWAYS FALSE
echo pipe|if defined X equ Y more
echo pipe|if defined X lss Y more
echo pipe|if defined X leq Y more

I've played around some time and got this:

Code: Select all

(...)

C:\>echo pipe|if not defined geq==equ,gtr more
pipe

Z:\>echo pipe|if defined {cmdExtVersion,lss,errorLevel} more
pipe

Z:\>echo pipe|if defined gtr gtr gtr more

Z:\>
Maybe an instable bug?

penpen

Re: what rem and if (and may be for) have against pipes?

Posted: 22 Apr 2014 12:58
by npocmaka_
penpen wrote:I've played around some time and got this:

Code: Select all

(...)

C:\>echo pipe|if not defined geq==equ,gtr more
pipe

Z:\>echo pipe|if defined {cmdExtVersion,lss,errorLevel} more
pipe

Z:\>echo pipe|if defined gtr gtr gtr more

Z:\>
Maybe an instable bug?

penpen



I think all of these are in the case with one operator case as , and =
are standard delimiters (even for IF command in some cases - check this if=a==a =echo what? of if not==,,a,,equ,,5 echo what?) .And the examples are the same as:

Code: Select all

(...)

C:\>echo pipe|if not defined "geq" equ "gtr" more
pipe

Z:\>echo pipe|if defined "{cmdExtVersion" lss "errorLevel}" more
pipe

Z:\>echo pipe|if defined "gtr" gtr "gtr" more

Z:\>


But I'm not completely sure about the first example...The equal sign could be misleading here.

Re: what rem and if (and may be for) have against pipes?

Posted: 22 Apr 2014 13:02
by npocmaka_
But this shows that my assumption for one-operator-case was not true :

Code: Select all

echo pipe|if defined neq gtr gtr more



:|

Deeper investigation is needed here....

Re: what rem and if (and may be for) have against pipes?

Posted: 22 Apr 2014 16:55
by jeb
Hi,

sorry I'm a little bit late for this discussion :)

But I only want to show the simple cause for the strange behaviour.

Code: Select all

C:\>echo pipe | if defined X lss Y echo %^cmdcmdline%

Output wrote:C:\Windows\system32\cmd.exe /S /D /c" if definedX lss Y echo %cmdcmdline% "

As you can see the two tokens just behind the IF are simply combined into one :idea:

Sometimes it can help when you see how the parser restructure the line... :D

jeb

Re: what rem and if (and may be for) have against pipes?

Posted: 22 Apr 2014 17:09
by penpen
AH :idea:

Then this is the cause, why the two operator case cannot be driven to make number comparisons:

Code: Select all

C:\>echo pipe|if 0 gtr gtr 0 echo %^cmdcmdline%
C:\WINDOWS\system32\cmd.exe /S /D /c" if 0GTR gtr 0 echo %cmdcmdline%"


And the following is a working two operator case equ on second operator part:

Code: Select all

C:\>echo pipe|if 0 gtr equ 0GTR echo %^cmdcmdline%
C:\WINDOWS\system32\cmd.exe /S /D /c" if 0GTR equ 0GTR echo %cmdcmdline%"
Very impressive (the echo %^cmdcmdline% trick).

penpen

Edit: Would have taken thousands of years detecting this, by simply "try and error"... .