it-swarm-vi.com

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

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?

708
Skrud

Biến môi trường giả có tên errorlevel lưu mã thoát:

echo Exit Code is %errorlevel%

Ngoài ra, lệnh if 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 giá trị thực của errorlevel thông qua biến môi trường %errorlevel%.

863
Samuel Renkert

Kiểm tra ErrorLevel hoạt động cho console ứng dụng, nhưng như được gợi ý tại bởi dmihailescu , điều này sẽ không hoạt động nếu bạn đang cố chạy windowed application (ví dụ: dựa trên Win32 ) từ một lệnh Nhắc. Một ứng dụng có cửa sổ sẽ chạy trong nền và điều khiển sẽ ngay lập tức trở lại lệnh Prompt (rất có thể với ErrorLevel bằng 0 để chỉ ra rằng quá 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 lệnh START /WAIT của Prompt. Điều này sẽ khởi động ứng dụng cửa sổ, đợi cho nó thoát, sau đó trả lại quyền điều khiển cho lệnh Nhắc với trạng thái thoát của quy trình được đặt trong ErrorLevel.

start /wait something.exe
echo %errorlevel%
227
Gary
92
Adam Rosenfield

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 0 khớp với errorlevel> = 0. Xem if /?.

18
Curtis Yallop

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

Đ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 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.

5
RockDoctor

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. Đâ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
0
jonretting