1

Why the !ERRORLEVEL! does not work in the following example?

@echo off
setlocal enabledelayedexpansion
(
  winscp.com /?
  echo !ERRORLEVEL!
) | findstr /v "word"
exit

I get !ERRORLEVEL! on the output.

While if I remove the | findstr /v "word":

@echo off
setlocal enabledelayedexpansion
(
  winscp.com /?
  echo !ERRORLEVEL!
)
exit

I get the error level on the output.

1 Answer 1

2

It's because a pipe executes both sides in new cmd.exe instances (when the command is a batch command).

The commands/code blocks are converted and used as parameters for cmd.exe, in your example it becomes:

C:\WINDOWS\system32\cmd.exe /S /D /c"( winscp.com & echo !errorlevel!)"

But as a new cmd.exe instance is invoked, the delayed expansion is disabled by default.

You could also examine the behaviour by using the cmdcmdline pseudo variable.

@echo off
(
  echo %%cmdcmdline%%
  echo !ERRORLEVEL!  
) | findstr /n "^"

Shows:

1:C:\WINDOWS\system32\cmd.exe /S /D /c" ( echo %cmdcmdline% & echo !ERRORLEVEL! )"
2:!ERRORLEVEL!

For more information Why does delayed expansion fail when inside a piped block of code?

Using errorlevel inside a code block with piping

You could simply use another expansion method

(
  winscp.com /?
  call echo %%ERR^^ORLEVEL%%
) | findstr /v "word"

Obviously, this works by the fact, that the converted block looks like

C:\WINDOWS\system32\cmd.exe  /S /D /c" ( winscp.com /? & call echo %ERR^ORLEVEL%  )" 

After cmd.exe parsed the block the percent expansion is already done and the block looks like

( winscp /? & call echo %errorlevel% )

The caret is important here, to avoid that the expansion occurs before the line is executed.

Another solution

Create your own cmd.exe instance with delayed expansion enabled by

(
  winscp.com /?
  cmd /V:on /c echo !SOME_VARIABLE!
) | findstr /v "word"

But this only works with "normal" variables, NOT with ERRORLEVEL or cmdcmdline, because they are changed by starting the new instance

Using a sub batch file

Instead of using a code block on the left side of the pipe, you could use a batch file, there it's possible to enable the delayed expansion again.

I'm using a trampoline function, to put the complete code into one batch file.

@echo off
FOR /F "tokens=3 delims=:" %%X in ("%0") do goto :%%X

"%~d0\:myblock:\..\%~pnx0" | findstr /v "word"
exit /b

:myblock
setlocal enabledelayedexpansion
(
  winscp.com /?
  echo !ERRORLEVEL!
)
exit /b
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.