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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/334879/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 05:48:38  来源:igfitidea点击:

How do I get the application exit code from a Windows command line?

windowscommand-lineprocesscmdexit-code

提问by Skrud

I am running a program and want to see what its return code is (since it returns different codes based on different errors).

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

I know in Bash I can do this by running

我知道在 Bash 中我可以通过运行来做到这一点

echo $?

回声 $?

What do I do when using cmd.exe on Windows?

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

回答by DrFloyd5

A pseudo environment variable named errorlevelstores the exit code:

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

echo Exit Code is %errorlevel%

Also, the ifcommand has a special syntax:

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

if errorlevel

See if /?for details.

详情请参阅if /?

Example

例子

@echo off
my_nify_exe.exe
if errorlevel 1 (
   echo Failure Reason Given is %errorlevel%
   exit /b %errorlevel%
)

Warning: If you set an environment variable name errorlevel, %errorlevel%will return that value and not the exit code. Use (set errorlevel=) to clear the environment variable, allowing access to the true value of errorlevelvia the %errorlevel%environment variable.

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

回答by Gary

Testing ErrorLevelworks for consoleapplications, but as hinted at by dmihailescu, this won't work if you're trying to run a windowedapplication (e.g. Win32-based) from a command prompt. A windowed application will run in the background, and control will return immediately to the command prompt (most likely with an ErrorLevelof zero to indicate that the process was createdsuccessfully). When a windowed application eventually exits, its exit status is lost.

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

Instead of using the console-based C++ launcher mentioned elsewhere, though, a simpler alternative is to start a windowed application using the command prompt's START /WAITcommand. This will start the windowed application, wait for it to exit, and then return control to the command prompt with the exit status of the process set in ErrorLevel.

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

start /wait something.exe
echo %errorlevel%

回答by Adam Rosenfield

Use the built-in ERRORLEVEL Variable:

使用内置的 ERRORLEVEL 变量:

echo %ERRORLEVEL%

But beware if an application has defined an environment variable named ERRORLEVEL!

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

回答by Curtis Yallop

If you want to match the error code exactly (eg equals 0), use this:

如果要精确匹配错误代码(例如等于 0),请使用以下命令:

@echo off
my_nify_exe.exe
if %ERRORLEVEL% EQU 0 (
   echo Success
) else (
   echo Failure Reason Given is %errorlevel%
   exit /b %errorlevel%
)

if errorlevel 0matches errorlevel>= 0. See if /?.

if errorlevel 0匹配errorlevel>= 0。见if /?

回答by dmihailescu

It might not work correctly when using a program that is not attached to the console, because that app might still be running while you think you have the exit code. A solution to do it in C++ looks like below:

使用未附加到控制台的程序时,它可能无法正常工作,因为当您认为拥有退出代码时,该应用程序可能仍在运行。在 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 line
        NULL,           // Process handle not inheritable
        NULL,           // Thread handle not inheritable
        FALSE,          // Set handle inheritance to FALSE
        0,              // No creation flags
        NULL,           // Use parent's environment block
        NULL,           // Use parent's starting directory 
        &si,            // Pointer to STARTUPINFO structure
        &pi )           // Pointer to PROCESS_INFORMATION structure
    ) 
    {
        printf( "CreateProcess failed (%d)\n", GetLastError() );
        return GetLastError();
    }
    else
        printf( "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() );
    }
    else
        printf("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;
}

回答by RockDoctor

It's worth noting that .BAT and .CMD files operate differently.

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

Reading https://ss64.com/nt/errorlevel.htmlit notes the following:

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

There is a key difference between the way .CMD and .BAT batch files set errorlevels:

An old .BAT batch script running the 'new' internal commands: APPEND, ASSOC, PATH, PROMPT, FTYPE and SET will only set ERRORLEVEL if an error occurs. So if you have two commands in the batch script and the first fails, the ERRORLEVEL will remain set even after the second command succeeds.

This can make debugging a problem BAT script more difficult, a CMD batch script is more consistent and will set ERRORLEVEL after every command that you run [source].

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

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

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

This was causing me no end of grief as I was executing successive commands, but the ERRORLEVEL would remain unchanged even in the event of a failure.

这让我在执行连续命令时悲痛不已,但即使发生故障,ERRORLEVEL 也将保持不变。

回答by jonretting

At one point I needed to accurately push log events from Cygwin to the Windows Event log. I wanted the messages in WEVL to be custom, have the correct exit code, details, priorities, message, etc. So I created a little Bash script to take care of this. Here it is on GitHub, logit.sh.

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

Some excerpts:

部分摘录:

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"

Here is the temporary file contents part:

这是临时文件内容部分:

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

Here is a function to to create events in WEVL:

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

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

Executing the batch script and calling on __create_event:

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

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