简体   繁体   中英

Using !ERRORLEVEL! in code block piped to another process

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM