Toán tử bình đẳng Bash (==, -eq)


135

Ai đó có thể vui lòng giải thích sự khác biệt giữa -eq==trong bash scripting?

Có sự khác biệt nào sau đây không?

[ $a -eq $b ][ $a == $b ]

Có phải chỉ đơn giản là nó chỉ ==được sử dụng khi các biến chứa số?

Câu trả lời:


186

Đó là cách khác: ===là để so sánh chuỗi, -eqdành cho số. -eqlà trong cùng một gia đình như -lt, -le, -gt, -ge, và -ne, nếu điều đó giúp bạn nhớ được mà.

==Nhân tiện, là một bash-ism. Tốt hơn là sử dụng POSIX =. Trong bash cả hai là tương đương, và trong sh đơn giản =là người duy nhất được đảm bảo để làm việc.

$ a=foo
$ [ "$a" = foo ]; echo "$?"       # POSIX sh
0
$ [ "$a" == foo ]; echo "$?"      # bash specific
0
$ [ "$a" -eq foo ]; echo "$?"     # wrong
-bash: [: foo: integer expression expected
2

(Lưu ý bên: Trích dẫn những mở rộng biến đổi đó! Đừng bỏ qua các trích dẫn kép ở trên.)

Nếu bạn đang viết một #!/bin/bashkịch bản thì tôi khuyên bạn nên sử dụng [[thay thế . Hình thức nhân đôi có nhiều tính năng hơn, cú pháp tự nhiên hơn và ít vấn đề hơn sẽ khiến bạn gặp khó khăn. Dấu ngoặc kép không còn cần thiết xung quanh $a, cho một:

$ [[ $a == foo ]]; echo "$?"      # bash specific
0

Xem thêm:


1
@DJCrashdummy, [[nói chung là một ksh-ism có từ thời những năm 1980 mà bash (và nhiều vỏ khác) được thông qua. Đó là toàn bộ vấn đề - nếu bạn có [[ tất cả , thì bạn có thể giả định một cách an toàn rằng tất cả các tiện ích mở rộng ksh được triển khai xung quanh nó ( fnmatch()khớp mẫu kiểu, biểu thức chính quy ERE với =~, và vâng, ngăn chặn phân tách chuỗi và toàn cầu hóa hệ thống tệp) sẽ có sẵn. Do [[toàn bộ cú pháp không phải là POSIX, nên không có sự mất tính di động bổ sung nào khi cho rằng các tính năng mà nó được sinh ra sẽ có sẵn.
Charles Duffy

1
@DJCrashdummy, ... liên kết mà bạn hiển thị điểm một cách chính xác rằng dấu ngoặc kép đôi khi cần thiết trên bên phải của [[ $var = $pattern ]], nếu bạn muốn gì nếu không sẽ được hiểu như là một mô hình fnmatch để thay thể được hiểu như là một chuỗi chữ. Chuỗi fookhông có giải thích phi nghĩa đen, làm cho trích dẫn hoàn toàn an toàn; Chỉ khi OP muốn khớp, giả sử, foo*(với dấu hoa thị là nghĩa đen, không có nghĩa là bất cứ điều gì có thể xảy ra sau chuỗi foo) mà trích dẫn hoặc thoát là cần thiết.
Charles Duffy

@CharlesDuffy tiếc là tôi không biết bạn đang đề cập đến điều gì, bởi vì nhận xét của tôi dường như bị xóa và tôi không thể nhớ được vì đã khá lâu rồi. :-(
DJCrashdummy

@DJCrashdummy, ... huh, tôi cho rằng bạn đã tự rút tiền. Về cơ bản, đó là một sự phản đối về việc mở rộng [[không được trích dẫn bên trong là một bashism (chỉ ra rằng đó là lý do duy nhất bạn không đưa ra câu trả lời +1).
Charles Duffy

@CharlesDuffy không, đó không phải là lý do duy nhất: bên cạnh thực tế là tôi không thích bash-isms, ksh-isms, v.v. cho các nhiệm vụ đơn giản (nó chỉ gây rắc rối và nhầm lẫn cho người mới bắt đầu), tôi không hiểu tại sao trộn đơn niềng răng [ ... ]và dấu bằng đôi ==. : - /
DJCrashdummy

27

Nó phụ thuộc vào Kiểm tra Xây dựng xung quanh toán tử. Tùy chọn của bạn là dấu ngoặc kép, dấu ngoặc kép, dấu ngoặc đơn hoặc phép thử

Nếu bạn sử dụng ((...)) , bạn đang kiểm tra vốn chủ sở hữu số học ==như trong C:

$ (( 1==1 )); echo $?
0
$ (( 1==2 )); echo $?
1

(Lưu ý: 0có nghĩa là truetheo nghĩa Unix và khác không là một thử nghiệm thất bại)

Sử dụng -eqbên trong dấu ngoặc kép là một lỗi cú pháp.

Nếu bạn đang sử dụng [...] (hoặc nẹp đơn) hoặc [[...]] (hoặc nẹp đôi) hoặc testbạn có thể sử dụng một trong các -eq, -ne, -lt, -le, -gt hoặc -ge như một so sánh số học .

$ [ 1 -eq 1 ]; echo $?
0
$ [ 1 -eq 2 ]; echo $?
1
$ test 1 -eq 1; echo $?
0

Bên ==trong của dấu ngoặc đơn hoặc kép (hoặc testlệnh) là một trong các toán tử so sánh chuỗi :

$ [[ "abc" == "abc" ]]; echo $?
0
$ [[ "abc" == "ABC" ]]; echo $?
1

Là một toán tử chuỗi, =tương đương ==và lưu ý khoảng trắng xung quanh =hoặc ==yêu cầu của nó.

Trong khi bạn có thể làm [[ 1 == 1 ]]hoặc [[ $(( 1+1 )) == 2 ]]nó đang kiểm tra đẳng thức chuỗi - không phải là đẳng thức số học.

Vì vậy, -eqtạo ra kết quả có thể mong đợi rằng giá trị số nguyên 1+1bằng với 2mặc dù RH là một chuỗi và có khoảng trắng ở cuối:

$ [[ $(( 1+1 )) -eq  "2 " ]]; echo $?
0

Trong khi so sánh chuỗi của cùng một khoảng không gian theo dõi và do đó, so sánh chuỗi không thành công:

$ [[ $(( 1+1 )) ==  "2 " ]]; echo $?
1

Và một so sánh chuỗi sai có thể tạo ra câu trả lời sai hoàn toàn. '10' là từ vựng nhỏ hơn '2', do đó, một so sánh chuỗi trả về truehoặc 0. Vì vậy, nhiều người bị cắn bởi lỗi này:

$ [[ 10 < 2 ]]; echo $?
0

so với bài kiểm tra đúng cho 10 là số ít hơn 2:

$ [[ 10 -lt 2 ]]; echo $?
1

Trong các bình luận, có một câu hỏi về lý do kỹ thuật sử dụng số nguyên -eqtrên chuỗi trả về True cho các chuỗi không giống nhau:

$ [[ "yes" -eq "no" ]]; echo $?
0

Lý do là Bash được tháo gỡ . Các -eqnguyên nhân khiến các chuỗi được hiểu là số nguyên nếu có thể bao gồm chuyển đổi cơ sở:

$ [[ "0x10" -eq 16 ]]; echo $?
0
$ [[ "010" -eq 8 ]]; echo $?
0
$ [[ "100" -eq 100 ]]; echo $?
0

0nếu Bash nghĩ rằng nó chỉ là một chuỗi:

$ [[ "yes" -eq 0 ]]; echo $?
0
$ [[ "yes" -eq 1 ]]; echo $?
1

Như vậy [[ "yes" -eq "no" ]]là tương đương với[[ 0 -eq 0 ]]

Lưu ý cuối cùng: Nhiều phần mở rộng cụ thể của Bash cho Cấu trúc kiểm tra không phải là POSIX và do đó sẽ thất bại trong các trình bao khác. Các vỏ khác thường không hỗ trợ [[...]]((...))hoặc== .


Tôi tò mò về lý do kỹ thuật để [[ "yes" -eq "no" ]]trở về True. Làm thế nào để bash ép các chuỗi này thành các giá trị nguyên có thể được so sánh? ;-)
odony

4
Các biến Bash được tháo ra để [[ "yes" -eq "no" ]]tương đương với [[ "yes" -eq 0 ]] hoặc [[ "yes" -eq "any_noninteger_string" ]]- Tất cả Đúng. Các -eqlực lượng so sánh số nguyên. Các "yes"được hiểu như là một số nguyên 0; so sánh là True nếu số nguyên khác là 0hoặc kết quả chuỗi là 0.
dawg

Boo, hiss re: hiển thị (không thể truy cập) ==trong các mẫu mã và chỉ đề cập (di động, tiêu chuẩn hóa) =bên dưới.
Charles Duffy

24

==là một bí danh dành riêng cho bash =và nó thực hiện so sánh chuỗi (từ vựng) thay vì so sánh số. eqlà một so sánh số của khóa học.

Cuối cùng, tôi thường thích sử dụng mẫu if [ "$a" == "$b" ]


15
Sử dụng ==ở đây là hình thức xấu, vì chỉ =được chỉ định bởi POSIX.
Charles Duffy

9
Nếu bạn thực sự khăng khăng sử dụng ==thì hãy đặt nó ở giữa [[]]. (Và đảm bảo rằng dòng đầu tiên trong tập lệnh của bạn chỉ định sử dụng /bin/bash.)
holgero

18

Guys: Một số câu trả lời cho thấy các ví dụ nguy hiểm. Ví dụ của OP [ $a == $b ]được sử dụng cụ thể thay thế biến không được trích dẫn (kể từ chỉnh sửa 17 tháng 10). Cho [...]rằng đó là an toàn cho bình đẳng chuỗi.

Nhưng nếu bạn sắp liệt kê các lựa chọn thay thế như thế [[...]], bạn cũng phải thông báo rằng phía bên tay phải phải được trích dẫn. Nếu không được trích dẫn, đó là một mô hình phù hợp! (Từ trang bash man: "Bất kỳ phần nào của mẫu có thể được trích dẫn để buộc nó được khớp dưới dạng chuỗi.").

Ở đây trong bash, hai câu lệnh mang lại "có" là khớp mẫu, ba câu khác là chuỗi bằng:

$ rht="A*"
$ lft="AB"
$ [ $lft = $rht ] && echo yes
$ [ $lft == $rht ] && echo yes
$ [[ $lft = $rht ]] && echo yes
yes
$ [[ $lft == $rht ]] && echo yes
yes
$ [[ $lft == "$rht" ]] && echo yes
$

2
Cần phải được [ "$lht" = "$rht" ] trích dẫn để đáng tin cậy ngay cả đối với bình đẳng. Nếu bạn có một tệp được tạo touch 'Afoo -o AB', [ $lft = $rht ]sẽ trả về true, mặc dù tên tệp đó hoàn toàn không giống với AB.
Charles Duffy
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.