Sử dụng hủy đặt so với đặt biến thành trống


108

Tôi hiện đang viết một khung thử nghiệm bash, trong đó trong một hàm thử nghiệm, [[có thể sử dụng cả các thử nghiệm bash tiêu chuẩn ( ) cũng như các trình so khớp được xác định trước. Đối sánh là trình bao bọc thành '[[' và bên cạnh việc trả về mã trả lại, hãy đặt một số thông báo có ý nghĩa cho biết những gì được mong đợi.

Thí dụ:

string_equals() {
    if [[ ! $1 = $2 ]]; then
            error_message="Expected '$1' to be '$2'."

            return 1
    fi
}

Vì vậy, khi một trình so khớp được sử dụng và nó không thành công, thì chỉ khi đó error_message mới được đặt.

Bây giờ, tại một số thời điểm sau đó, tôi kiểm tra xem các thử nghiệm có thành công hay không. Nếu nó thành công, tôi in kỳ vọng màu xanh lá cây, nếu nó không thành công màu đỏ.

Hơn nữa, có thể có một bộ error_message, vì vậy tôi kiểm tra nếu có một thông báo tồn tại, hãy in nó và sau đó hủy đặt nó (vì kiểm tra sau có thể không đặt một error_message):

if [[ $error_message ]]; then
    printf '%s\n' "$error_message"

    unset -v error_message
fi

Bây giờ câu hỏi của tôi là, nếu tốt hơn là bỏ đặt biến hoặc chỉ đặt nó thành '', như

error_message=''

Cái nào tốt hơn? Nó thực sự tạo ra sự khác biệt? Hoặc có lẽ tôi nên có một cờ bổ sung cho biết rằng thông báo đã được đặt?


1
Nếu bạn không bao giờ so sánh error_messagevới bất cứ điều gì khác, tôi sẽ nói rằng nó không quan trọng. Tuy nhiên, tôi nghĩ bạn muốn [[ $error_message ]], nếu không, bạn đang kiểm tra xem chuỗi chữ "error_message" có tồn tại hay không.
chepner

@chepner Vâng, là một lỗi đánh máy. Đã sửa nó.
helpermethod

Câu trả lời:


143

Hầu như bạn không thấy sự khác biệt, trừ khi bạn đang sử dụng set -u:

/home/user1> var=""
/home/user1> echo $var

/home/user1> set -u
/home/user1> echo $var

/home/user1> unset var
/home/user1> echo $var
-bash: var: unbound variable

Vì vậy, thực sự, nó phụ thuộc vào cách bạn sẽ kiểm tra biến.

Tôi sẽ nói thêm rằng cách kiểm tra ưa thích của tôi nếu nó được đặt là:

[[ -n $var ]]  # True if the length of $var is non-zero

hoặc là

[[ -z $var ]]  # True if zero length

43
var=không phải là "không đặt". Nó chỉ là một chuỗi trống không được trích dẫn. Ngoài ra set -u, các dạng mở rộng tham số khác nhau của bash cũng có thể phân biệt giữa giá trị chưa đặt và giá trị null: ${foo:bar}mở rộng thành "bar" khi fookhông được đặt, nhưng "" khi foolà null, trong khi ${foo:-bar}mở rộng thành "thanh" nếu foo chưa được đặt hoặc null.
chepner

1
[[ -n $var ]]là false nếu varđược đặt thành chuỗi trống.
chepner

1
nếu bạn sử dụng 'khai báo -p' để kiểm tra biến 'tồn tại' thì var = sẽ hiển thị 'khai báo - var = ""' bạn phải sử dụng unset để loại bỏ nó, tất nhiên nếu nó là biến chỉ đọc thì bạn không thể nhận được tất nhiên là loại bỏ nó. Hơn nữa, nếu bạn var = một cái gì đó bên trong một hàm, bạn sẽ không phải lo lắng về việc loại bỏ nó nếu bạn sử dụng "local var = value", hãy cẩn thận vì "khai báo var = value" cũng là local. bạn phải đặt rõ ràng nó là toàn cục bằng cách sử dụng "khai báo -g var = giá trị", mà không khai báo, bạn phải đặt rõ ràng nó thành cục bộ bằng cách sử dụng "cục bộ". Global vars chỉ bị xóa / không được đặt.
osirisgothra

@osirisgothra: điểm tốt về các biến cục bộ. Tất nhiên nói chung, tốt nhất là khai báo (hoặc cục bộ hóa) tất cả các biến trong một hàm để nó được đóng gói.
cdarke

3
@chepner nên được ${foo-bar}thay vì ${foo:bar}. kiểm tra cho chính mình:unset a; echo ">${a:-foo}-${a:foo}-${a-foo}<"
Liviu Chircu

17

Như đã nói, việc sử dụng unset cũng khác với các mảng

$ foo=(4 5 6)

$ foo[2]=

$ echo ${#foo[*]}
3

$ unset foo[2]

$ echo ${#foo[*]}
2

2

Vì vậy, bằng cách bỏ đặt chỉ số mảng 2, về cơ bản bạn loại bỏ phần tử đó trong mảng và giảm kích thước mảng (?).

Tôi đã thực hiện bài kiểm tra của riêng mình ..

foo=(5 6 8)
echo ${#foo[*]}
unset foo
echo ${#foo[*]}

Kết quả là ..

3
0

Vì vậy, chỉ để làm rõ rằng việc bỏ đặt toàn bộ mảng trên thực tế sẽ loại bỏ nó hoàn toàn.


0

Dựa trên các nhận xét ở trên, đây là một bài kiểm tra đơn giản:

isunset() { [[ "${!1}" != 'x' ]] && [[ "${!1-x}" == 'x' ]] && echo 1; }
isset()   { [ -z "$(isunset "$1")" ] && echo 1; }

Thí dụ:

$ unset foo; [[ $(isunset foo) ]] && echo "It's unset" || echo "It's set"
It's unset
$ foo=     ; [[ $(isunset foo) ]] && echo "It's unset" || echo "It's set"
It's set
$ foo=bar  ; [[ $(isunset foo) ]] && echo "It's unset" || echo "It's set"
It's set
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.