it-swarm.com.de

Wie erhalte ich den Programm-Exit-Code von einer Windows-Befehlszeile?

Ich führe ein Programm aus und möchte wissen, wie der Rückgabecode lautet (da er aufgrund verschiedener Fehler unterschiedliche Codes zurückgibt).

Ich weiß in Bash, dass ich das machen kann, indem ich renne

echo $?

Was mache ich, wenn ich cmd.exe unter Windows verwende?

737
Skrud

Eine Pseudo-Umgebungsvariable mit dem Namen errorlevel speichert den Exit-Code:

echo Exit Code is %errorlevel%

Außerdem hat der Befehl if eine spezielle Syntax:

if errorlevel

Siehe if /? für Details.

Beispiel

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

Warnung: Wenn Sie einen Umgebungsvariablennamen errorlevel festlegen, gibt %errorlevel% diesen Wert und nicht den Beendigungscode zurück. Verwenden Sie (set errorlevel=), um die Umgebungsvariable zu löschen und den Zugriff zuzulassen auf den wahren Wert von errorlevel über die Umgebungsvariable %errorlevel%.

899
Samuel Renkert

Das Testen von ErrorLevel funktioniert für Konsolenanwendungen , aber wie unter von dmihailesc angedeutet, funktioniert dies nicht, wenn Sie versuchen, eine auszuführen Fensteranwendung (z. B. Win32-basiert) über eine Eingabeaufforderung. Eine fenstergesteuerte Anwendung wird im Hintergrund ausgeführt und die Steuerung kehrt sofort zur Eingabeaufforderung zurück (höchstwahrscheinlich mit einem ErrorLevel von Null, um anzuzeigen, dass der Prozess erfolgreich erstellt wurde ). Wenn eine Anwendung mit Fenster beendet wird, geht ihr Beendigungsstatus verloren.

Anstatt den an anderer Stelle erwähnten konsolenbasierten C++ - Launcher zu verwenden, besteht eine einfachere Alternative darin, eine fenstergesteuerte Anwendung mit dem Befehl START /WAIT der Eingabeaufforderung zu starten. Dadurch wird die Anwendung mit Fenster gestartet, gewartet, bis sie beendet ist, und anschließend die Steuerung an den Befehl Eingabeaufforderung mit dem Beendigungsstatus des in ErrorLevel festgelegten Prozesses zurückgegeben.

start /wait something.exe
echo %errorlevel%
239
Gary

Verwenden Sie die integrierte ERRORLEVEL-Variable:

echo %ERRORLEVEL%

Aber Vorsicht, wenn eine Anwendung eine Umgebungsvariable mit dem Namen ERRORLEVEL definiert hat !

94
Adam Rosenfield

Wenn Sie den Fehlercode genau zuordnen möchten (z. B. gleich 0), verwenden Sie Folgendes:

@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 stimmt mit errorlevel> = 0 überein. Siehe if /?.

20
Curtis Yallop

Es funktioniert möglicherweise nicht richtig, wenn Sie ein Programm verwenden, das nicht an die Konsole angeschlossen ist, da diese App möglicherweise noch ausgeführt wird, während Sie glauben, den Beendigungscode zu haben. Eine Lösung dafür in C++ sieht wie folgt aus:

#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;
}
14
dmihailescu

Es ist erwähnenswert, dass .BAT- und .CMD-Dateien unterschiedlich funktionieren.

Lesen https://ss64.com/nt/errorlevel.html stellt Folgendes fest:

Es gibt einen wesentlichen Unterschied zwischen der Art und Weise, wie .CMD- und .BAT-Batchdateien Fehlerlevel setzen:

Ein altes .BAT-Stapelskript, das die 'neuen' internen Befehle ausführt: APPEND, ASSOC, PATH, Prompt, FTYPE und SET setzt ERRORLEVEL nur, wenn ein Fehler auftritt. Wenn Sie also zwei Befehle im Stapelskript haben und der erste fehlschlägt, bleibt der ERRORLEVEL-Wert auch dann gesetzt, wenn der zweite Befehl erfolgreich ausgeführt wurde.

Dies kann das Debuggen eines problematischen BAT-Skripts erschweren, ein CMD-Batch-Skript ist konsistenter und setzt ERRORLEVEL nach jedem Befehl, den Sie [source] ausführen.

Dies bereitete mir große Sorgen, als ich aufeinanderfolgende Befehle ausführte, aber der ERRORLEVEL blieb auch im Falle eines Fehlers unverändert.

6
RockDoctor

Zu einem bestimmten Zeitpunkt musste ich Protokollereignisse von Cygwin in das Windows-Ereignisprotokoll übertragen. Ich wollte, dass die Nachrichten in WEVL benutzerdefiniert sind, den richtigen Beendigungscode, Details, Prioritäten, Nachrichten usw. haben. Deshalb habe ich ein kleines Bash-Skript erstellt, um dies zu beheben. Hier ist es auf GitHub, logit.sh .

Einige Auszüge:

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"

Hier ist der Inhalt der temporären Datei:

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"

Hier ist eine Funktion zum Erstellen von Ereignissen in 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
}

Ausführen des Batch-Skripts und Aufrufen von __create_event:

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