使用!ERRORLEVEL!在通过管道传输到另一个进程的代码块中
Using !ERRORLEVEL! in code block piped to another process
为什么 !ERRORLEVEL!
在以下示例中不起作用?
@echo off
setlocal enabledelayedexpansion
(
winscp.com /?
echo !ERRORLEVEL!
) | findstr /v "word"
exit
我在输出中得到 !ERRORLEVEL!
。
而如果我删除 | findstr /v "word"
:
@echo off
setlocal enabledelayedexpansion
(
winscp.com /?
echo !ERRORLEVEL!
)
exit
我得到了输出的错误级别。
这是因为一个管道在新的cmd.exe个实例中执行两侧(当命令是批处理命令时)。
commands/code 块被转换并用作 cmd.exe 的参数,在您的示例中它变为:
C:\WINDOWS\system32\cmd.exe /S /D /c"( winscp.com & echo !errorlevel!)"
但是当调用一个新的cmd.exe实例时,默认情况下禁用延迟扩展。
您还可以使用 cmdcmdline
伪变量检查行为。
@echo off
(
echo %%cmdcmdline%%
echo !ERRORLEVEL!
) | findstr /n "^"
显示:
1:C:\WINDOWS\system32\cmd.exe /S /D /c" ( echo %cmdcmdline% & echo !ERRORLEVEL! )"
2:!ERRORLEVEL!
更多信息Why does delayed expansion fail when inside a piped block of code?
在带有管道的代码块中使用错误级别
你可以简单地使用另一种扩展方法
(
winscp.com /?
call echo %%ERR^^ORLEVEL%%
) | findstr /v "word"
显然,这是有效的,转换后的块看起来像
C:\WINDOWS\system32\cmd.exe /S /D /c" ( winscp.com /? & call echo %ERR^ORLEVEL% )"
在 cmd.exe 解析块后,百分比扩展已经完成,块看起来像
( winscp /? & call echo %errorlevel% )
插入符号在这里很重要,以避免在执行该行之前发生扩展。
另一种解决方案
创建您自己的 cmd.exe 实例,并通过
启用延迟扩展
(
winscp.com /?
cmd /V:on /c echo !SOME_VARIABLE!
) | findstr /v "word"
但这仅适用于“普通”变量,不适用于 ERRORLEVEL
或 cmdcmdline
,因为它们会通过启动新实例进行更改
使用子批处理文件
您可以使用批处理文件代替管道左侧的代码块,这样可以再次启用延迟扩展。
我正在使用 trampoline 函数,将完整的代码放入一个批处理文件中。
@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
为什么 !ERRORLEVEL!
在以下示例中不起作用?
@echo off
setlocal enabledelayedexpansion
(
winscp.com /?
echo !ERRORLEVEL!
) | findstr /v "word"
exit
我在输出中得到 !ERRORLEVEL!
。
而如果我删除 | findstr /v "word"
:
@echo off
setlocal enabledelayedexpansion
(
winscp.com /?
echo !ERRORLEVEL!
)
exit
我得到了输出的错误级别。
这是因为一个管道在新的cmd.exe个实例中执行两侧(当命令是批处理命令时)。
commands/code 块被转换并用作 cmd.exe 的参数,在您的示例中它变为:
C:\WINDOWS\system32\cmd.exe /S /D /c"( winscp.com & echo !errorlevel!)"
但是当调用一个新的cmd.exe实例时,默认情况下禁用延迟扩展。
您还可以使用 cmdcmdline
伪变量检查行为。
@echo off
(
echo %%cmdcmdline%%
echo !ERRORLEVEL!
) | findstr /n "^"
显示:
1:C:\WINDOWS\system32\cmd.exe /S /D /c" ( echo %cmdcmdline% & echo !ERRORLEVEL! )"
2:!ERRORLEVEL!
更多信息Why does delayed expansion fail when inside a piped block of code?
在带有管道的代码块中使用错误级别
你可以简单地使用另一种扩展方法
(
winscp.com /?
call echo %%ERR^^ORLEVEL%%
) | findstr /v "word"
显然,这是有效的,转换后的块看起来像
C:\WINDOWS\system32\cmd.exe /S /D /c" ( winscp.com /? & call echo %ERR^ORLEVEL% )"
在 cmd.exe 解析块后,百分比扩展已经完成,块看起来像
( winscp /? & call echo %errorlevel% )
插入符号在这里很重要,以避免在执行该行之前发生扩展。
另一种解决方案
创建您自己的 cmd.exe 实例,并通过
启用延迟扩展(
winscp.com /?
cmd /V:on /c echo !SOME_VARIABLE!
) | findstr /v "word"
但这仅适用于“普通”变量,不适用于 ERRORLEVEL
或 cmdcmdline
,因为它们会通过启动新实例进行更改
使用子批处理文件
您可以使用批处理文件代替管道左侧的代码块,这样可以再次启用延迟扩展。
我正在使用 trampoline 函数,将完整的代码放入一个批处理文件中。
@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