Artinya $? (tanda tanya dolar) dalam skrip shell


Jawaban:


212

Ini adalah status keluar dari perintah yang dieksekusi terakhir.

Misalnya perintah trueselalu mengembalikan status 0dan falseselalu mengembalikan status 1:

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

Dari manual: (dapat diakses dengan memanggil man bashshell Anda)

$?       Memperluas status keluar dari pipa latar depan yang baru saja dieksekusi.

Dengan konvensi status keluar 0berarti berhasil, dan status pengembalian tidak nol berarti kegagalan. Pelajari lebih lanjut tentang status keluar di wikipedia .

Ada variabel khusus lain seperti ini, seperti yang dapat Anda lihat di manual online ini: https://www.gnu.org/s/bash/manual/bash.html#Special-Parameters


Catatan $dan ?dua parameter berbeda dan $?tidak muncul di halaman bash (1).
Josh Habdas

19

$?mengembalikan nilai keluar dari perintah yang terakhir dieksekusi. echo $?mencetak nilai itu di konsol. nol menyiratkan eksekusi yang berhasil sementara nilai-nilai yang tidak nol dipetakan ke berbagai alasan kegagalan.

Karena itu ketika scripting; Saya cenderung menggunakan sintaks berikut

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

Perbandingannya harus dilakukan pada sama dengan 0atau tidak sama 0.

** Pembaruan Berdasarkan komentar: Idealnya, Anda tidak boleh menggunakan blok kode di atas untuk perbandingan, lihat komentar @tripleee dan penjelasannya.


15
Tidak, ini adalah antipattern. Apa pun yang terlihat seperti cmd; if [ $? -eq 0 ]; thenharus di refactored if cmd; then. Sangat Tujuan dari if(dan laporan kontrol aliran lainnya di shell) adalah dengan menjalankan perintah dan memeriksa status keluar nya.
tripleee

if cmd;mungkin tidak terlalu mudah dibaca adalah beberapa kondisi terutama ketika cmd merujuk ke skrip lain.
Saurabh Ariyan

1
Ini bahkan lebih salah sekarang. [ 1 ]dan [ 0 ]keduanya benar; [tanpa operator memeriksa apakah argumennya adalah string yang tidak kosong.
tripleee

2
Saya akan melakukannya vendor/bin/drush status bootstrap | grep -q $(vendor/bin/drush php-eval 'if (function_exists("t")) echo t("Successful");') &> /dev/null;. Jika saya harus meletakkannya dalam satu baris, if [ ... ]itu akan sangat tidak dapat dibaca. Saya berencana untuk menyimpan output dari baris itu ke variabel jadi saya bisa katakan if [ $drupal_installed -eq 0 ]nanti.
thirdender

1
@ thirdender Solusi yang tepat untuk itu adalah untuk merangkum tes kompleks dalam fungsi shell.
tripleee

12

echo $? - Memberikan STATUS KELUAR dari perintah yang paling baru dieksekusi . STATUS KELUAR ini kemungkinan besar adalah angka dengan NOL yang menyiratkan Kesuksesan dan nilai NON-ZERO yang mengindikasikan Kegagalan

? - Ini adalah salah satu parameter / variabel khusus dalam bash.

$? - Ini memberi nilai yang disimpan dalam variabel "?".

Beberapa parameter khusus serupa di BASH adalah 1,2, *, # (Biasanya terlihat dalam perintah gema sebagai $ 1, $ 2, $ *, $ #, dll,).



5

Contoh status keluar POSIX C minimal

Untuk memahami $?, Anda harus terlebih dahulu memahami konsep status proses keluar yang ditentukan oleh POSIX . Di Linux:

  • ketika suatu proses memanggil panggilan exitsistem, kernel menyimpan nilai yang diteruskan ke panggilan sistem (an int) bahkan setelah proses mati.

    Sistem exit panggilan disebut dengan exit()fungsi ANSI C, dan secara tidak langsung ketika Anda melakukan returndari main.

  • proses yang disebut proses anak keluar (Bash), sering dengan fork+ exec, dapat mengambil status keluar anak dengan waitpanggilan sistem

Pertimbangkan kode Bash:

$ false
$ echo $?
1

C "setara" adalah:

false.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));
}

Kompilasi dan jalankan:

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

Keluaran:

$? = 1

Di Bash, ketika Anda menekan enter, fork + exec + wait terjadi seperti di atas, dan bash kemudian set $?ke status keluar dari proses bercabang.

Catatan: untuk perintah bawaan seperti echo, suatu proses tidak perlu muncul, dan Bash hanya menetapkan $?ke 0 untuk mensimulasikan proses eksternal.

Standar dan dokumentasi

POSIX 7 2.5.2 "Parameter Khusus" http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_05_02 :

? Perluas ke status keluar desimal dari saluran pipa terbaru (lihat Saluran Pipa).

man bash "Parameter Khusus":

Shell memperlakukan beberapa parameter secara khusus. Parameter ini hanya dapat dirujuk; penugasan kepada mereka tidak diizinkan. [...]

? Memperluas status keluar dari pipa latar depan yang baru saja dieksekusi.

ANSI C dan POSIX kemudian merekomendasikan bahwa:

  • 0 berarti programnya berhasil

  • nilai-nilai lain: program gagal entah bagaimana.

    Nilai yang tepat dapat menunjukkan jenis kegagalan.

    ANSI C tidak mendefinisikan arti dari sembarang vaues, dan POSIX menentukan nilai yang lebih besar dari 125: Apa arti dari "POSIX"?

Bash menggunakan status keluar untuk if

Di Bash, kami sering menggunakan status keluar $?secara implisit untuk mengontrol ifpernyataan seperti pada:

if true; then
  :
fi

di mana trueprogram yang baru saja mengembalikan 0.

Di atas setara dengan:

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

Dan masuk:

if [ 1 = 1 ]; then
  :
fi

[hanyalah sebuah program dengan nama aneh (dan Bash built-in yang berperilaku seperti itu), dan 1 = 1 ]argumennya, lihat juga: Perbedaan antara tanda kurung kotak tunggal dan ganda di Bash




2

Output hasil dari perintah unix yang terakhir dieksekusi

0 implies true
1 implies false
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.