Cara memeriksa status keluar menggunakan pernyataan if

256

Saya bertanya-tanya apa yang akan menjadi cara terbaik untuk memeriksa status keluar dalam pernyataan if untuk menggemakan output tertentu.

Saya sedang memikirkan itu

if [ $? -eq 1 ]
then
   echo "blah blah blah"
fi

Masalah saya juga adalah bahwa pernyataan keluar sebelum pernyataan if hanya karena harus memiliki kode keluar itu. Juga, saya tahu saya melakukan sesuatu yang salah karena keluar jelas akan keluar dari program.

deadcell4
sumber
3
Pla memposting skrip lengkap Anda (atau setidaknya ruang lingkup yang lebih luas). Kalau tidak, ini sepertinya baik-baik saja.
RedX
5
Jika Anda perlu menggunakan kode keluar dari beberapa pemanggilan program tertentu di dua tempat yang berbeda, maka Anda harus melestarikannya - sesuatu di sepanjang garissome_program; rc=$?; if [ ${rc} -eq 1 ] .... fi ; exit ${rc}
twalberg

Jawaban:

262

Setiap perintah yang dijalankan memiliki status keluar.

Pemeriksaan itu melihat status keluar dari perintah yang selesai paling baru sebelum baris itu berjalan.

Jika Anda ingin skrip Anda keluar ketika tes itu kembali benar (perintah sebelumnya gagal) maka Anda memasukkan exit 1(atau apa pun) di dalam ifblok itu setelah echo.

Itu dikatakan jika Anda menjalankan perintah dan ingin menguji outputnya menggunakan yang berikut ini sering kali lebih mudah.

if some_command; then
    echo command returned true
else
    echo command returned some error
fi

Atau untuk mengubahnya digunakan !untuk negasi

if ! some_command; then
    echo command returned some error
else
    echo command returned true
fi

Perhatikan bahwa tidak satu pun dari mereka yang peduli tentang kode kesalahan itu. Jika Anda tahu Anda hanya peduli pada kode kesalahan tertentu maka Anda perlu memeriksa $?secara manual.

Etan Reisner
sumber
11
@ deadcell4 Ketika seseorang perlu menghentikan skrip shell pada kegagalan program, idiom berikut bergunaa_command || return 1
gboffi
10
@ gboffi returnhanya berfungsi dalam fungsi dan skrip bersumber. Anda perlu exituntuk kasus lain (yang melakukan terlalu banyak fungsi dan skrip bersumber). Tapi ya, itu pasti pola yang masuk akal jika Anda tidak memerlukan pembersihan khusus atau output tambahan.
Etan Reisner
1
Saya harus mengatakan itu dash , shell non-interaktif default di banyak distribusi linux modern, tidak peduli dengan perbedaan antara returndan exitdi dalam skrip shell yang dieksekusi. dashkeluar dari skrip walaupun saya menggunakannya return.
gboffi
Apa logika di balik dua pemeriksaan terakhir? Tampaknya kontra-intuitif bahwa kondisi if <command>berlalu jika kode keluar adalah 0. Dalam bahasa lain itu akan menjadi sebaliknya
sjw
3
CATATAN PENTING: Ini tidak akan berfungsi untuk pipa. if ! some_command | some_other_commandakan mengabaikan status some_command. Dua penyelesaian perintah yang paling adalah set -o pipefail(dapat mengubah fungsionalitas di bagian lain dari program Anda) atau untuk memindahkan ifpernyataan ke if [[ ${PIPESTATUS[0]} -ne 0 ]]sebagai perintah tindak lanjut yang terpisah (jelek, tetapi fungsional). Jika Anda menggunakanset -e maka Anda juga akan ingin menambahkan || trueke ujung pipa ketika menggunakan solusi kedua karena menghapus pipa dari aliran kontrol yang ditawarkan oleh ifjika tidak akan menyebabkannya untuk segera keluar.
Alex Jansen
186

Perhatikan bahwa kode keluar! = 0 digunakan untuk melaporkan kesalahan. Jadi, lebih baik dilakukan:

retVal=$?
if [ $retVal -ne 0 ]; then
    echo "Error"
fi
exit $retVal

dari pada

# will fail for error codes > 1
retVal=$?
if [ $retVal -eq 1 ]; then
    echo "Error"
fi
exit $retVal
Oo.o
sumber
Anda harus menguji pada retVal, karena $? setelah penugasan retVal bukan nilai balik dari perintah Anda.
anr78
Tidak juga: mywiki.wooledge.org/BashFAQ/002 - namun, saya setuju bahwa pengeditan meningkatkan keterbacaan.
Oo.oO
1
Baru saja menemukan posting ini yang menjelaskannya stackoverflow.com/questions/20157979/...
anr78
dnf check-updatemengembalikan 0 (tidak ada pembaruan), 100 (pembaruan tersedia) atau 1 (kesalahan).
jww
1
@jww - yah, itu bukan ide yang bagus untuk menentang konvensi ( gnu.org/software/bash/manual/html_node/Exit-Status.html ). Tapi, yah, tidak ada yang mencegah hal itu. Jika dnfpengembang memilih cara ini, itu pilihan mereka. Tapi tetap saja, pilihan mereka tidak membuat spesifikasi menjadi rusak :)
Oo.oO
44

$?adalah parameter seperti yang lainnya. Anda dapat menyimpan nilainya untuk digunakan sebelum akhirnya menelepon exit.

exit_status=$?
if [ $exit_status -eq 1 ]; then
    echo "blah blah blah"
fi
exit $exit_status
chepner
sumber
29

Alternatif untuk eksplisit if pernyataan

Minimal:

test $? -eq 0 || echo "something bad happened"

Lengkap:

EXITCODE=$?
test $EXITCODE -eq 0 && echo "something good happened" || echo "something bad happened"; 
exit $EXITCODE
Catskul
sumber
13

Hanya untuk menambah jawaban yang bermanfaat dan terperinci :

Jika Anda harus memeriksa kode keluar secara eksplisit, lebih baik menggunakan operator aritmatika (( ... )),, dengan cara ini:

run_some_command
(($? != 0)) && { printf '%s\n' "Command exited with non-zero"; exit 1; }

Atau, gunakan casepernyataan:

run_some_command; ec=$?  # grab the exit code into a variable so that it can
                         # be reused later, without the fear of being overwritten
case $ec in
    0) ;;
    1) printf '%s\n' "Command exited with non-zero"; exit 1;;
    *) do_something_else;;
esac

Jawaban terkait tentang penanganan kesalahan di Bash:

codeforester
sumber