Kiểm tra chuỗi có độ dài khác không trong Bash: [-n Lời $ var] hoặc [Hồi $ var]


182

Tôi đã thấy Bash script kiểm tra chuỗi có độ dài khác không theo hai cách khác nhau. Hầu hết các tập lệnh sử dụng -ntùy chọn:

#!/bin/bash
# With the -n option
if [ -n "$var" ]; then
  # Do something when var is non-zero length
fi

Nhưng tùy chọn -n không thực sự cần thiết:

# Without the -n option
if [ "$var" ]; then
  # Do something when var is non-zero length
fi

Đó là cách tốt hơn?

Tương tự, đó là cách tốt hơn để kiểm tra độ dài bằng không:

if [ -z "$var" ]; then
  # Do something when var is zero-length
fi

hoặc là

if [ ! "$var" ]; then
  # Do something when var is zero-length
fi

Câu trả lời:


394

Chỉnh sửa: Đây là phiên bản hoàn chỉnh hơn cho thấy nhiều sự khác biệt giữa [(aka test) và [[.

Bảng sau đây cho thấy rằng một biến được trích dẫn hay không, cho dù bạn sử dụng dấu ngoặc đơn hay dấu ngoặc kép và biến đó chỉ chứa một khoảng trắng là những điều ảnh hưởng đến việc sử dụng kiểm tra có hay không -n/-zphù hợp để kiểm tra biến.

     | 1a    2a    3a    4a    5a    6a   | 1b    2b    3b    4b    5b    6b
     | [     ["    [-n   [-n"  [-z   [-z" | [[    [["   [[-n  [[-n" [[-z  [[-z"
-----+------------------------------------+------------------------------------
unset| false false true  false true  true | false false false false true  true
null | false false true  false true  true | false false false false true  true
space| false true  true  true  true  false| true  true  true  true  false false
zero | true  true  true  true  false false| true  true  true  true  false false
digit| true  true  true  true  false false| true  true  true  true  false false
char | true  true  true  true  false false| true  true  true  true  false false
hyphn| true  true  true  true  false false| true  true  true  true  false false
two  | -err- true  -err- true  -err- false| true  true  true  true  false false
part | -err- true  -err- true  -err- false| true  true  true  true  false false
Tstr | true  true  -err- true  -err- false| true  true  true  true  false false
Fsym | false true  -err- true  -err- false| true  true  true  true  false false
T=   | true  true  -err- true  -err- false| true  true  true  true  false false
F=   | false true  -err- true  -err- false| true  true  true  true  false false
T!=  | true  true  -err- true  -err- false| true  true  true  true  false false
F!=  | false true  -err- true  -err- false| true  true  true  true  false false
Teq  | true  true  -err- true  -err- false| true  true  true  true  false false
Feq  | false true  -err- true  -err- false| true  true  true  true  false false
Tne  | true  true  -err- true  -err- false| true  true  true  true  false false
Fne  | false true  -err- true  -err- false| true  true  true  true  false false

Nếu bạn muốn biết nếu một biến có độ dài khác không, hãy thực hiện bất kỳ thao tác nào sau đây:

  • trích dẫn biến trong ngoặc đơn (cột 2a)
  • sử dụng -nvà trích dẫn biến trong ngoặc đơn (cột 4a)
  • sử dụng dấu ngoặc kép có hoặc không có trích dẫn và có hoặc không có -n(cột 1b - 4b)

Lưu ý trong cột 1a bắt đầu từ hàng có nhãn "hai" rằng kết quả chỉ ra rằng [đang đánh giá nội dung của biến như thể chúng là một phần của biểu thức điều kiện (kết quả khớp với xác nhận được ngụ ý bởi "T" hoặc "F" trong cột mô tả). Khi [[được sử dụng (cột 1b), nội dung biến được xem dưới dạng chuỗi và không được đánh giá.

Các lỗi trong cột 3a và 5a là do thực tế là giá trị biến bao gồm một khoảng trắng và biến không được trích dẫn. Một lần nữa, như được hiển thị trong cột 3b và 5b, [[đánh giá nội dung của biến là một chuỗi.

Tương ứng, đối với các thử nghiệm cho các chuỗi có độ dài bằng không, các cột 6a, 5b và 6b chỉ ra các cách chính xác để làm điều đó. Cũng lưu ý rằng bất kỳ thử nghiệm nào trong số này có thể bị phủ định nếu phủ định cho thấy mục đích rõ ràng hơn so với sử dụng thao tác ngược lại. Ví dụ : if ! [[ -n $var ]].

Nếu bạn đang sử dụng [, chìa khóa để đảm bảo rằng bạn không nhận được kết quả không mong muốn là trích dẫn biến. Sử dụng [[, nó không thành vấn đề.

Các thông báo lỗi, đang bị loại bỏ, là "toán tử đơn nguyên dự kiến" hoặc "toán tử nhị phân dự kiến".

Đây là kịch bản sản xuất bảng trên.

#!/bin/bash
# by Dennis Williamson
# 2010-10-06, revised 2010-11-10
# for http://stackoverflow.com/q/3869072
# designed to fit an 80 character terminal

dw=5    # description column width
w=6     # table column width

t () { printf '%-*s' "$w" " true"; }
f () { [[ $? == 1 ]] && printf '%-*s' "$w" " false" || printf '%-*s' "$w" " -err-"; }

o=/dev/null

echo '     | 1a    2a    3a    4a    5a    6a   | 1b    2b    3b    4b    5b    6b'
echo '     | [     ["    [-n   [-n"  [-z   [-z" | [[    [["   [[-n  [[-n" [[-z  [[-z"'
echo '-----+------------------------------------+------------------------------------'

while read -r d t
do
    printf '%-*s|' "$dw" "$d"

    case $d in
        unset) unset t  ;;
        space) t=' '    ;;
    esac

    [ $t ]        2>$o  && t || f
    [ "$t" ]            && t || f
    [ -n $t ]     2>$o  && t || f
    [ -n "$t" ]         && t || f
    [ -z $t ]     2>$o  && t || f
    [ -z "$t" ]         && t || f
    echo -n "|"
    [[ $t ]]            && t || f
    [[ "$t" ]]          && t || f
    [[ -n $t ]]         && t || f
    [[ -n "$t" ]]       && t || f
    [[ -z $t ]]         && t || f
    [[ -z "$t" ]]       && t || f
    echo

done <<'EOF'
unset
null
space
zero    0
digit   1
char    c
hyphn   -z
two     a b
part    a -a
Tstr    -n a
Fsym    -h .
T=      1 = 1
F=      1 = 2
T!=     1 != 2
F!=     1 != 1
Teq     1 -eq 1
Feq     1 -eq 2
Tne     1 -ne 2
Fne     1 -ne 1
EOF

1
Cảm ơn! Tôi đã quyết định áp dụng kiểu "trích dẫn biến trong ngoặc đơn (cột 2a)" IMO, -n chỉ thêm tiếng ồn và giảm khả năng đọc. Tương tự, để kiểm tra độ dài bằng không hoặc không đặt, tôi sẽ sử dụng [! "$ var"] thay vì [-z "$ var"].
AllenHalsey

2
Vì vậy, biểu đồ của bạn cho ["vs [-n"(câu hỏi đầu tiên của OP) cho thấy rằng chúng hoàn toàn tương đương, phải không?
hobs

1
@hobs: Có, và sử dụng tùy thuộc vào cái nào rõ ràng hơn. Bạn cũng sẽ nhận thấy rằng tương đương của chúng khi sử dụng biểu mẫu khung đôi được ưu tiên khi sử dụng Bash.
Tạm dừng cho đến khi có thông báo mới.

1
Vì vậy, để tóm tắt bảng tuyệt vời của bạn, cách rõ ràng hơn ("tốt hơn") để kiểm tra các chuỗi không null là[["
hobs

22

Nó là tốt hơn để sử dụng mạnh mẽ hơn [[ như xa như Bash có liên quan.

Trường hợp thông thường

if [[ $var ]]; then   # var is set and it is not empty
if [[ ! $var ]]; then # var is not set or it is set to an empty string

Hai cấu trúc trên trông sạch sẽ và dễ đọc. Họ nên đủ trong hầu hết các trường hợp.

Lưu ý rằng chúng tôi không cần phải trích dẫn mở rộng biến bên trong [[như không có nguy cơ bị chia tách từglobbing .

Để ngăn các khiếu nại mềm của shellcheck về [[ $var ]][[ ! $var ]], chúng tôi có thể sử dụng -ntùy chọn.

Những trường hợp hiếm

Trong trường hợp hiếm hoi chúng ta phải phân biệt giữa "được đặt thành một chuỗi trống" so với "không được đặt ở tất cả", chúng ta có thể sử dụng những điều sau:

if [[ ${var+x} ]]; then           # var is set but it could be empty
if [[ ! ${var+x} ]]; then         # var is not set
if [[ ${var+x} && ! $var ]]; then # var is set and is empty

Chúng tôi cũng có thể sử dụng -vthử nghiệm:

if [[ -v var ]]; then             # var is set but it could be empty
if [[ ! -v var ]]; then           # var is not set
if [[ -v var && ! $var ]]; then   # var is set and is empty
if [[ -v var && -z $var ]]; then  # var is set and is empty

Bài viết và tài liệu liên quan

Có rất nhiều bài viết liên quan đến chủ đề này. Ở đây có một ít:


9

Dưới đây là một số bài kiểm tra

Đúng nếu chuỗi không trống:

[ -n "$var" ]
[[ -n $var ]]
test -n "$var"
[ "$var" ]
[[ $var ]]
(( ${#var} ))
let ${#var}
test "$var"

Đúng nếu chuỗi trống:

[ -z "$var" ]
[[ -z $var ]]
test -z "$var"
! [ "$var" ]
! [[ $var ]]
! (( ${#var} ))
! let ${#var}
! test "$var"

Điều này không trả lời câu hỏi của OP về cách tốt hơn.
codeforester

0

Câu trả lời đúng như sau:

if [[ -n $var ]] ; then
  blah
fi

Lưu ý việc sử dụng [[...]], trong đó xử lý chính xác trích dẫn các biến cho bạn.


2
Tại sao sử dụng -nkhi nó không thực sự cần thiết trong Bash?
codeforester

0

Một cách khác để đánh giá một biến môi trường trống và có lẽ minh bạch hơn là sử dụng ...

  if [ "x$ENV_VARIABLE" != "x" ] ; then
      echo 'ENV_VARIABLE contains something'
  fi

10
Đây là ngôi trường rất cũ từ thời vỏ Bourne. Đừng duy trì thói quen cũ này. bashlà một công cụ sắc nét hơn so với người tiền nhiệm của nó.
tbc0

2
Bạn thậm chí không cần điều này với các shell trước bash, nếu bạn đang tránh cú pháp mà tiêu chuẩn POSIX đánh dấu rõ ràng là lỗi thời. [ "$ENV_VARIABLE" != "" ]sẽ hoạt động trên mọi shell với testtriển khai tuân thủ POSIX - không chỉ bash, mà là ash / dash / ksh / etc.
Charles Duffy

... có nghĩa là, không sử dụng -ahoặc -okết hợp các thử nghiệm mà thay vào đó sử dụng [ ... ] && [ ... ]hoặc [ ... ] || [ ... ]và các trường hợp góc duy nhất có thể áp dụng để sử dụng dữ liệu của các biến tùy ý trong một thử nghiệm được đóng rõ ràng.
Charles Duffy

-2

Sử dụng case/esacđể kiểm tra:

case "$var" in
  "") echo "zero length";;
esac

12
Không, làm ơn. Đây không phải là những gì casecó nghĩa là cho.
tbc0

2
casehoạt động tốt nhất khi có nhiều hơn hai lựa chọn thay thế.
codeforester

casekhông dành cho loại sử dụng này.
Luis Lavaire
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.