如何正确报告分批退出状态? [英] How to properly report an exit status in batch?

查看:203
本文介绍了如何正确报告分批退出状态?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我现在面临一个奇怪的情况:一个批处理文件,我写了报告不正确的退出状态。下面是再现问题的最少的样品:

I'm facing a weird situation where a batch file I wrote reports an incorrect exit status. Here is a minimal sample that reproduces the problem:

echo before

if "" == "" (
        echo first if
        exit /b 1

        if "" == "" (
                echo second if
        )
)

echo after

如果我运行此脚本(使用Python,但在其他方面也确实推出时出现的问题),这里是我所得到的:

If I run this script (using Python but the problem actually occurs when launched in other ways too), here is what I get:

python -c "from subprocess import Popen as po; print 'exit status: %d' % po(['bug.cmd']).wait()"
echo before
before

if "" == "" (
echo first if
 exit /b 1
 if "" == "" (echo second if )
)
first if
exit status: 0

请注意如何退出状态报告为 0 即使退出/ B 1 应该把它变成 1

Note how exit status is reported as 0 even though exit /b 1 should make it be 1.

现在奇怪的是,如果我删除了里面的如果子句(这不应该的问题,因为一切都在退出/ B 1 不应该被执行的),并尝试将其启动:

Now the weird thing is that if I remove the inside if clause (which should not matter because everything after exit /b 1 should not be executed anyway) and try to launch it:

echo before

if "" == "" (
        echo first if
        exit /b 1
)

echo after

我再次启动它:

python -c "from subprocess import Popen as po; print 'exit status: %d' % po(['ok.cmd']).wait()"

echo before
before

(environment) F:\pf\mm_3.0.1\RendezVous\Services\Matchmaking>if "" == "" (
echo first if
 exit /b 1
)
first if
exit status: 1

现在的退出状态被正确地报告为 1

Now the exit status is correctly reported as 1.

我在亏损了解是什么原因造成这一点。它是非法的巢如果语句?

I'm at loss understanding what is causing this. Is it illegal to nest if statements ?

如何信号正确,可靠我的脚本退出状态在批处理?

请注意:调用退出1 (不包括 / B )是不是一种选择,因为它杀死整间preTER和prevents本地脚本的使用。

Note: calling exit 1 (without the /b) is not an option as it kills the whole interpreter and prevents local script usage.

推荐答案

由于@dbenham指出,[我]发命令后,解析EXIT / B ,内同样的命令块,那么问题出现,即使随后的命令不会被执行。在这种特殊情况下的如果语句体基本上评为

As @dbenham notes, "[i]f a command is parsed after EXIT /B, within the same command block, then the problem manifests, even though the subsequent command never executes". In this particular case the body of the IF statement is basically evaluated as

(echo first if) & (exit /b 1) & (if "" == "" (echo second if))

其中&安培; 操作符的功能是 CMD eComSep (即命令分隔符)!在 EXIT / B 1 命令(函数 CMD!eExit ),通过设置全局变量评估 CMD LastRet code 1,然后基本上执行 GOTO:EOF 。当它返回时,第二个 eComSep 看到 CMD!GotoFlag 设置,因此跳过评估右侧。在这种情况下,它也忽略了左边的返回code,而不是返回成功(0)。这传递了堆栈成为进程退出code。

where the & operator is the function cmd!eComSep (i.e. command separator). The EXIT /B 1 command (function cmd!eExit) is evaluated by setting the global variable cmd!LastRetCode to 1 and then basically executing GOTO :EOF. When it returns, the second eComSep sees cmd!GotoFlag is set and so skips evaluating the right-hand side. In this case, it also ignores the return code of the left-hand side to instead return SUCCESS (0). This gets passed up the stack to become process exit code.

在下面,我包括运行bug.cmd和ok.cmd调试会话。

Below I've included the debug sessions for running bug.cmd and ok.cmd.

bug.cmd:

(test) C:\Temp>cdb -oxi ld python

Microsoft (R) Windows Debugger Version 6.12.0002.633 AMD64
Copyright (c) Microsoft Corporation. All rights reserved.

CommandLine: python
Symbol search path is: symsrv*symsrv.dll*
    C:\Symbols*http://msdl.microsoft.com/download/symbols
Executable search path is:
(1404.10b4): Break instruction exception - code 80000003 (first chance)
ntdll!LdrpDoDebuggerBreak+0x30:
00000000`77848700 cc              int     3
0:000> g

Python 3.4.3 (v3.4.3:9b73f1c3e601, Feb 24 2015, 22:44:40)
[MSC v.1600 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from subprocess import Popen as po
>>> po('bug.cmd').wait()

Symbol search path is: symsrv*symsrv.dll*
    C:\Symbols*http://msdl.microsoft.com/download/symbols
Executable search path is:
(1818.1a90): Break instruction exception - code 80000003 (first chance)
ntdll!LdrpDoDebuggerBreak+0x30:
00000000`77848700 cc              int     3
1:005> bp cmd!eExit
1:005> g

(test) C:\Temp>echo before
before

(test) C:\Temp>if "" == "" (
echo first if
 exit /b 1
 if "" == "" (echo second if )
)
first if
Breakpoint 0 hit
cmd!eExit:
00000000`4a6e8288 48895c2410      mov     qword ptr [rsp+10h],rbx
                                          ss:00000000`002fed78=0000000000000000
1:005> kc
Call Site
cmd!eExit
cmd!FindFixAndRun
cmd!Dispatch
cmd!eComSep
cmd!Dispatch
cmd!eComSep
cmd!Dispatch
cmd!Dispatch
cmd!eIf
cmd!Dispatch
cmd!BatLoop
cmd!BatProc
cmd!ECWork
cmd!ExtCom
cmd!FindFixAndRun
cmd!Dispatch
cmd!main
cmd!LUAGetUserType
kernel32!BaseThreadInitThunk
ntdll!RtlUserThreadStart

1:005> db cmd!GotoFlag l1
00000000`4a70e0c9  00                                               .
1:005> pt
cmd!eExit+0xe1:
00000000`4a6e8371 c3              ret

1:005> r rax
rax=0000000000000001
1:005> dd cmd!LastRetCode l1
00000000`4a70e188  00000001
1:005> db cmd!GotoFlag l1
00000000`4a70e0c9  01                                               .

1:005> gu;gu;gu
cmd!eComSep+0x14:
00000000`4a6e6218 803daa7e020000  cmp     byte ptr [cmd!GotoFlag
                                                    (00000000`4a70e0c9)],0
                                                    ds:00000000`4a70e0c9=01
1:005> p
cmd!eComSep+0x1b:
00000000`4a6e621f 0f85bd4d0100    jne     cmd!eComSep+0x1d
                                          (00000000`4a6fafe2) [br=1]
1:005>
cmd!eComSep+0x1d:
00000000`4a6fafe2 33c0            xor     eax,eax
1:005> pt
cmd!eComSep+0x31:
00000000`4a6e6235 c3              ret

1:005> r rax
rax=0000000000000000
1:005> bp ntdll!RtlExitUserProcess
1:005> g
Breakpoint 1 hit
ntdll!RtlExitUserProcess:
00000000`777c3830 48895c2408      mov     qword ptr [rsp+8],rbx
                                          ss:00000000`0029f6b0=00000000003e5638
1:005> r rcx
rcx=0000000000000000
1:005> g
ntdll!ZwTerminateProcess+0xa:
00000000`777ede7a c3              ret
1:005> g
0

ok.cmd:

>>> po('ok.cmd').wait()

Symbol search path is: symsrv*symsrv.dll*
    C:\Symbols*http://msdl.microsoft.com/download/symbols
Executable search path is:
(ce4.b94): Break instruction exception - code 80000003 (first chance)
ntdll!LdrpDoDebuggerBreak+0x30:
00000000`77848700 cc              int     3
1:002> bp cmd!eExit
1:002> g

(test) C:\Temp>echo before
before

(test) C:\Temp>if "" == "" (
echo first if
 exit /b 1
)
first if
Breakpoint 0 hit
cmd!eExit:
00000000`4a6e8288 48895c2410      mov     qword ptr [rsp+10h],rbx
                                          ss:00000000`0015e808=0000000000000000

1:002> kc
Call Site
cmd!eExit
cmd!FindFixAndRun
cmd!Dispatch
cmd!eComSep
cmd!Dispatch
cmd!Dispatch
cmd!eIf
cmd!Dispatch
cmd!BatLoop
cmd!BatProc
cmd!ECWork
cmd!ExtCom
cmd!FindFixAndRun
cmd!Dispatch
cmd!main
cmd!LUAGetUserType
kernel32!BaseThreadInitThunk
ntdll!RtlUserThreadStart

1:002> gu;gu;gu
cmd!eComSep+0x2c:
00000000`4a6e6230 4883c420        add     rsp,20h
1:002> p
cmd!eComSep+0x30:
00000000`4a6e6234 5b              pop     rbx
1:002> p
cmd!eComSep+0x31:
00000000`4a6e6235 c3              ret

1:002> r rax
rax=0000000000000001
1:002> bp ntdll!RtlExitUserProcess
1:002> g
Breakpoint 1 hit
ntdll!RtlExitUserProcess:
00000000`777c3830 48895c2408      mov     qword ptr [rsp+8],rbx
                                          ss:00000000`0015f750=00000000002b5638
1:002> r rcx
rcx=0000000000000001
1:002> g
ntdll!ZwTerminateProcess+0xa:
00000000`777ede7a c3              ret
1:002> g
1

在ok.cmd情况下, CMD!eComSep 只有一次在堆栈跟踪中出现。在退出/ B 1 命令被评为右侧操作数,所以code,着眼于 GotoFlag 从不运行。相反,1返回code被传递堆栈成为进程退出code。

In the ok.cmd case, cmd!eComSep only appears once in the stack trace. The exit /b 1 command is evaluated as the right-hand side operand, so the code that looks at GotoFlag never runs. Instead the return code of 1 gets passed up the stack to become the process exit code.

这篇关于如何正确报告分批退出状态?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆