Ý nghĩa của $? (dấu hỏi đô la) trong tập lệnh shell


Câu trả lời:


212

Đây là trạng thái thoát của lệnh được thực hiện cuối cùng.

Ví dụ: lệnh trueluôn trả về trạng thái 0falseluôn trả về trạng thái 1:

true
echo $? # echoes 0
false
echo $? # echoes 1

Từ hướng dẫn: (acessible bằng cách gọi man bashtrong vỏ của bạn)

$?       Mở rộng đến trạng thái thoát của đường ống tiền cảnh được thực hiện gần đây nhất.

Theo quy ước, trạng thái thoát 0có nghĩa là thành công và trạng thái trả về khác không có nghĩa là thất bại. Tìm hiểu thêm về trạng thái thoát trên wikipedia .

Có các biến đặc biệt khác như thế này, như bạn có thể thấy trong hướng dẫn trực tuyến này: https://www.gnu.org/s/bash/manual/bash.html# Special- Parameter


Lưu ý $?là hai tham số riêng biệt và $?không xuất hiện trong trang chủ bash (1).
Josh Habdas

19

$?trả về giá trị thoát của lệnh được thực hiện cuối cùng. echo $?in giá trị đó trên bàn điều khiển. zero ngụ ý thực hiện thành công trong khi các giá trị khác không được ánh xạ tới nhiều lý do thất bại.

Do đó khi viết kịch bản; Tôi có xu hướng sử dụng cú pháp sau

if [ $? -eq 0 ]; then
 # do something
else
 # do something else
fi

Việc so sánh sẽ được thực hiện trên bằng 0hoặc không bằng 0.

** Cập nhật Dựa trên nhận xét: Tốt nhất, bạn không nên sử dụng khối mã trên để so sánh, hãy tham khảo ý kiến ​​và giải thích của @tripleee.


15
Không, đây là một antipotype. Bất cứ điều gì trông giống như cmd; if [ $? -eq 0 ]; thennên được tái cấu trúc if cmd; then. Rất Mục đích của if(và các báo cáo kiểm soát dòng chảy khác trong vỏ) là để chạy một lệnh và kiểm tra trạng thái thoát của nó.
tripleee

if cmd;có thể không dễ đọc là một số điều kiện đặc biệt là khi cmd đề cập đến tập lệnh khác.
Saurabh Ariyan

1
Điều này thậm chí còn sai hơn bây giờ. [ 1 ][ 0 ]đều đúng; [không có toán tử kiểm tra nếu đối số là một chuỗi không trống.
tripleee

2
Tôi sắp làm vendor/bin/drush status bootstrap | grep -q $(vendor/bin/drush php-eval 'if (function_exists("t")) echo t("Successful");') &> /dev/null;. Nếu tôi phải đặt nó trong một dòng duy nhất if [ ... ]thì nó sẽ không thể đọc được. Tôi dự định lưu trữ đầu ra của dòng đó vào một biến để tôi có thể nói if [ $drupal_installed -eq 0 ]sau.
thứ

1
@thirdender Giải pháp thích hợp cho việc đó là gói gọn các bài kiểm tra phức tạp trong hàm shell.
tripleee

12

tiếng vang $? - Cung cấp TÌNH TRẠNG EXIT của lệnh được thực hiện gần đây nhất . TÌNH TRẠNG EXIT này rất có thể sẽ là một con số với ZERO ngụ ý Thành công và bất kỳ giá trị NON-ZERO nào cho thấy Thất bại

? - Đây là một tham số / biến đặc biệt trong bash.

$? - Nó cho giá trị được lưu trong biến "?".

Một số tham số đặc biệt tương tự trong BASH là 1,2, *, # (Thường thấy trong lệnh echo là $ 1, $ 2, $ *, $ #, v.v.,).



5

Ví dụ trạng thái thoát POSIX C tối thiểu

Để hiểu $?, trước tiên bạn phải hiểu khái niệm trạng thái thoát quy trình được xác định bởi POSIX . Trong Linux:

  • khi một tiến trình gọi cuộc gọi exithệ thống, hạt nhân lưu trữ giá trị được truyền cho cuộc gọi hệ thống (an int) ngay cả sau khi quá trình chết.

    Cuộc gọi hệ thống thoát được gọi bởi hàm exit()ANSI C và gián tiếp khi bạn thực hiện returntừmain .

  • quá trình được gọi là tiến trình con thoát (Bash), thường với fork+ exec, có thể truy xuất trạng thái thoát của con vớiwait gọi hệ thống

Hãy xem xét mã Bash:

$ false
$ echo $?
1

Chữ "tương đương" là:

sai.c

#include <stdlib.h> /* exit */

int main(void) {
    exit(1);
}

bash.c

#include <unistd.h> /* execl */
#include <stdlib.h> /* fork */
#include <sys/wait.h> /* wait, WEXITSTATUS */
#include <stdio.h> /* printf */

int main(void) {
    if (fork() == 0) {
        /* Call false. */
        execl("./false", "./false", (char *)NULL);
    }
    int status;
    /* Wait for a child to finish. */
    wait(&status);
    /* Status encodes multiple fields,
     * we need WEXITSTATUS to get the exit status:
     * http://stackoverflow.com/questions/3659616/returning-exit-code-from-child
     **/
    printf("$? = %d\n", WEXITSTATUS(status));
}

Biên dịch và chạy:

g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o bash bash.c
g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o false false.c
./bash

Đầu ra:

$? = 1

Trong Bash, khi bạn nhấn enter, một fork + exec + Wait xảy ra như trên và bash sau đó thiết lập $? thành trạng thái thoát của quá trình rẽ nhánh.

Lưu ý: đối với các lệnh dựng sẵn như echo, một quy trình không cần phải được sinh ra và Bash chỉ thiết lập$? thành 0 để mô phỏng quy trình bên ngoài.

Tiêu chuẩn và tài liệu

POSIX 7 2.5.2 "Thông số đặc biệt" http://pub.opengroup.org/onlinepub/9699919799/utilities/V3_chap02.html#tag_18_05_02 :

? Mở rộng đến trạng thái thoát thập phân của đường ống gần đây nhất (xem Đường ống).

man bash "Thông số đặc biệt":

Vỏ xử lý một số thông số đặc biệt. Các thông số này chỉ có thể được tham chiếu; giao cho họ không được phép. [...]

? Mở rộng đến trạng thái thoát của đường ống tiền cảnh được thực hiện gần đây nhất.

ANSI C và POSIX sau đó khuyến nghị rằng:

  • 0 có nghĩa là chương trình đã thành công

  • giá trị khác: chương trình thất bại bằng cách nào đó.

    Giá trị chính xác có thể chỉ ra loại thất bại.

    ANSI C không xác định ý nghĩa của bất kỳ vau nào và POSIX chỉ định các giá trị lớn hơn 125: Ý nghĩa của "POSIX" là gì?

Bash sử dụng trạng thái thoát cho if

Trong Bash, chúng ta thường sử dụng trạng thái thoát $?ngầm để kiểm soát các ifcâu lệnh như trong:

if true; then
  :
fi

trong đó truemột chương trình chỉ trả về 0.

Trên đây là tương đương với:

true
result=$?
if [ $result = 0 ]; then
  :
fi

Và trong:

if [ 1 = 1 ]; then
  :
fi

[chỉ là một chương trình có một cái tên kỳ lạ (và Bash tích hợp hoạt động giống như nó) và 1 = 1 ]các đối số của nó, xem thêm: Sự khác biệt giữa dấu ngoặc đơn và dấu ngoặc kép trong Bash




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.