如何从Windows命令行获取应用程序退出代码?

我正在运行一个程序,想看看它的返回代码是什么(因为它根据不同的错误返回不同的代码)。

我知道在Bash我可以通过跑步来做到这一点

回声$?

在Windows上使用cmd.exe时该怎么办?

968005 次浏览

名为errorlevel的伪环境变量存储退出代码:

echo Exit Code is %errorlevel%

此外,if命令有一个特殊的语法:

if errorlevel

详情见if /?

示例

@echo offmy_nifty_exe.exeif errorlevel 1 (echo Failure Reason Given is %errorlevel%exit /b %errorlevel%)

警告:如果设置环境变量名称errorlevel%errorlevel%将返回该值而不是退出代码。使用(set errorlevel=)清除环境变量,允许通过%errorlevel%环境变量访问errorlevel的真值。

使用内置的ERRORLEVEL变量:

echo %ERRORLEVEL%

注意应用程序是否定义了名为ERRORLEVEL的环境变量

使用未附加到控制台的程序时,它可能无法正常工作,因为该应用程序可能在您认为拥有退出代码时仍在运行。C++的解决方案如下所示:

#include "stdafx.h"#include "windows.h"#include "stdio.h"#include "tchar.h"#include "stdio.h"#include "shellapi.h"
int _tmain( int argc, TCHAR *argv[] ){
CString cmdline(GetCommandLineW());cmdline.TrimLeft('\"');CString self(argv[0]);self.Trim('\"');CString args = cmdline.Mid(self.GetLength()+1);args.TrimLeft(_T("\" "));printf("Arguments passed: '%ws'\n",args);STARTUPINFO si;PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );si.cb = sizeof(si);ZeroMemory( &pi, sizeof(pi) );
if( argc < 2 ){printf("Usage: %s arg1,arg2....\n", argv[0]);return -1;}
CString strCmd(args);// Start the child process.if( !CreateProcess( NULL,   // No module name (use command line)(LPTSTR)(strCmd.GetString()),        // Command lineNULL,           // Process handle not inheritableNULL,           // Thread handle not inheritableFALSE,          // Set handle inheritance to FALSE0,              // No creation flagsNULL,           // Use parent's environment blockNULL,           // Use parent's starting directory&si,            // Pointer to STARTUPINFO structure&pi )           // Pointer to PROCESS_INFORMATION structure){printf( "CreateProcess failed (%d)\n", GetLastError() );return GetLastError();}elseprintf( "Waiting for \"%ws\" to exit.....\n", strCmd );
// Wait until child process exits.WaitForSingleObject( pi.hProcess, INFINITE );int result = -1;if(!GetExitCodeProcess(pi.hProcess,(LPDWORD)&result)){printf("GetExitCodeProcess() failed (%d)\n", GetLastError() );}elseprintf("The exit code for '%ws' is %d\n",(LPTSTR)(strCmd.GetString()), result );// Close process and thread handles.CloseHandle( pi.hProcess );CloseHandle( pi.hThread );return result;}

测试ErrorLevel适用于控制台的应用程序,但正如作者:dmihailescu所暗示的,如果您尝试从命令提示符运行窗口的应用程序(例如基于Win32的应用程序),这将不起作用。窗口应用程序将在后台运行,控制将立即返回到命令提示符(很可能是ErrorLevel表示进程创建成功)。当窗口应用程序最终退出时,其退出状态丢失。

不过,与其使用其他地方提到的基于控制台的C++启动器,更简单的替代方法是使用命令提示符的START /WAIT命令启动窗口应用程序。这将启动窗口应用程序,等待它退出,然后将控制权返回到命令提示符,并在ErrorLevel中设置进程的退出状态。

start /wait something.exeecho %errorlevel%

如果您想完全匹配错误代码(例如等于0),请使用:

@echo offmy_nify_exe.exeif %ERRORLEVEL% EQU 0 (echo Success) else (echo Failure Reason Given is %errorlevel%exit /b %errorlevel%)

说明if errorlevel 0匹配errorlevel>=0。
if /?.

或者,如果你不处理成功:

if  %ERRORLEVEL% NEQ 0 (echo Failed with exit-code: %errorlevel%exit /b %errorlevel%)

有一次,我需要准确地将日志事件从Cygwin推送到Windows事件日志。我希望WEVL中的消息是自定义的,有正确的退出代码、详细信息、优先级、消息等。所以我创建了一个小Bash脚本来处理这个问题。这是在GitHub上,logit.sh

部分摘录:

usage: logit.sh [-h] [-p] [-i=n] [-s] <description>example: logit.sh -p error -i 501 -s myscript.sh "failed to run the mount command"

这是临时文件内容部分:

LGT_TEMP_FILE="$(mktemp --suffix .cmd)"cat<<EOF>$LGT_TEMP_FILE@echo offset LGT_EXITCODE="$LGT_ID"exit /b %LGT_ID%EOFunix2dos "$LGT_TEMP_FILE"

这是一个在WEVL中创建事件的函数:

__create_event () {local cmd="eventcreate /ID $LGT_ID /L Application /SO $LGT_SOURCE /T $LGT_PRIORITY /D "if [[ "$1" == *';'* ]]; thenlocal IFS=';'for i in "$1"; do$cmd "$i" &>/dev/nulldoneelse$cmd "$LGT_DESC" &>/dev/nullfi}

执行批处理脚本并调用__create_event:

cmd /c "$(cygpath -wa "$LGT_TEMP_FILE")"__create_event

值得注意的是。BAT和。CMD文件的操作方式不同。

阅读https://ss64.com/nt/errorlevel.html它注意到以下内容:

. CMD和. BAT批处理文件设置错误级别的方式有一个关键区别:

运行“new”内部命令的旧的. BAT批处理脚本:APPEND、ASSOC、PATH、PROMPT、FTYPE和SET只会在发生错误时设置ERRORLEVEL。因此,如果批处理脚本中有两个命令并且第一个失败,即使第二个命令成功,ERRORLEVEL也会保持设置。

这会使调试问题BAT脚本更加困难,CMD批处理脚本更加一致,并且会在您运行[source]的每个命令后设置ERRORLEVEL。

当我执行连续的命令时,这让我没有结束悲伤,但即使在失败的情况下,ERRORLEVEL也会保持不变。