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.
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