Saya sedang menulis skrip di Bash untuk menguji beberapa kode. Namun, tampaknya konyol untuk menjalankan tes jika kompilasi kode gagal di tempat pertama, dalam hal ini saya hanya akan membatalkan tes.
Apakah ada cara saya bisa melakukan ini tanpa membungkus seluruh skrip dalam loop sementara dan menggunakan jeda? Sesuatu seperti dun dun dun goto?
1
secara konsisten. Jika skrip dimaksudkan untuk dijalankan oleh skrip lain, Anda mungkin ingin mendefinisikan kumpulan kode status Anda sendiri dengan makna tertentu. Misalnya,1
== tes gagal,2
== kompilasi gagal. Jika skrip adalah bagian dari sesuatu yang lain, Anda mungkin perlu menyesuaikan kode untuk mencocokkan praktik yang digunakan di sana. Misalnya, ketika bagian dari rangkaian uji dijalankan oleh automake, kode77
tersebut digunakan untuk menandai tes yang dilewati.exit #
perintah di dalam suatu fungsi, bukan skrip. (Dalam hal ini digunakanreturn #
sebagai gantinya.)exit 0
keluar dari skrip dan mengembalikan 0 (memberi tahu skrip lain yang mungkin menggunakan hasil skrip ini berhasil)Gunakan set -e
Script akan berakhir setelah baris pertama yang gagal (mengembalikan kode keluar bukan nol). Dalam hal ini, perintah-yang-gagal2 tidak akan berjalan.
Jika Anda memeriksa status pengembalian setiap perintah, skrip Anda akan terlihat seperti ini:
Dengan set -e akan terlihat seperti:
Perintah apa pun yang gagal akan menyebabkan seluruh skrip gagal dan mengembalikan status keluar yang dapat Anda periksa dengan $? . Jika skrip Anda sangat panjang atau Anda sedang membangun banyak hal itu akan menjadi sangat jelek jika Anda menambahkan cek status pengembalian di mana-mana.
sumber
set -e
Anda masih dapat membuat beberapa perintah keluar dengan kesalahan tanpa berhenti script:command 2>&1 || echo $?
.set -e
akan membatalkan skrip jika pipa atau struktur perintah mengembalikan nilai bukan nol. Misalnyafoo || bar
akan gagal hanya jika keduanyafoo
danbar
mengembalikan nilai bukan nol. Biasanya skrip bash yang ditulis dengan baik akan berfungsi jika Anda menambahkanset -e
di awal dan penambahan berfungsi sebagai cek kewarasan otomatis: batalkan skrip jika ada yang salah.set -o pipefail
opsi.set -e
akan adilmake || exit $?
.set -u
. Lihatlah ke tidak resmi modus ketat pesta :set -euo pipefail
.Seorang pria SysOps pernah mengajari saya teknik Three-Fingered Claw:
Fungsi-fungsi ini adalah * NIX OS dan shell-robust. Letakkan di awal skrip Anda (bash atau tidak),
try()
pernyataan dan kode Anda menyalaPenjelasan
(berdasarkan komentar domba terbang ).
yell
: cetak nama skrip dan semua argumen kestderr
:$0
adalah jalan menuju naskah;$*
semua argumen.>&2
berarti>
mengarahkan ulang stdout ke & pipa2
. pipa1
itustdout
sendiri.die
melakukan hal yang sama sepertiyell
, tetapi keluar dengan status keluar non-0 , yang berarti "gagal".try
menggunakan||
(booleanOR
), yang hanya mengevaluasi sisi kanan jika yang kiri gagal.$@
semua argumen lagi, tetapi berbeda .sumber
$0
adalah jalan menuju skrip.$*
semua argumen.>&2
berarti ">
mengarahkan stdout ke&
pipa2
". pipa 1 akan menjadi stdout sendiri. jadi berteriak awalan semua argumen dengan nama skrip dan cetak ke stderr die melakukan hal yang sama dengan berteriak , tetapi keluar dengan status keluar non-0, yang berarti “gagal”. coba gunakan boolean atau||
, yang hanya mengevaluasi sisi kanan jika yang kiri tidak gagal.$@
semua argumen lagi, tetapi berbeda . harapan yang menjelaskan semuanyadie() { yell "$1"; exit $2; }
agar Anda dapat menyampaikan pesan dan keluar dengan kodedie "divide by zero" 115
.yell
dandie
. Namun,try
tidak terlalu banyak. Bisakah Anda memberikan contoh Anda menggunakannya?Jika Anda akan memanggil skrip
source
, Anda dapat menggunakan direturn <x>
mana<x>
status skrip akan keluar (gunakan nilai bukan nol untuk kesalahan atau salah). Tetapi jika Anda menjalankan skrip yang dapat dieksekusi (yaitu, langsung dengan nama filenya), pernyataan kembali akan menghasilkan komplain (pesan kesalahan "kembali: hanya dapat` kembali 'dari suatu fungsi atau skrip bersumber ").Jika
exit <x>
digunakan sebagai gantinya, ketika skrip dipanggil dengansource
, itu akan menghasilkan keluar shell yang memulai skrip, tetapi skrip yang dapat dieksekusi hanya akan berakhir, seperti yang diharapkan.Untuk menangani kedua kasus dalam skrip yang sama, Anda dapat menggunakan
Ini akan menangani permintaan mana saja yang cocok. Itu dengan asumsi Anda akan menggunakan pernyataan ini di tingkat atas skrip. Saya akan menyarankan agar tidak langsung keluar dari skrip dari dalam suatu fungsi.
Catatan:
<x>
seharusnya hanya angka.sumber
Saya sering menyertakan fungsi yang disebut run () untuk menangani kesalahan. Setiap panggilan yang ingin saya lakukan diteruskan ke fungsi ini sehingga seluruh skrip keluar saat kegagalan terjadi. Keuntungan dari solusi set -e ini adalah skrip tidak keluar secara diam-diam ketika sebuah baris gagal, dan dapat memberi tahu Anda apa masalahnya. Pada contoh berikut, baris ke-3 tidak dieksekusi karena skrip keluar saat dipanggil ke false.
sumber
set -e option
. Kemudian perintah, karena dengan argumen, saya menggunakan tanda kutip tunggal untuk menghindari masalah pesta suka begitu:runTry 'mysqldump $DB_PASS --user="$DB_USER" --host="$BV_DB_HOST" --triggers --routines --events --single-transaction --verbose $DB_SCHEMA $tables -r $BACKUP_DIR/$tables$BACKUP_FILE_NAME'
. Catatan saya mengubah nama fungsi menjadi runTry.eval
berpotensi berbahaya jika Anda menerima input sewenang-wenang, tetapi sebaliknya ini terlihat cukup bagus.Alih-alih
if
membangun, Anda dapat meningkatkan evaluasi hubungan pendek :Perhatikan pasangan tanda kurung yang diperlukan karena prioritas operator pergantian.
$?
adalah variabel khusus yang diatur untuk keluar dari kode yang paling terakhir disebut perintah.sumber
command -that --fails || exit $?
tanpa tanda kurung, apaecho $[4/0]
yang menyebabkan kita membutuhkannya?echo $[4/0] || exit $?
) bash tidak akan pernah menjalankanecho
, apalagi mematuhi||
.Saya memiliki pertanyaan yang sama tetapi tidak dapat menanyakannya karena itu merupakan duplikat.
Jawaban yang diterima, menggunakan keluar, tidak berfungsi ketika skrip sedikit lebih rumit. Jika Anda menggunakan proses latar belakang untuk memeriksa kondisi, keluar hanya keluar dari proses itu, karena berjalan dalam sub-shell. Untuk membunuh skrip, Anda harus membunuhnya secara eksplisit (setidaknya itulah satu-satunya cara saya tahu).
Berikut ini adalah skrip kecil tentang cara melakukannya:
Ini adalah jawaban yang lebih baik tetapi masih belum lengkap. Saya benar-benar tidak tahu bagaimana cara menyingkirkan bagian booming .
sumber