4

I simplified the code. The following three are work.

for /L %a in (1,1,9) do @(if %a NEQ 0 (echo %a))

&

for /L %a in (1,1,9) do @(if not %a == 0 (echo %a))

&

(for /L %a in (1,1,9) do @(if not %a == 0 (echo %a)))|sort /R

But the next one didn't work,

(for /L %a in (1,1,9) do @(if %a NEQ 0 (echo %a)))|sort /R

What's the problem of NEQ in the piped block command?

more simplified,

This works, (if 3 == 3 echo yes)|sort

This doesn't work, (if 3 NEQ 2 echo yes)|sort

Part of my code.

@echo off
setlocal enabledelayedexpansion
set Unx_path=.....\bin\UnxUtils\
(
for /F %%a in ('^""%Unx_path%pclip.exe"^|"%Unx_path%sed.exe" -r "s/^^$/none/"^|"%Unx_path%sed.exe" -rf "script_file"^"') do @(
  if not "%%a" == "none" (
    "%Unx_path%grep.exe" -iEe "%%a" "file4search"|"%Unx_path%sed.exe" -r "s/^^[^,]+$/,&/";"s/^^([^.]+)[.][^.]+$/\1/"|"%Unx_path%gawk.exe" "BEGIN{FS=\",\";ORS=\" \"}{print $2}"|"%Unx_path%sed.exe" "s/%%a//I g";"s/.*/%%a &|/";"s/ -/ /g";"s/ |/\n/g";"s/ /\t/g";"s/~/\t/g"
  ) else (
    echo none
  )
)
)|"%Unx_path%gclip.exe"
exit /b
aschipfl
  • 33,626
  • 12
  • 54
  • 99
enjoying
  • 177
  • 1
  • 9

4 Answers4

3

try this:

set "myline=if 3 NEQ 2 echo yes"

( %myLin^e%)|sort

or from batch file (double expansion works differently from batch file and the console):

set "myline=if 3 NEQ 2 echo yes"

( %%myLine%%)|sort

The "mystery" was solved by jeb here and here . Though you are facing the issue before the pipe it is the same bug because the cmd creates two threads on each side of the pipe.

Here's how the for loop can be made to work:

set "line=if %a NEQ 0"
(for /L %a in (1,1,9) do @( %lin^e% echo %a))|sort /R
Community
  • 1
  • 1
npocmaka
  • 55,367
  • 18
  • 148
  • 187
  • Yes. That works. But I have complicated code `(for .... do @(if ... () else ()))|more`, which seems cannot be changed to that way. – enjoying Apr 21 '16 at 08:45
  • @enjoying I think you can use the same technique. with for command.I'll try it and if I succeed will update the answer. – npocmaka Apr 21 '16 at 08:47
  • npocmaka, I added my part of code at the end of my question. It quite complicated. The solution you said is a exactly good one. But with my real code, I have to use `if not "..." == "..."` (Luckily, I don't need `LSS`, `GTR`, `GEQ` nor `LEQ` here.) – enjoying Apr 21 '16 at 09:05
  • 1
    I found a way by testing the metod calling `%cmdcmdline%` from jeb . `echo pipe|if 1234^ gtr 124 echo %^cmdcmdline%` can work. One caret and two SPACEs have to be added before `gtr` due to the strange swallowing. – enjoying Apr 21 '16 at 11:01
  • @enjoying -Ha! Great finding. – npocmaka Apr 21 '16 at 11:09
  • @enjoying - this I think will work better with more complex expressions and works fine without piping. – npocmaka Apr 21 '16 at 11:15
  • 1
    @enjoying - may be your workaround is related to [this IF bug](http://stackoverflow.com/questions/28000194/why-if-checking-ignores-delimtersome-word-after-the-check-expression) – npocmaka Apr 21 '16 at 13:24
  • - It's interesting. Learned a lot. Thank you. – enjoying Apr 22 '16 at 04:14
3

For testing purposes the cmdcmdline variable can be used.
But this fails, when somewhere in the expression is a syntax error, as the complete code block will be dropped.

@echo off
echo dummy | (
echo %%cmdcmdline%
if 1 NEQ 2 echo Work
)

This results into "2" can't be syntactically evaluated here (From german "2" kann syntaktisch an dieser Stelle nicht verarbeitet werden.)

So exactly in the case of a syntax error, you can't see the cause!

I build a small debug variable for this case

@echo off
setlocal
(set \n=^
%=empty=%
)
set "debug=echo ### %%cmdcmdline%% ^) %%\n%%"
echo dummy | (
    %debug%
    if 1 NEQ 2 echo Work
)

When you add the %debug% you will see the cmdcmdline, but the code will not be executed, so you can examine how different modification take effect.

Like

...
| ( 
  %debug%
  break & if 1 NEQ 2 echo THIS FAILS
)

but

...
| ( 
  %debug%
  break ^& if 1 NEQ 2 echo This Works !!!
)

The trick is to add ^) %%\n%%, this closes the debug expression code block with ) and cancels further parsing of the remaing code by the linefeed %%\n%%.

jeb
  • 78,592
  • 17
  • 171
  • 225
  • 2
    so `break ^&if ...` is the ultimate workaround for this? – npocmaka Apr 21 '16 at 16:58
  • @jeb , It's coooool of your debug method. I tested `if 1234 gtr 124 echo ture`, `if 1234^ gtr 124 echo ture`, `if 1234^ gtr 124 echo ture` (The 3rd one has double SPACEs befor `gtr`. But the 2nd one is failed. Why? – enjoying Apr 22 '16 at 02:18
  • 1
    @npocmaka, I think there is an even easier work-around that works with all `if` statements (including `not`, `exist`, `defined`, `else`, all comparison operators and on either side of the pipe): `(if^ left_item OP right_item ...)` – aschipfl Feb 16 '17 at 10:25
3

Base on the idea & method from npocmaka & jeb.

Another way was found to solve the error of IF command in piped code.

TO ADD AN ESCAPE SPACE AT RIGHT POSITION


For EQU NEQ LSS LEQ GTR or GEQ,

  1. ONE ^ has to be added after 1st compared string/number,

  2. At least TWO SPACE have to be added between this ^ and EQU NEQ LSS LEQ GTR or GEQ.

Example,

echo pipe|IF 1234^  GTR 124 echo true

true can be replaced by %^cmdcmdline% to see the parser.

(IF 1234^  NEQ 124 echo right)|more

For IF DEFINED & IF EXIST

  1. At least ONE SPACE has to be added after IF DEFINED or IF EXIST,
  2. At least TWO SPACE have to be added before variable or file/folder,
  3. ONE ^ has to be added between above added SPACE.

Example,

echo pipe|IF DEFINED ^  username echo true
echo pipe|IF EXIST ^  c:\windows echo true

true can be replaced by %^cmdcmdline% to see the parser

(IF DEFINED ^  username echo right)|more
(IF EXIST ^  c:\windows echo right)|more

But so far I didn't know why all of them have to work like above.


Something interesting,

echo pipe|if 123^   equ   ======  123 ======    echo %^cmdcmdline%

All = are ignored.

Updated (2016-04-23),

As npcmaka mentioned, =,, are also delimiters.

CASE 1

echo pipe|if not defined^===neq === echo %^cmdcmdline%

Outputs,

C:\Windows\system32\cmd.exe  /S /D /c" if not defined=== neq echo %cmdcmdline%"

CASE 2

echo pipe|if not defined^ === neq === echo %^cmdcmdline%

Outputs,

C:\Windows\system32\cmd.exe  /S /D /c" if not defined == = neq === echo %cmdcmdline%"

One space appears between ===.

CASE 3

echo pipe|if not defined^,,,neq ,,, echo %^cmdcmdline%

Outputs,

C:\Windows\system32\cmd.exe  /S /D /c" if not defined,NEQ echo %cmdcmdline%"

Some phenomenon can be found, which may be known how to parse...

  • neq is identified as variable in all CASE. (do set neq=blah before will occur no output for all CASE)

  • In CASE 2, == in Delimiter === seems be identified as comparison and auto be added one space after

  • According to the rule in CASE 2, in CASE 3, input neq is lowercase and output NEQ is uppercase. But in CASE 1 & 2, due to existed == before neq, this time, neq is kept in lowercase, which is not identified as comparison.

So it has several steps in parser period. But has some bugs of adding or deleting delimiters. Right?

CASE 4

The next code seems trigger cmd executing infinitely,

echo pipe|if not defined^ == echo %^cmdcmdline%

it runs like if not "defined" == "echo" recursive command

enjoying
  • 177
  • 1
  • 9
  • 3
    Yes.`=` is a standard delimiter in batch files - in a lot of cases it acts like ``, `` , `,` ,`;`. This will also work `if 123 equ === 123 == echo #` – npocmaka Apr 22 '16 at 09:01
  • 1
    @npcmaka - Something more interesting I found after reading your new post at dostips. please see my updated content... – enjoying Apr 23 '16 at 13:27
  • Interesting.Looks like `cmdcmdline` is recursively expanded and executing itself. – npocmaka Apr 23 '16 at 17:49
2

I think the easiest work-around to get if statements working within pipes is the following (the outer surrounding pair of parentheses is mandatory):

(if^ comparison_expression conditional_command_line)
(if^ comparison_expression (conditional_command_line) else other_conditional_command_line)

I tested it with all keywords like not, exist and defined, else clauses, all possible comparison operators (==, EQU, NEQ, etc.), for either side of the pipe, and in cmd and batch-files.
Also I also successfully tested the if statements embedded within the body of a for loop (in which case the outer parentheses are no longer required).

aschipfl
  • 33,626
  • 12
  • 54
  • 99