Harry Johnston
Harry Johnston

Reputation: 36308

Why don't some "for" commands work when the output is piped?

As an example of the problem I'm seeing, the command

for /D %%i in (*) do @if not exist m:\home\%%i echo %%i

gives me a list of directories in the current directory that don't exist in the other directory.

However, if I want to pipe the output to another command, for example:

(for /D %%i in (*) do @if not exist m:\home\%%i echo %%i) | findstr /n .

I get this error message:

echo was unexpected at this time.

Note that I can't just leave the brackets out, because that would result in the pipe operator being processed once per iteration of the loop; I need the output of the loop piped to a single instance of an application. For example, if I leave the brackets out in this example, the line number from findstr will always be shown as 1 rather than counting the number of directories.

Does anybody know how to make this work, preferably in the general case rather than just this specific example?

Windows 7 SP1 x64.

Upvotes: 5

Views: 85

Answers (2)

Harry Johnston
Harry Johnston

Reputation: 36308

As per Eryksun's comments, this is definitely a bug. It can be worked around by explicitly creating a child process, rather than letting the batch processor do it for you:

cmd /s /c "for /D %%i in (*) do @if not exist m:\home\%%i echo %%i" | findstr /n .

Another option is to manually inject the missing space, by defining %space% to be a single space and saying:

(for /D %%i in (*) do @if not exist ^%%space^%% m:\home\%%i echo %%i) | findstr /n .

Upvotes: 2

jeb
jeb

Reputation: 82257

It's a problem of the parser with special IF syntax forms like:

IF exist
IF defined
IF errorlevel
IF x EQU y

But this one works without problems

IF x == y

It can be solved with defining a variable containing a single IF.

set "_IF_=IF"
( %%_IF_%% defined path echo It's defined ) | more
( %%_IF_%% errorlevel 0 echo Errorlevel is 0 or above ) | more

This works, as the %%_IF_%% will be expanded not before the child process parses the block.

Upvotes: 2

Related Questions