bash -e keluar ketika let atau expr mengevaluasi ke 0

19

Saya memiliki skrip bash yang menetapkan -e sehingga skrip akan keluar pada status keluar apa pun! = 0.

Saya mencoba untuk melakukan beberapa aritmatika shell dasar yang ditugaskan untuk variabel dan kadang-kadang ekspresi sama dengan 0 yang menyebabkan status keluar dari perintah let atau expr menjadi "1".

Ini sebuah contoh:

#!/bin/bash -ex
echo "Test 1"
Z=`expr 1 - 1` || true
echo "Z will print"
let "A=4 - 4"
echo "A WILL NEVER PRINT $A"
Y=`expr 1 - 1`
echo "Y WILL NEVER PRINT $Y"
X=$(expr 2 - 2)
echo "X WILL NEVER PRINT $X"

Outputnya adalah:

$ ./test_error.sh 
+ echo 'Test 1'
Test 1
++ expr 1 - 1
+ Z=0
+ true
+ echo 'Z will print'
Z will print
+ let 'A=4 - 4'

Pertanyaan saya adalah apa cara scripting bash idiomatik untuk memungkinkan skrip gagal pada kesalahan keluar nyata dan bukan pada aritmatika dasar sama dengan 0. Saya bisa mengakhiri semua ekspresi dengan:

A=`expr $C - $D`    || true

Tapi itu sepertinya berantakan.

Dougnukem
sumber

Jawaban:

16

Jangan gunakan expruntuk aritmatika. Sudah lama usang: shell sekarang memiliki aritmatika bawaan, dengan $((…))konstruk (POSIX), atau dengan letbuiltin (ksh / bash / zsh) atau ((…))konstruk (ksh / bash / zsh).

letdan ((…))kembalikan 1 (kode status kegagalan) jika ekspresi yang terakhir dievaluasi adalah 0. Untuk menghindari ini yang menyebabkan skrip Anda keluar di bawah set -e, atur agar ungkapan terakhir tidak mengembalikan 0, misalnya:

let "a = 2 - 2" 1
((a = 2 - 2, 1))

Atau, gunakan || trueidiom:

((a = 2 - 2)) || true

Atau, lakukan aritmatika Anda di dalam $((…))dan tugas Anda di luar. Suatu tugas mengembalikan status substitusi perintah terakhir dalam nilai, atau 0 jika tidak ada substitusi perintah, sehingga Anda aman. Ini memiliki manfaat tambahan untuk bekerja di shell POSIX (seperti tanda hubung).

a=$((2 - 2))
Gilles 'SANGAT berhenti menjadi jahat'
sumber
1

Gunakan $(( $C - $D ))sebagai gantinya untuk aritmatika Anda. Ini juga lebih efisien.

tylerl
sumber
Apa yang membuatnya lebih efisien daripada mengatakan (( A = $C - $D ))?
Uskup
1

Saya memiliki masalah yang sama . tl; dr:

Jika ARG terakhir [let] mengevaluasi ke 0, biarkan mengembalikan 1; biarkan mengembalikan 0 sebaliknya.

l0b0
sumber
1

Sintaks ini berfungsi untuk saya:

a=$((b + c))
Mark Sawers
sumber