Có bất kỳ mã trạng thái thoát tiêu chuẩn trong Linux?


308

Một quy trình được coi là đã hoàn thành chính xác trong Linux nếu trạng thái thoát của nó là 0.

Tôi đã thấy rằng các lỗi phân đoạn thường dẫn đến trạng thái thoát là 11, mặc dù tôi không biết liệu đây chỉ là quy ước nơi tôi làm việc (các ứng dụng thất bại như thế đều là nội bộ) hoặc là một tiêu chuẩn.

Có mã thoát tiêu chuẩn cho các quy trình trong Linux không?


6
nếu bạn đang tìm kiếm thứ gọi là "số lỗi hệ thống" được trả về bởi các chức năng hệ thống, hãy xem tại đây tại errno
marinara

Câu trả lời:


86

8 bit của mã trả về và 8 bit của số tín hiệu tiêu diệt được trộn lẫn thành một giá trị duy nhất khi trả về từ wait(2)& co. .

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <signal.h>

int main() {
    int status;

    pid_t child = fork();
    if (child <= 0)
        exit(42);
    waitpid(child, &status, 0);
    if (WIFEXITED(status))
        printf("first child exited with %u\n", WEXITSTATUS(status));
    /* prints: "first child exited with 42" */

    child = fork();
    if (child <= 0)
        kill(getpid(), SIGSEGV);
    waitpid(child, &status, 0);
    if (WIFSIGNALED(status))
        printf("second child died with %u\n", WTERMSIG(status));
    /* prints: "second child died with 11" */
}

Làm thế nào để bạn xác định trạng thái thoát? Theo truyền thống, shell chỉ lưu trữ mã trả về 8 bit, nhưng đặt bit cao nếu quá trình bị chấm dứt bất thường.

$ sh -c 'thoát 42'; tiếng vang $?
42
$ sh -c 'giết -SEGV $$'; tiếng vang $?
Lỗi phân đoạn
139
$ expr 139 - 128
11

Nếu bạn thấy bất cứ điều gì khác ngoài điều này, thì chương trình có thể có SIGSEGVtrình xử lý tín hiệu mà sau đó gọi exitbình thường, vì vậy nó không thực sự bị tín hiệu giết chết. (Các chương trình có thể chọn xử lý bất kỳ tín hiệu nào ngoài SIGKILLSIGSTOP.)


8
Theo cách mà câu hỏi bây giờ xuất hiện, đây dường như không phải là câu trả lời hữu ích nhất (và do đó được chấp nhận).
David J.

332

Phần 1: Hướng dẫn viết kịch bản Bash nâng cao

Như mọi khi, Hướng dẫn lập trình Bash nâng caothông tin tuyệt vời : (Điều này đã được liên kết trong một câu trả lời khác, nhưng với một URL không chính tắc.)

1: Catchall cho các lỗi chung
2: Sử dụng sai các nội dung shell (theo tài liệu Bash)
126: Lệnh được gọi không thể thực thi
127: "không tìm thấy lệnh"
128: Đối số không hợp lệ để thoát
128 + n: Tín hiệu lỗi nghiêm trọng "n"
255: Thoát trạng thái ngoài phạm vi (thoát chỉ lấy các số nguyên trong phạm vi 0 - 255)

Phần 2: sysexits.h

Các tài liệu tham khảo ABSG sysexits.h.

Trên Linux:

$ find /usr -name sysexits.h
/usr/include/sysexits.h
$ cat /usr/include/sysexits.h

/*
 * Copyright (c) 1987, 1993
 *  The Regents of the University of California.  All rights reserved.

 (A whole bunch of text left out.)

#define EX_OK           0       /* successful termination */
#define EX__BASE        64      /* base value for error messages */
#define EX_USAGE        64      /* command line usage error */
#define EX_DATAERR      65      /* data format error */
#define EX_NOINPUT      66      /* cannot open input */    
#define EX_NOUSER       67      /* addressee unknown */    
#define EX_NOHOST       68      /* host name unknown */
#define EX_UNAVAILABLE  69      /* service unavailable */
#define EX_SOFTWARE     70      /* internal software error */
#define EX_OSERR        71      /* system error (e.g., can't fork) */
#define EX_OSFILE       72      /* critical OS file missing */
#define EX_CANTCREAT    73      /* can't create (user) output file */
#define EX_IOERR        74      /* input/output error */
#define EX_TEMPFAIL     75      /* temp failure; user is invited to retry */
#define EX_PROTOCOL     76      /* remote error in protocol */
#define EX_NOPERM       77      /* permission denied */
#define EX_CONFIG       78      /* configuration error */

#define EX__MAX 78      /* maximum listed value */

5
Lưu ý rằng trong một số hương vị của unix, một số lệnh sử dụng trạng thái thoát là 2 để chỉ ra những thứ khác. Chẳng hạn, nhiều triển khai của grep sử dụng trạng thái thoát là 2 để chỉ ra lỗi và sử dụng trạng thái thoát là 1 để có nghĩa là không tìm thấy dòng nào được chọn.
NamshubWriter

3
Trên BSD có một trang người đàn ông tóm tắt thông tin từ sysexits.h:man sysexits
georgebrock

6
Những gì @NamshubWriter đã nói. Thoát trạng thái 2 là hướng đi chung cho việc sử dụng dòng lệnh không chính xác trong các tiện ích Unix, không chỉ trong "một số hương vị của unix" mà nói chung. Tiêu đề hiển thị trong câu trả lời này không phản ánh các quy ước thực tế, bây giờ hoặc khi nó được viết vào năm 1987.
alexis

ABS không "tuyệt vời". Xin vui lòng đọc lên về chủ đề này; chính xác là không khó để tìm thấy những lời chỉ trích.
tripleee

Nhưng mã nguồn chính thức thực sự ở sysexits.hđâu? Các trang người đàn ông tất cả mọi người giữ tham chiếu chỉ là văn xuôi. Ví dụ, nó tham chiếu EX_OKnhưng không thực sự định nghĩa nó theo cách quy chuẩn như các mã khác. Có nhiều thứ còn thiếu?
Garret Wilson

71

'1' >>> Catchall cho các lỗi chung

'2' >>> Sử dụng sai nội dung shell (theo tài liệu của Bash)

'126' >>> Lệnh được gọi không thể thực thi

'127' >>> "không tìm thấy lệnh"

'128' >>> Đối số không hợp lệ để thoát

'128 + n' >>> Tín hiệu lỗi nghiêm trọng "n"

'130' >>> Tập lệnh bị chấm dứt bởi Control-C

'255' >>> Thoát trạng thái ra khỏi phạm vi

Đây là cho bash. Tuy nhiên, đối với các ứng dụng khác, có các mã thoát khác nhau.


1
Có vẻ như cả hai bạn đã trả lời trong cùng một phút. Tian sẽ phải khá nhanh chóng để xem các liên kết của bạn và dán chúng vào.
Nathan Fellman

6
Lưu ý rằng 'control-C mang lại 130' phù hợp với '128 + n' cho tín hiệu n; control-C tạo SIGINT là tín hiệu 2.
Jonathan Leffler

3
Điều này dường như được đạo văn từ ABS mà không có sự ghi nhận. (Chúng tôi có thể biết vì ABS chứa thông tin không chính xác hoặc ít nhất là sai lệch.)
tripleee

4
Đây là các mã thoát RESERVED, theo Hướng dẫn Bash-Scripting nâng cao . Điều đó có nghĩa là các giá trị này do đó nên tránh cho các tham số thoát do người dùng chỉ định .
trong

53

Không có câu trả lời cũ nào mô tả chính xác trạng thái thoát 2. Trái với những gì họ yêu cầu, trạng thái 2 là những gì tiện ích dòng lệnh của bạn thực sự trả về khi được gọi không đúng cách. (Vâng, một câu trả lời có thể là chín tuổi, có hàng trăm lượt upvote, và vẫn sai.)

Đây là quy ước trạng thái thoát thực sự lâu dài để chấm dứt bình thường, tức là không phải bằng tín hiệu:

  • Thoát trạng thái 0: thành công
  • Thoát trạng thái 1: "thất bại", như được xác định bởi chương trình
  • Thoát trạng thái 2: lỗi sử dụng dòng lệnh

Ví dụ, difftrả về 0 nếu các tệp mà nó so sánh giống hệt nhau và 1 nếu chúng khác nhau. Theo quy ước lâu dài, các chương trình unix trả về trạng thái thoát 2 khi được gọi không chính xác (tùy chọn không xác định, số lượng đối số sai, v.v.) Ví dụ diff -N, grep -Yhoặc diff a b ctất cả sẽ dẫn đến$? việc được đặt thành 2. Đây là và đã được thực hiện kể từ khi Những ngày đầu của Unix vào những năm 1970.

Các câu trả lời được chấp nhận giải thích những gì xảy ra khi một lệnh được chấm dứt bởi một tín hiệu. Tóm lại, chấm dứt do tín hiệu chưa được phát hiện dẫn đến trạng thái thoát 128+[<signal number>. Ví dụ, chấm dứt bởi SIGINT( tín hiệu 2 ) dẫn đến trạng thái thoát 130.

Ghi chú

  1. Một số câu trả lời xác định trạng thái thoát 2 là "Sử dụng sai các nội dung bash". Điều này chỉ áp dụng khi bash (hoặc tập lệnh bash) thoát với trạng thái 2. Hãy coi đó là trường hợp đặc biệt của lỗi sử dụng không chính xác.

  2. Trong sysexits.h, được đề cập trong câu trả lời phổ biến nhất , trạng thái thoát EX_USAGE("lỗi sử dụng dòng lệnh") được xác định là 64. Nhưng điều này không phản ánh đúng thực tế: Tôi không biết bất kỳ tiện ích Unix phổ biến nào trả về 64 khi gọi không chính xác (ví dụ chào mừng ). Đọc kỹ mã nguồn cho thấy đó sysexits.hlà khát vọng, chứ không phải là sự phản ánh của việc sử dụng thực sự:

     *    This include file attempts to categorize possible error
     *    exit statuses for system programs, notably delivermail
     *    and the Berkeley network.
    
     *    Error numbers begin at EX__BASE [64] to reduce the possibility of 
     *    clashing with oth­er exit statuses that random programs may 
     *    already return. 
    

    Nói cách khác, những định nghĩa này không phản ánh thực tiễn phổ biến tại thời điểm đó (1993) nhưng cố tình không tương thích với nó. Đáng tiếc hơn.


Những gì nên quay trở lại chương trình khi nó không xử lý chấm dứt bằng cách bắt SIGINT / Ctrl-C? Vẫn là 130? Có sử dụng một vỏ khác ngoài vấn đề bash?
Gringo Suave

1
Shell đang thực hiện chương trình là không liên quan; về mặt lý thuyết, một quy trình có thể chọn thoát với trạng thái khác nhau tùy thuộc vào quy trình mẹ của nó, nhưng tôi chưa bao giờ nghe về trường hợp điều này xảy ra.
alexis

1
Nếu một chương trình bắt SIGINT, dọn dẹp và thoát ra bằng mọi cách, trạng thái là bất cứ điều gì có ý nghĩa cho chương trình. Ví dụ: moresẽ đặt lại các chế độ đầu cuối và thoát với trạng thái 0 (bạn có thể thử nó).
alexis

1
Câu trả lời này hàm ý mức độ tiêu chuẩn hóa cao hơn nhiều so với thực tế. Không có tiêu chuẩn hóa phù hợp về ý nghĩa của giá trị 2, và thực tế sau đó được dự đoán là rất hỗn hợp. Đúng là nhiều công cụ trả về 2 cho việc sử dụng không đúng nhưng nó không được xác định chính xác "sử dụng không đúng" nghĩa là gì và nhiều công cụ khác không tuân thủ quy ước này.
tripleee

@tripleee "công cụ" cũng không được xác định rõ! :-) Chắc chắn, bất kỳ ai cũng có thể viết chương trình dòng lệnh và nó có thể trả về mọi thứ, nhưng "tiện ích dòng lệnh Unix" cũ đã tồn tại lâu hơn Linux, hoặc nội dung của GNU coreutils, khá nhất quán về điều này. Nếu bạn nghĩ khác, vui lòng đặt tên cho một số công cụ trong nhóm này không sử dụng trạng thái 2 theo cách này. Ngoài ra, "sử dụng không đúng cách" là thuật ngữ của bạn (và tôi đồng ý đó là một thuật ngữ mơ hồ); Tôi đã viết "lỗi sử dụng dòng lệnh", khá cụ thể: các tùy chọn không tồn tại hoặc không tương thích, sai số lượng đối số không phải tùy chọn, v.v.
alexis

25

Không có mã thoát tiêu chuẩn, ngoài 0 có nghĩa là thành công. Không khác không nhất thiết có nghĩa là thất bại.

stdlib.h không định nghĩa EXIT_FAILURElà 1 và EXIT_SUCCESS0, nhưng đó là về nó.

Số 11 trên segfault rất thú vị, vì 11 là số tín hiệu mà kernel sử dụng để giết tiến trình trong trường hợp segfault. Có khả năng một số cơ chế, trong kernel hoặc trong shell, dịch nó thành mã thoát.


20

sysexits.h có một danh sách các mã thoát tiêu chuẩn. Nó dường như có từ ít nhất năm 1993 và một số dự án lớn như Postfix sử dụng nó, vì vậy tôi tưởng tượng đó là cách để đi.

Từ trang người đàn ông OpenBSD:

Theo phong cách (9), sẽ không tốt khi gọi lối ra (3) với các giá trị tùy ý để chỉ ra tình trạng lỗi khi kết thúc chương trình. Thay vào đó, nên sử dụng mã thoát được xác định trước từ sysexits, vì vậy người gọi quy trình có thể có được ước tính sơ bộ về lớp lỗi mà không cần tra cứu mã nguồn.

8

Với một xấp xỉ đầu tiên, 0 là thành công, khác không là thất bại, với 1 là thất bại chung và bất cứ điều gì lớn hơn một là một thất bại cụ thể. Ngoài các trường hợp ngoại lệ tầm thường về sai và kiểm tra, cả hai đều được thiết kế để đưa ra 1 cho thành công, có một vài trường hợp ngoại lệ khác mà tôi tìm thấy.

Thực tế hơn, 0 có nghĩa là thành công hoặc có thể thất bại, 1 có nghĩa là thất bại chung hoặc có thể thành công, 2 có nghĩa là thất bại chung nếu cả 1 và 0 đều được sử dụng cho thành công, nhưng cũng có thể thành công.

Lệnh diff cho 0 nếu các tệp được so sánh là giống hệt nhau, 1 nếu chúng khác nhau và 2 nếu nhị phân khác nhau. 2 cũng có nghĩa là thất bại. Lệnh less đưa ra 1 cho thất bại trừ khi bạn không cung cấp đối số, trong trường hợp đó, nó thoát 0 mặc dù thất bại.

Lệnh nhiều hơn và lệnh chính tả cung cấp 1 cho thất bại, trừ khi thất bại là kết quả của sự cho phép bị từ chối, tệp không tồn tại hoặc cố gắng đọc một thư mục. Trong bất kỳ trường hợp nào, chúng thoát 0 mặc dù không thành công.

Sau đó, lệnh expr cho 1 cho thành công trừ khi đầu ra là chuỗi rỗng hoặc 0, trong trường hợp này, 0 là thành công. 2 và 3 là thất bại.

Sau đó, có những trường hợp thành công hay thất bại là mơ hồ. Khi grep không tìm thấy mẫu, nó sẽ thoát 1, nhưng nó thoát 2 vì lỗi chính hãng (như quyền bị từ chối). Klist cũng thoát 1 khi không tìm được vé, mặc dù điều này thực sự không phải là một thất bại nữa so với khi grep không tìm thấy một mẫu hoặc khi bạn là một thư mục trống.

Vì vậy, thật không may, các quyền hạn unix dường như không thực thi bất kỳ bộ quy tắc logic nào, ngay cả trên các tệp thực thi được sử dụng rất phổ biến.


Tôi cũng sắp chỉ ra hành vi của diff. wget cũng có lỗi chi tiết (ví dụ 6 cho lỗi xác thực), nhưng sau đó họ sử dụng 1 = lỗi chung, 2..n = lỗi cụ thể
PypeBros

5

Các chương trình trả về mã thoát 16 bit. Nếu chương trình bị giết với tín hiệu thì byte thứ tự cao chứa tín hiệu được sử dụng, nếu không, byte thứ tự thấp là trạng thái thoát được trả về bởi lập trình viên.

Làm thế nào mã thoát đó được gán cho biến trạng thái $? sau đó lên đến vỏ. Bash giữ 7 bit thấp hơn của trạng thái và sau đó sử dụng 128 + (signal nr) để biểu thị tín hiệu.

Quy ước "tiêu chuẩn" duy nhất cho các chương trình là 0 cho thành công, khác không cho lỗi. Một quy ước khác được sử dụng là trả về errno khi có lỗi.


3

Mã thoát Unix tiêu chuẩn được xác định bởi sysexits.h, như một poster khác được đề cập. Các mã thoát tương tự được sử dụng bởi các thư viện di động như Poco - đây là danh sách của chúng:

http://pocoproject.org/docs/Poco.Util.Application.html#16218

Tín hiệu 11 là tín hiệu SIGSEGV (vi phạm phân đoạn), khác với mã trả về. Tín hiệu này được tạo bởi kernel để đáp ứng với truy cập trang xấu, khiến chương trình chấm dứt. Một danh sách các tín hiệu có thể được tìm thấy trong trang man tín hiệu (chạy "tín hiệu man").


1

Khi Linux trả về 0, điều đó có nghĩa là thành công. Bất cứ điều gì khác có nghĩa là thất bại, mỗi chương trình có mã thoát riêng, vì vậy sẽ khá lâu để liệt kê tất cả ...!

Về 11 mã lỗi, thực sự là số lỗi phân đoạn, chủ yếu có nghĩa là chương trình đã truy cập một vị trí bộ nhớ không được chỉ định.


1
Nó luôn luôn là 11 bởi vì kernel giết nó và gán "giá trị thoát". Tương tự, các loại Lỗi khác sẽ luôn có cùng giá trị thoát.
Alex Gartrell
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.