Kiểm tra xem một biến có được đặt trong bash hay không khi sử dụng “set -o danh từ”


95

Đoạn mã sau thoát với lỗi biến không liên kết. Làm thế nào để sửa lỗi này, trong khi vẫn sử dụng set -otùy chọn danh từ?

#!/bin/bash

set -o nounset

if [ ! -z ${WHATEVER} ];
 then echo "yo"
fi

echo "whatever"

Câu trả lời:


98
#!/bin/bash

set -o nounset


VALUE=${WHATEVER:-}

if [ ! -z ${VALUE} ];
 then echo "yo"
fi

echo "whatever"

Trong trường hợp này, VALUEkết thúc là một chuỗi trống nếu WHATEVERkhông được đặt. Chúng tôi đang sử dụng phần {parameter:-word}mở rộng mà bạn có thể tra cứu trong phần man bash"Mở rộng Tham số".


14
chỉ cần thay thế nếu [! -z $ {VALUE}]; với nếu [! -z $ {WHATEVER: -}];
Angelom

18
:-kiểm tra xem biến chưa được đặt hay đang trống. Nếu bạn muốn kiểm tra chỉ cho dù đó là unset, sử dụng -: VALUE=${WHATEVER-}. Ngoài ra, một cách dễ đọc hơn để kiểm tra xem một biến là rỗng:if [ "${WHATEVER+defined}" = defined ]; then echo defined; else echo undefined; fi
l0b0

1
Ngoài ra, điều này sẽ không hoạt động nếu $WHATEVERchỉ chứa khoảng trắng - Hãy xem câu trả lời của tôi.
l0b0

10
Có lý do gì để sử dụng " ! -z" thay vì chỉ " -n" không?
Jonathan Hartley

31

Bạn cần phải trích dẫn các biến nếu bạn muốn nhận được kết quả như mong đợi:

check() {
    if [ -n "${WHATEVER-}" ]
    then
        echo 'not empty'
    elif [ "${WHATEVER+defined}" = defined ]
    then
        echo 'empty but defined'
    else
        echo 'unset'
    fi
}

Kiểm tra:

$ unset WHATEVER
$ check
unset
$ WHATEVER=
$ check
empty but defined
$ WHATEVER='   '
$ check
not empty

Tôi cố gắng này và tôi đang công trình này ngạc nhiên ... Tất cả mọi thứ là chính xác, ngoại trừ theo "info bash", "${WHATEVER-}"nên có một ":"(ruột kết) trước khi "-"(gạch ngang) như: "${WHATEVER:-}", và "${WHATEVER+defined}"nên có một dấu hai chấm trước "+"(cộng) như: "${WHATEVER:+defined}". Đối với tôi, nó hoạt động theo cả hai cách, có hoặc không có dấu hai chấm. Trên một số phiên bản của 'nix, nó có thể sẽ không hoạt động nếu không bao gồm dấu hai chấm, vì vậy nó có thể nên được thêm vào.
Kevin Fegan

8
Nope, -, +, :+, và :-tất cả đều được hỗ trợ. Đầu tiên phát hiện xem biến đã được đặt hay chưa và biến sau phát hiện xem biến đó được đặt hay trống . From man bash: "Việc bỏ qua dấu hai chấm sẽ chỉ dẫn đến kết quả kiểm tra đối với tham số chưa được đặt."
l0b0

1
Đừng bận tâm =). Bạn nói đúng. Tôi không biết làm thế nào tôi đã bỏ lỡ điều đó.
Kevin Fegan

Từ tài liệu : Nói một cách khác, nếu dấu hai chấm được bao gồm, toán tử sẽ kiểm tra sự tồn tại của cả tham số và giá trị của nó không phải là rỗng; nếu dấu hai chấm bị bỏ qua, toán tử chỉ kiểm tra sự tồn tại.
Acumenus

8

Làm thế nào về một tấm lót?

[ -z "${VAR:-}" ] && echo "VAR is not set or is empty" || echo "VAR is set to $VAR"

-z kiểm tra cả biến trống hoặc chưa đặt


2
Không, -zchỉ kiểm tra nếu tham số tiếp theo trống. -zlà chỉ là một đối số của [lệnh. Mở rộng biến xảy ra trước khi [ -zcó thể làm bất cứ điều gì.
dolmen

1
Đây có vẻ là giải pháp chính xác, ở chỗ nó không tạo ra lỗi nếu $ VAR không được đặt. @dolmen, bạn có thể cung cấp một ví dụ về thời điểm nó không hoạt động không?
Chris Stryczynski

@dolmen đã đọc các tài nguyên bash khác nhau về mở rộng tham số và tìm các câu trả lời khác quá phức tạp, tôi không thấy có gì sai với câu này. vì vậy, "làm rõ" của bạn, mặc dù đúng về mặt kỹ thuật, có vẻ khá vô nghĩa trong thực tế, trừ khi bạn cần phân biệt không đặt và trống. Tôi đã thử nghiệm không đặt, trống và không trống, (bash 4) và nó thực hiện khá nhiều những gì được quảng cáo mỗi lần.
JL Peyret

8

Các giả định:

$ echo $SHELL
/bin/bash
$ /bin/bash --version | head -1
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
$ set -o nounset

Nếu bạn muốn một tập lệnh không tương tác in ra lỗi và thoát nếu một biến là null hoặc không được đặt:

$ [[ "${HOME:?}" ]]

$ [[ "${IAMUNBOUND:?}" ]]
bash: IAMUNBOUND: parameter null or not set

$ IAMNULL=""
$ [[ "${IAMNULL:?}" ]]
bash: IAMNULL: parameter null or not set

Nếu bạn không muốn tập lệnh thoát:

$ [[ "${HOME:-}" ]] || echo "Parameter null or not set."

$ [[ "${IAMUNBOUND:-}" ]] || echo "Parameter null or not set."
Parameter null or not set.

$ IAMNULL=""
$ [[ "${IAMUNNULL:-}" ]] || echo "Parameter null or not set."
Parameter null or not set.

Bạn thậm chí có thể sử dụng []thay vì [[]]ở trên, nhưng cái sau thích hợp hơn trong Bash.

Lưu ý những gì dấu hai chấm ở trên. Từ các tài liệu :

Nói cách khác, nếu dấu hai chấm được bao gồm, toán tử kiểm tra sự tồn tại của cả tham số và giá trị của nó không phải là giá trị rỗng; nếu dấu hai chấm bị bỏ qua, toán tử chỉ kiểm tra sự tồn tại.

Rõ ràng là không cần -nhoặc -z.

Tóm lại, tôi thường có thể chỉ sử dụng [[ "${VAR:?}" ]]. Theo các ví dụ, điều này sẽ in ra một lỗi và thoát ra nếu một biến là null hoặc không được đặt.


4

Bạn có thể dùng

if [[ ${WHATEVER:+$WHATEVER} ]]; then

nhưng

if [[ "${WHATEVER:+isset}" == "isset" ]]; then

có thể dễ đọc hơn.


So sánh chuỗi nên sử dụng toán tử tiêu chuẩn (POSIX) =, không ==hỗ trợ tính di động và [thay vì [[nếu có thể.
Jens

2
@Jens Câu hỏi dành riêng cho bash và bao gồm câu hỏi set -o nounsetdành riêng cho bash. Nếu bạn đặt một #!/bin/bashở đầu tập lệnh của mình, thực sự tốt nhất là sử dụng các cải tiến của bash.
Bruno Bronosky

0

Mặc dù đây không phải là trường hợp sử dụng chính xác được yêu cầu ở trên, nhưng tôi thấy rằng nếu bạn muốn sử dụng nounset(hoặc -u) hành vi mặc định là hành vi bạn muốn: thoát khỏi nonzero bằng một thông báo mô tả.

Tôi đã mất đủ lâu để nhận ra điều này và tôi thấy rằng nó đáng được đăng tải như một giải pháp.

Nếu tất cả những gì bạn muốn là vọng lại điều gì đó khác khi thoát ra ngoài hoặc thực hiện một số hoạt động dọn dẹp, bạn có thể sử dụng bẫy.

Nhà :-điều hành có thể là những gì bạn muốn khác.

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.