2011-07-29 36 views
6

Xem xét việc này (điển hình) bash script:Tăng dần biến gây nên EXIT trong bash 4, nhưng không phải trong bash 3

#!/bin/bash -e 
errorExit() { 
    echo "" >&2 
    echo "ERROR (${var_scriptfilename}):" >&2 
    echo "An unhandled error occurred." >&2 
    intentionalExit 1 
} 
intentionalExit() { 
    trap - EXIT # Unregister the EXIT trap 
    exit $1 
} 
trap errorExit EXIT # Trap script errors 
var_scriptfilename="$(basename "$0")" 
# ==== START OF TEST ==== 
var_counter=0 
((var_counter++)) 
echo "var_counter is $var_counter" >&2 
# ===== END OF TEST ===== 
intentionalExit 0 

Nếu tôi chạy nó trong bash Cygwin của nó tạo ra sản lượng dự kiến:

var_counter is 1 

Tuy nhiên, nếu tôi chạy nó trên hộp Bóp Debian của tôi, đó là nơi dự định của mình, tôi kết thúc trong cái bẫy EXIT:

ERROR (test.increment.sh): 
An unhandled error occurred. 

... Tại sao vậy?

Nếu tôi xóa tùy chọn -e, nó hoạt động như mong đợi trên cả hai hệ thống, nhưng tôi muốn giữ nguyên sử dụng, rõ ràng.

Biến thể "phổ quát" hơi cồng kềnh hơn, var_counter=$(($var_counter+1)), hoạt động với -e được đặt trên cả hai vỏ, nhưng tôi muốn sử dụng ký hiệu đầu tiên (hoặc cái gì đó tương tự) vì nó rõ ràng là một thao tác tăng khi đọc mã.

bash --version trên bash Cygwin nói:

GNU bash, version 3.2.51(24)-release (i686-pc-cygwin) 
Copyright (C) 2007 Free Software Foundation, Inc. 

trên Debian, đó là:

GNU bash, Version 4.1.5(1)-release (x86_64-pc-linux-gnu) 
Copyright (C) 2009 Free Software Foundation, Inc. 

Tôi tò mò là tại sao đây là như vậy. Có ai biết nguyên nhân của hành vi này không?

Ngoài ra, không ai biết cách tương tự để tăng biến trong bash mà tôi có thể sử dụng?

+1

bạn có thấy điều gì hữu ích khi bạn 'đặt -vx' không? Chúc may mắn. – shellter

Trả lời

9

Từ manpage bash4 trên Debian:

((expression)) 
    The expression is evaluated according to the rules described 
    below under ARITHMETIC EVALUATION. If the value of the expres‐ 
    sion is non-zero, the return status is 0; otherwise the return 
    status is 1. This is exactly equivalent to let "expression". 

và cũng ...

-e  Exit immediately if a pipeline (which may consist of a 
     single simple command), a subshell command enclosed in 
     parentheses, or one of the commands executed as part of 
     a command list enclosed by braces (see SHELL GRAMMAR 
     above) exits with a non-zero status. 

Vì vậy, những gì đang xảy ra là ((var++)) increments var 0-1 và trả 0, làm cho tổng thể biểu thức để trả về khác 0, kích hoạt errexit.

Bây giờ cho sự khác biệt giữa hai phiên bản bash khác nhau: thay đổi này trong hành vi (( dường như đã xảy ra giữa 4.0 và 4.1. Trong 4.0 (( dường như không kích hoạt errexit. Hãy xem tập tin này NEWS để biết chi tiết. Bạn sẽ phải cuộn xuống dòng 135 hoặc hơn. Changelog từ nguồn phân phối dường như xác nhận điều này.

Nếu bạn chỉ muốn biến tăng lên mà không sử dụng trạng thái thoát, có nhiều cách để thực hiện.Có lẽ một số người khác có thể đưa ra lời khuyên trên đó là tốt nhất, nhưng một số khả năng như sau:

  • var="$((var+1))", POSIX di sh phương pháp
  • ((var++)) || true, buộc báo cáo kết quả luôn luôn có một trạng thái thoát zero (bash chỉ)
+0

Cảm ơn bạn rất nhiều, điều đó chắc chắn làm sáng tỏ rất nhiều điều đó. Tôi thấy rằng EXIT chỉ được gọi vì tôi bắt đầu đếm từ 0, tôi có thể sử dụng tiền gia tăng thay vì tăng sau, tức là '((++ var_counter))' thay vì '((var_counter ++))'. Kết quả của phép tính sau đó bắt đầu từ 1 và giá trị trả về sẽ luôn bằng không. Tôi đã thử nghiệm thành công điều này trên cả hai vỏ đã đề cập bây giờ. – eomanis

+1

giải thích tốt. làm thế nào để $ ((và (khác nhau? –

+2

@ FelipeAlvarez '(())' là một lệnh độc lập, giống như thực hiện một câu lệnh trong các ngôn ngữ lập trình khác '((2 + 2))' sẽ chạy, trả về 0 cho '$ (())' là một mở rộng - các kết quả của biểu thức được chèn trở lại vào dòng lệnh thay cho biểu thức '$ (())'. Nó thường được sử dụng như là một phần của dòng lệnh dài hơn. – jw013