簡體   English   中英

如何從 Windows 命令行獲取應用程序退出代碼?

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

我正在運行一個程序並想查看它的返回代碼是什么(因為它根據不同的錯誤返回不同的代碼)。

我知道在 Bash 中我可以通過運行來做到這一點

回聲 $?

在 Windows 上使用 cmd.exe 時該怎么辦?

一個名為errorlevel偽環境變量存儲退出代碼:

echo Exit Code is %errorlevel%

此外, if命令有一個特殊的語法:

if errorlevel

看看if /? 詳情。

例子

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

警告:如果您設置環境變量名稱errorlevel%errorlevel%將返回該值而不是退出代碼。 使用 ( set errorlevel= ) 清除環境變量,允許通過%errorlevel%環境變量訪問errorlevel的真實值。

測試ErrorLevel適用於控制台應用程序,但正如dmihailescu所暗示的那樣,如果您嘗試從命令提示符運行窗口應用程序(例如基於 Win32 的應用程序),這將不起作用。 窗口化應用程序將在后台運行,並且控制權將立即返回到命令提示符(最有可能的ErrorLevel為零表示該進程已成功創建)。 當窗口化應用程序最終退出時,其退出狀態將丟失。

不過,與使用其他地方提到的基於控制台的 C++ 啟動器不同,更簡單的替代方法是使用命令提示符的START /WAIT命令啟動窗口應用程序。 這將啟動窗口化應用程序,等待它退出,然后將控制權返回到命令提示符,並在ErrorLevel中設置進程的退出狀態。

start /wait something.exe
echo %errorlevel%

使用內置的 ERRORLEVEL 變量:

echo %ERRORLEVEL%

要注意應用程序是否定義了名為 ERRORLEVEL 的環境變量

如果要精確匹配錯誤代碼(例如等於 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 0匹配錯誤errorlevel >= 0。看看if /? .

使用未附加到控制台的程序時,它可能無法正常工作,因為當您認為擁有退出代碼時,該應用程序可能仍在運行。 在 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;
}

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

閱讀https://ss64.com/nt/errorlevel.html它注意到以下內容:

.CMD 和 .BAT 批處理文件設置錯誤級別的方式有一個關鍵區別:

運行“新”內部命令的舊 .BAT 批處理腳本:APPEND、ASSOC、PATH、PROMPT、FTYPE 和 SET 僅在發生錯誤時設置 ERRORLEVEL。 因此,如果批處理腳本中有兩個命令並且第一個失敗,則即使第二個命令成功,ERRORLEVEL 仍將保持設置。

這會使調試有問題的 BAT 腳本更加困難,CMD 批處理腳本更加一致,並且會在您運行每個命令后設置 ERRORLEVEL [source]。

這讓我在執行連續命令時悲痛不已,但即使發生故障,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 off
    set LGT_EXITCODE="$LGT_ID"
    exit /b %LGT_ID%
EOF
unix2dos "$LGT_TEMP_FILE"

這是在 WEVL 中創建事件的函數:

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

執行批處理腳本並調用 __create_event:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM