gpt4 book ai didi

python - 如何正确批量上报退出状态?

转载 作者:可可西里 更新时间:2023-11-01 13:28:07 26 4
gpt4 key购买 nike

我遇到了一种奇怪的情况,我编写的批处理文件报告了不正确的退出状态。这是重现问题的最小示例:

bug.cmd

echo before

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

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

echo after

如果我运行这个脚本(使用 Python 但问题实际上也发生在以其他方式启动时),这是我得到的:

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

请注意 exit status 如何报告为 0,即使 exit/b 1 应该使它成为 1 .

现在奇怪的是,如果我删除里面的 if 子句(这应该无关紧要,因为无论如何都不应该执行 exit/b 1 之后的所有内容)并尝试启动它:

ok.cmd

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

现在 exit status 被正确报告为 1

我不知道是什么原因造成的。嵌套 if 语句是否违法?

如何批量正确可靠地指示我的脚本退出状态?

注意:调用 exit 1(没有 /b)不是一个选项,因为它会杀死整个解释器并阻止本地脚本的使用。

最佳答案

正如@dbenham 指出的那样,“[i]如果在同一命令 block 中 EXIT/B 之后解析命令,那么问题就会显现,即使后续命令永远不会执行”。在这种特殊情况下,IF 语句的主体基本上被评估为

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

其中 & 运算符是函数 cmd!eComSep(即命令分隔符)。 EXIT/B 1 命令(函数 cmd!eExit)通过将全局变量 cmd!LastRetCode 设置为 1 来评估,然后基本上执行 转到:EOF。当它返回时,第二个 eComSep 看到 cmd!GotoFlag 已设置,因此跳过评估右侧。在这种情况下,它还会忽略左侧的返回码,而是返回 SUCCESS (0)。这会向上传递到堆栈,成为进程退出代码。

下面我包含了运行 bug.cmd 和 ok.cmd 的调试 session 。

错误命令:

(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 仅在堆栈跟踪中出现一次。 exit/b 1 命令被评估为右侧操作数,因此查看 GotoFlag 的代码永远不会运行。取而代之的是,返回代码 1 向上传递到堆栈,成为进程退出代码。

关于python - 如何正确批量上报退出状态?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30714985/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com