标题: [其他] [已解决]批处理使用管道后,如何捕获errorlevel? [打印本页]
作者: shootman2 时间: 2015-3-21 10:18 标题: [已解决]批处理使用管道后,如何捕获errorlevel?
本帖最后由 shootman2 于 2015-3-27 01:02 编辑
假如使用了管道符后,再去捕获errorlevel时发现,其值已变为0,即便之前的命令是否返回0。
如下代码
call myCommand.bat|mtee /d /t /+ sysLog.log
如果调用myCommand.bat后返回errorlevel值为1,但是执行如上代码后,errorlevel值又变为0了,
求大神帮助!!!
作者: bailong360 时间: 2015-3-21 18:26
(call myCommand.bat&Set ExitCode=!ErrorLevel!)|mtee /d /t /+ sysLog.log
这样呢?
作者: shootman2 时间: 2015-3-21 23:34
回复 2# bailong360
我试过了,不行的!
作者: bailong360 时间: 2015-3-21 23:50
- call myCommand.bat&>$tmp.txt Echo;!ErrorLevel!|mtee /d /t /+ sysLog.log
- Set /P ExitCode=<$tmp.txt
复制代码
那就这样吧
作者: shootman2 时间: 2015-3-24 15:17
回复 4# bailong360
还是没有达到我想要的结果,errorlevel是获取正确了,但是没有正确的将打印结果输出到sysLog.log文件中
作者: CrLf 时间: 2015-3-24 22:15
管道中不允许有独立的内部命令或代码块,所以这个 call myCommand.bat|mtee /d /t /+ sysLog.log 相当于- cmd /c call myCommand.bat|mtee /d /t /+ sysLog.log
复制代码
而只要是外部命令,一定会改变退出码,所以你取到的永远是 mtee 的退出码
至于怎么解决...这里举一个比较复杂的例子:- for /f "delims=" %%a in ('cmd /c "(call myCommand.bat 1>&2 2>nul & call echo %%errorlevel^^%%) 1>&2 2>&1|mtee /d /t /+ sysLog.log" 2^>^&1') do (
- echo call myCommand.bat 的退出码是 %%a
- )
复制代码
1>&2 2>&1 的意思是交换句柄 1 和 2,很久以前发现的小技巧,一直用不上,也不知道有没有人用过
作者: bailong360 时间: 2015-3-24 22:59
回复 6# CrLf
请教一下在这里交换句柄指向的意义......表示这么高深的代码全然看不懂
作者: shootman2 时间: 2015-3-24 23:08
管道中不允许有独立的内部命令或代码块,所以这个 call myCommand.bat|mtee /d /t /+ sysLog.log 相当于而只 ...
CrLf 发表于 2015-3-24 22:15
CrLf 大神,太牛了!32个赞给你。但是能不能稍微简化一下,不好理解呀!
作者: CrLf 时间: 2015-3-24 23:48
本帖最后由 CrLf 于 2015-3-25 01:00 编辑
回复 7# bailong360
回复 8# shootman2
仔细想一下其实不需要交换句柄 1 和 2,化简一下:(外交部发言人 for /f 代表党和人民热烈欢迎英勇突围的 %errorlevel%,并致以最诚挚的问候)- for /f "delims=" %%a in ('"(call myCommand.bat 2>nul & call echo %%errorlevel^^%% 1>&2)|mtee /d /t /+ sysLog.log 2>&1"') do (
- echo call myCommand.bat 的退出码是 %%a
- )
复制代码
----------------------------------------------------------------------------------------------------
经过预处理变成这样:(for /f 欢迎突围的 %errorlevel%)- for /f "delims=" %a in ('"(call myCommand.bat 2>nul & call echo %errorlevel^^% 1>&2)|mtee /d /t /+ sysLog.log 2>&1"') do (
- echo call myCommand.bat 的退出码是 %a
- )
复制代码
----------------------------------------------------------------------------------------------------
for /f 隐含了一个 cmd,执行起来相当于:(这里没发生什么,只是在句柄 1 中包含了 %errorlevel% 的内容)- cmd /c "(call myCommand.bat 2>nul & call echo %errorlevel^^% 1>&2)|mtee /d /t /+ sysLog.log 2>&1"
复制代码
----------------------------------------------------------------------------------------------------
管道前的代码块触发了一个内层的 cmd,外面的 cmd 执行的代码相当于这样:(因为 mtee 已经取走了所有来自句柄 1 的输出,所以句柄 1 为空,可以放心将句柄 2 再重定向到句柄 1)- (cmd /c "(call myCommand.bat 2>nul & call echo %errorlevel^^% 1>&2)"|mtee /d /t /+ sysLog.log) 2>&1
复制代码
----------------------------------------------------------------------------------------------------
里面那个隐含的 cmd 执行的是这样:(把这句柄 1 的输出都交给 mtee 进行处理,句柄 2 的未被读取)- cmd /c (call myCommand.bat 2>nul & call echo %errorlevel^% 1>&2)
复制代码
----------------------------------------------------------------------------------------------------
管道前的部分执行的是这样:(先将 call myCommand.bat 的句柄 1 输出到句柄 2 中,并屏蔽原有的句柄 2 输出,再输出其 %errorlevel% 到正常的句柄 2)- (
- call myCommand.bat 2>nul
- call echo %errorlevel% 1>&2
- )
- rem 因为 cmd 里不存在的变量不会被扩展,所以只要不存在 errorlevel^ 变量,%errorlevel^% 就不会被扩展
复制代码
----------------------------------------------------------------------------------------------------
接下来,请按 ctrl+A 全选变成蓝底白字,然后从下往上看粗体字
作者: shootman2 时间: 2015-3-25 12:08
回复 bailong360
回复 shootman2
仔细想一下其实不需要交换句柄 1 和 2,化简一下:(外交部 ...
CrLf 发表于 2015-3-24 23:48
myCommand.bat是有输出的,当我执行您写的代码后,结果是这样的。。。
1
call myCommand.bat 的退出码是 2015-03-25 12:06:11.833 1231312312
call myCommand.bat 的退出码是 2015-03-25 12:06:11.837 12312312312312312
请按任意键继续. . .
myCommand.bat内容如下
@echo off
echo 1231312312
echo 12312312312312312
exit /b 1
作者: CrLf 时间: 2015-3-25 16:16
本帖最后由 CrLf 于 2015-3-25 20:26 编辑
回复 10# shootman2
ok,那你试试这个:- @echo off
-
- rem 1>nul 3>&1 4>&1
-
- (
- (
- (
- call myCommand.bat 2>nul & call echo %%errorlevel^^^^%% 1>&2
- )|(
- mtee /d /t /+ sysLog.log
- )
- ) 1>&2 2>&3 | (
- set /p err=&call exit /b %%err^^%%
- )
- ) 1>&3
-
- echo myCommand.bat 的退出码为 %errorlevel%
-
- pause
复制代码
用了句柄重定向中的句柄备份、句柄交换两个小技巧
伪代码是这样:- 【备份干净的句柄 1 到句柄 3 中备用】
-
- (
- (
- (
- 【屏蔽 myCommand.bat 句柄 2】
- 【输出 %errorlevel% 到句柄 2】
- ) | (
- 【mtee 接收句柄 1 并将其内容原样输出到句柄 1】
- )
- ) 【交换句柄 1 和 2,因为此时句柄 1 是“脏”的,所以从句柄 3 获取原始的句柄 1】 | (
- 【获取句柄 1 的值保存到变量】
- 【以此变量为退出码设定最终的 %errorlevel%】
- )
- ) 【将句柄 1 还原为原始的句柄 1】
-
- 【显示 myCommand.bat 的退出码 %errorlevel%】
复制代码
作者: shootman2 时间: 2015-3-26 00:04
回复 11# CrLf
哈哈!实现了,感谢您,对您的景仰有如滔滔江水!
不过还有个问题,当myCommand.bat有报错的话,是直接打印出来的,您的代码,就直接给屏蔽掉了。
能帮忙再改改嘛?
作者: CrLf 时间: 2015-3-26 00:16
回复 12# shootman2
如果一定要不生成临时文件的话那没办法,StdOut 和 StdErr 一定要有一个用来输出 %errorlevel%
但如果可以用临时文件就很简单了,你把它输出到文本,比如这样:- @echo off
- (call myCommand.bat & call echo %%errorlevel^^%% >errorlevel.txt) |mtee /d /t /+ sysLog.log
- set /p error=<errorlevel.txt
- echo myCommand.bat 的退出码为 %error%
- pause
复制代码
作者: shootman2 时间: 2015-3-26 10:07
回复 13# CrLf
嗯!正解。。。大神,你太牛了!对您的景仰有如滔滔江水,永远都流不尽啊!
作者: pcl_test 时间: 2015-3-26 11:25
回复 14# shootman2
问题得到解决后请在标题最前面注明[已解决]
http://www.bathome.net/thread-3473-1-1.html
作者: shootman2 时间: 2015-3-26 11:55
回复 13# CrLf
@echo off
set exit_code_file=%thd_tmp_folder%\errorlevel.txt
(call myCommand.bat & call echo %%errorlevel^^%% >"!exit_code_file!") |mtee /d /t /+ sysLog.log
set /p error=<"!exit_code_file!"
echo myCommand.bat 的退出码为 %error%
pause
报错了,提示找不到文件,这是咋回事呢?
作者: CrLf 时间: 2015-3-26 15:35
回复 16# shootman2
我这里测试无误- 2015-03-26 15:35:17.879 1231312312
- 2015-03-26 15:35:17.879 12312312312312312
- myCommand.bat 的退出码为 1
- 请按任意键继续. . .
复制代码
作者: shootman2 时间: 2015-3-26 16:23
回复 17# CrLf
是这样的,您看!我把errorlevel.txt文件扩展了一下,给放到了一个特殊的目录下,文件的完整路径为:
set exit_code_file=%thd_tmp_folder%\errorlevel.txt & rem %thd_tmp_folder%是我指定的一个专门存放临时文件的目录
然后,将所有输出内容到errorlevel.txt的地方都修改成了"!exit_code_file!",就成了下面的这个样子了
@echo off
set exit_code_file=%thd_tmp_folder%\errorlevel.txt
(call myCommand.bat & call echo %%errorlevel^^%% >"!exit_code_file!") |mtee /d /t /+ sysLog.log
set /p error=<"!exit_code_file!"
echo myCommand.bat 的退出码为 %error%
pause
但是它报错了,提示找不到文件,然后我改成是如下代码后,就不报错了,
@echo off
set exit_code_file=%thd_tmp_folder%\errorlevel.txt
(call myCommand.bat & call echo %%errorlevel^^%% >"%thd_tmp_folder%\errorlevel.txt") |mtee /d /t /+ sysLog.log
set /p error=<"%thd_tmp_folder%\errorlevel.txt"
echo myCommand.bat 的退出码为 %error%
pause
我想知道这是为什么? 以上的这段代码是处在一个for循环内部的,且都开启了变量延迟。
作者: CrLf 时间: 2015-3-26 16:52
变量延迟会触发 ^ 的转义,^ 的数量得翻倍
作者: shootman2 时间: 2015-3-26 17:00
回复 19# CrLf
确实如您所说,测试代码是正常的
@echo off
set exit_code_file=%cd%\kkk\errorlevel.txt
(call myCommand.bat & call echo %%errorlevel^^%% >"%exit_code_file%") |mtee /d /t /+ sysLog.log
set /p error=<"%exit_code_file%"
echo myCommand.bat 的退出码为 %error%
pause
那像前面的那种写法,有没有解决方法呢?
作者: CrLf 时间: 2015-3-26 19:42
回复 20# shootman2
^ 的数量翻倍
作者: shootman2 时间: 2015-3-26 20:02
回复 21# CrLf
好像还是不行!我已经加到了4个,6个也不行,8个也不行
@echo off
setlocal enabledelayedexpansion
set exit_code_file=%cd%\kkk\errorlevel.txt
(call myCommand.bat & call echo %%errorlevel^^^^%% >"!exit_code_file!") |mtee /d /t /+ sysLog.log
set /p error=<"!exit_code_file!"
echo myCommand.bat 的退出码为 %error%
pause
2015-03-26 20:00:59.649 1231312312
2015-03-26 20:00:59.654 12312312312312312
系统找不到指定的文件。
myCommand.bat 的退出码为
请按任意键继续. . .
再不行,我就放弃了!
作者: CrLf 时间: 2015-3-26 20:54
回复 22# shootman2
诡异,括号居然会影响解析,我也没搞明白这里的 !exit_code_file! 为什么没有扩展,不过去掉括号就好了,相当于直接传递给 cmd /c 去解析,这样就一定会扩展- @echo off
- setlocal enabledelayedexpansion
- set exit_code_file=errorlevel.txt
- call myCommand.bat ^& call echo %%errorlevel^^^^%% ^>"!exit_code_file!" |mtee /d /t /+ sysLog.log
- set /p error=<"!exit_code_file!"
- echo myCommand.bat 的退出码为 %error%
- pause
复制代码
作者: shootman2 时间: 2015-3-27 01:01
回复 23# CrLf
对CrLf大哥的这种精神所震撼,感谢您帮我解决问题。非常感谢!!!
作者: shootman2 时间: 2015-4-6 19:02
回复 23# CrLf
大哥,我又遇到了新问题,我想将myCommand.bat中的错误输出也打印到sysLog.log文件中,论坛里有大神告诉我得加个 2>&1 语句,
但是加了之后一直未生效,但是把后面的语句 ^& call echo %%errorlevel^^^^%% ^>"!exit_code_file!" 去掉后,就ok了,我想让
它们共存,该怎么办呢?求帮助!
如下不能生效的代码- @echo off
- setlocal enabledelayedexpansion
- set exit_code_file=errorlevel.txt
- call myCommand.bat 2>&1 ^& call echo %%errorlevel^^^^%% ^>"!exit_code_file!" |mtee /d /t /+ sysLog.log
- set /p error=<"!exit_code_file!"
- echo myCommand.bat 的退出码为 %error%
- pause
复制代码
作者: bailong360 时间: 2015-4-6 19:32
回复 25# shootman2
你得把问题说完整啊...
在myCommand.bat的开头加上@echo off 2>&1 3>&1
这样输出就都正常了
作者: shootman2 时间: 2015-4-6 19:44
回复 26# bailong360
正解!太感谢大哥了。。。
欢迎光临 批处理之家 (http://www.bathome.net/) |
Powered by Discuz! 7.2 |