Làm cách nào để lấy mã thoát ứng dụng từ dòng lệnh Windows?


797

Tôi đang chạy một chương trình và muốn xem mã trả về của nó là gì (vì nó trả về các mã khác nhau dựa trên các lỗi khác nhau).

Tôi biết ở Bash tôi có thể làm điều này bằng cách chạy

tiếng vang $?

Tôi phải làm gì khi sử dụng cmd.exe trên Windows?



1
Googled cho "Win8 Cách nhận dấu nhắc CMD để hiển thị trạng thái thoát" như chúng ta có thể làm trong Linux. Đây là lựa chọn hàng đầu, và là chính xác.
SDsolar

1
Bạn có thể nhanh chóng xem ứng dụng nào trả về:app.exe & echo %errorlevel%
marbel82

Câu trả lời:


976

Một biến môi trường giả có tên errorlevellưu trữ mã thoát:

echo Exit Code is %errorlevel%

Ngoài ra, iflệnh có một cú pháp đặc biệt:

if errorlevel

Xem if /?để biết chi tiết.

Thí dụ

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

Cảnh báo: Nếu bạn đặt tên biến môi trường errorlevel, %errorlevel%sẽ trả về giá trị đó chứ không phải mã thoát. Sử dụng ( set errorlevel=) để xóa biến môi trường, cho phép truy cập vào giá trị thực của errorlevelthông qua %errorlevel%biến môi trường.


38
Nếu bạn đang chạy trực tiếp từ một dòng lệnh Windows và luôn thấy 0 được trả về, hãy xem câu trả lời của Gary: stackoverflow.com/a/11476681/31629
Ken

9
Ngoài ra nếu bạn đang ở trong thế giới quyền lực, bạn có thể sử dụngecho Exit Code is $LastExitCode
Brandon Pugh

11
Lưu ý: "errorlevel 1" là đúng nếu errorlevel> = 1. Vì vậy, "errorlevel 0" sẽ khớp với mọi thứ. Xem "nếu /?". Thay vào đó, bạn có thể sử dụng "if% ERRORLEVEL% THIẾT BỊ 0 (..)".
Curtis Yallop

1
Tìm thấy trường hợp bằng %ERRORLEVEL%0 mặc dù đã xảy ra lỗi. Đã xảy ra khi kiểm tra %ERRORLEVEL%trong một tập tin cmd. Cố gắng start /waitkhông làm việc. Điều duy nhất hiệu quả làif errorlevel 1 (...)
AlikElzin-kilaka

1
Lời khuyên thân thiện:% ErrorLevel% là biến shell, không phải là biến môi trường và nó cũng trả về stringkhông phải là một intnghĩa là bạn không thể sử dụng EQ/ NEQhiệu quả.
kayleeFrye_onDeck

277

Kiểm tra ErrorLevelhoạt động cho các ứng dụng bảng điều khiển , nhưng theo gợi ý của dmihailescu , điều này sẽ không hoạt động nếu bạn đang cố chạy một ứng dụng có cửa sổ (ví dụ dựa trên Win32) từ dấu nhắc lệnh. Một ứng dụng có cửa sổ sẽ chạy trong nền và điều khiển sẽ trở lại ngay lập tức với dấu nhắc lệnh (rất có thể có ErrorLevelsố 0 để chỉ ra rằng quy trình đã được tạo thành công). Khi một ứng dụng cửa sổ cuối cùng thoát ra, trạng thái thoát của nó bị mất.

Tuy nhiên, thay vì sử dụng trình khởi chạy C ++ dựa trên bảng điều khiển được đề cập ở nơi khác, một cách khác đơn giản hơn là khởi động một ứng dụng có cửa sổ bằng cách sử dụng lệnh của dấu nhắc START /WAITlệnh. Điều này sẽ khởi động ứng dụng cửa sổ, đợi cho nó thoát ra và sau đó trả lại quyền điều khiển cho dấu nhắc lệnh với trạng thái thoát của quá trình được đặt trong ErrorLevel.

start /wait something.exe
echo %errorlevel%

20
Cảm ơn rất nhiều về ý tưởng "BẮT ĐẦU / chờ đợi". Điều đó làm việc cho tôi :)
Timotei

3
bắt tốt Tôi không biết về lệnh đó. Tôi vừa thấy nó hoạt động cho> bắt đầu / chờ notepad.exe
dmihailescu

1
Một lý do khác tại sao nó có thể không hoạt động (luôn luôn bằng không) là khi nó nằm trong ifhoặc for. Xem xét sử dụng !errorlevel!thay thế, như được mô tả trong câu trả lời này .
Roman Starkov


23

Nếu bạn muốn khớp chính xác mã lỗi (ví dụ bằng 0), hãy sử dụng:

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

if errorlevel 0khớp errorlevel> = 0. Xem if /?.


Có phải là trường hợp nhạy cảm?
Nishant

1
Số vars, lệnh (bao gồm cả "nếu") và "đẳng" hoạt động bất kể trường hợp nào.
Curtis Yallop

14

Nó có thể không hoạt động chính xác khi sử dụng chương trình không được gắn vào bảng điều khiển, vì ứng dụng đó có thể vẫn đang chạy trong khi bạn nghĩ rằng bạn có mã thoát. Một giải pháp để làm điều đó trong C ++ trông như dưới đây:

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

Trong một số cấu hình, bạn nên thêm #include <atlstr.h> để loại CString được thu lại.
Jake OPJ

8

Điều đáng chú ý là các tệp .BAT và .CMD hoạt động khác nhau.

Đọc https://ss64.com/nt/errorlevel.html nó ghi chú như sau:

Có một sự khác biệt chính giữa cách các tệp bó .CMD và .BAT đặt các lỗi:

Một tập lệnh bó .BAT cũ chạy các lệnh nội bộ 'mới': APPEND, ASSOC, PATH, PROMPT, FTYPE và SET sẽ chỉ đặt ERRORLEVEL nếu xảy ra lỗi. Vì vậy, nếu bạn có hai lệnh trong tập lệnh bó và lần đầu tiên thất bại, ERRORLEVEL sẽ vẫn được đặt ngay cả sau khi lệnh thứ hai thành công.

Điều này có thể làm cho việc gỡ lỗi một tập lệnh BAT trở nên khó khăn hơn, tập lệnh bó CMD phù hợp hơn và sẽ đặt ERRORLEVEL sau mỗi lệnh bạn chạy [nguồn].

Điều này khiến tôi không hết đau buồn khi tôi thực hiện các lệnh liên tiếp, nhưng ERRORLEVEL sẽ không thay đổi ngay cả trong trường hợp thất bại.


0

Tại một thời điểm tôi cần đẩy chính xác các sự kiện nhật ký từ Cygwin sang nhật ký Sự kiện Windows. Tôi muốn các thông điệp trong WEVL được tùy chỉnh, có mã thoát chính xác, chi tiết, ưu tiên, tin nhắn, v.v. Vì vậy, tôi đã tạo một tập lệnh Bash nhỏ để xử lý việc này. Đây là trên GitHub, logit.sh .

Một số trích đoạn:

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"

Đây là phần nội dung tập tin tạm thời:

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"

Đây là một chức năng để tạo các sự kiện trong 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
}

Thực thi tập lệnh bó và gọi vào __create_event:

cmd /c "$(cygpath -wa "$LGT_TEMP_FILE")"
__create_event
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.