Sự khác biệt giữa dấu hiệu đơn và đôi bằng nhau (=) trong so sánh vỏ là gì?


28

Đọc rằng để so sánh các chuỗi bên trong ifchúng ta cần sử dụng dấu ngoặc vuông. Một số cuốn sách nói rằng so sánh có thể được thực hiện bởi =. Nhưng nó hoạt động với ==quá.

#!/bin/bash
a="hello"
b="world"
if [[ $a == $b ]];then
    echo "equal"
fi

Có một sự khác biệt giữa ===trong so sánh?


4
Có một câu hỏi ở đây ở đâu đó? Nếu vậy, tôi không nhìn thấy nó. =là cho [. ==là cho [[.
Chris Xuống

@ChrisDown Điều đó hoàn toàn không đúng.
xdavidliu

@xdavidliu Chăm sóc công phu? Điều này chắc chắn đúng theo POSIX, vốn không hiểu gì ==, đó là lý do tại sao bạn nên sử dụng =(bình đẳng) với [==(khớp mẫu, với ngữ nghĩa được trích dẫn) [[. Xem help testso với help [[.
Chris xuống

@ChrisDown có lẽ tôi đang hiểu nhầm "nghĩa là gì". Nếu "là cho" có nghĩa là "chỉ hoạt động với", thì nhận xét đó không đúng, vì [ foo == foo ] && echo foochắc chắn in foo, chỉ ra rằng nó ==hoạt động với [. Tuy nhiên, nếu "dành cho" bạn có nghĩa là "được dự định sử dụng", thì tôi sẽ ít phản đối hơn.
xdavidliu

@xdavidliu "dành cho" trong trường hợp cụ thể mà bạn đề cập có nghĩa là "được xác định bởi POSIX". Chỉ vì bash tình cờ chấp nhận nó là sự tiện lợi, không có nghĩa là nó được khuyến nghị - dù sao bạn cũng đang tránh tính di động, chỉ cần sử dụng [[ở nơi đầu tiên có sự hiểu biết nhiều sắc thái hơn về tokenisation, chia tách từ, v.v ...
Chris Down

Câu trả lời:


28

[[ $a == $b ]]không so sánh, đó là mô hình phù hợp. Bạn cần [[ $a == "$b" ]]so sánh đẳng thức byte-byte. =giống như ==trong bất kỳ shell nào hỗ trợ [[...]](được giới thiệu bởi ksh).

[[...]]không phải là shcú pháp chuẩn . Các [ lệnh là tiêu chuẩn, và các tiêu chuẩn so sánh điều hành có =(mặc dù một số [hiện thực cũng nhận ==).

Giống như trong bất kỳ đối số nào đối với bất kỳ lệnh nào, các biến phải được trích dẫn, vì vậy:

[ "$a" = "$b" ]

Trong tiêu chuẩn sh, khớp mẫu được thực hiện với case:

case $a in
  ($b) ...
esac

Để hoàn thiện, các toán tử giống như bình đẳng khác mà bạn có thể gặp trong các tập lệnh shell:

  • [ "$a" -eq "$b" ]: [toán tử chuẩn để so sánh các số nguyên thập phân. Một số [triển khai cho phép khoảng trống xung quanh các con số, một số cho phép các biểu thức số học tùy ý, nhưng đó không phải là di động. Có thể sử dụng, người ta có thể sử dụng [ "$((a))" -eq "$((b))" ]cho điều đó. Xem thêm [ "$((a == b))" -ne 0 ]sẽ là tương đương tiêu chuẩn (ngoại trừ POSIXly, hành vi chỉ được chỉ định nếu $a$bchứa hằng số nguyên) của:
  • ((a == b)), từ ksh và cũng được tìm thấy trong zshbash, trả về true nếu đánh giá biểu thức số học được lưu trữ trong $asản lượng có cùng số với số đó $b. Thông thường, đó là được sử dụng để so sánh số. Lưu ý rằng có các biến thể giữa các hệ vỏ như cách đánh giá các biểu thức số học và số nào được hỗ trợ (ví dụ bash và một số phiên bản / phiên bản của ksh không hỗ trợ dấu phẩy động hoặc coi các số có số 0 đứng đầu là bát phân).

  • expr "$a" = "$b"thực hiện so sánh số nếu cả hai toán hạng được nhận dạng là số nguyên thập phân (một số cho phép khoảng trống xung quanh số) và kiểm tra xem hai toán tử chuỗi có cùng thứ tự sắp xếp không. Nó cũng sẽ thất bại đối với các giá trị của $ahoặc $blà các exprtoán tử như (, substr...

  • awk 'BEGIN{exit !(ARGV[1] == ARGV[2])}' "$a" "$b": Nếu $a$bđược công nhận là con số (tại số nguyên thập phân tối thiểu và số dấu phảy như 1.2, -1.5e-4, dẫn khoảng trống trailing bỏ qua, một số cũng nhận ra hệ thập lục phân, bát phân hay bất cứ điều gì được công nhận bởi strtod()), sau đó so sánh số được thực hiện. Nếu không, tùy thuộc vào việc thực hiện, đó là hoặc là một byte-to-byte chuỗi so sánh, hoặc như cho exprmột strcoll()so sánh, mà là liệu $a$bloại giống nhau.

Xem thêm:


13

Đây là tương đương trong bash:

[[ $x == "$y" ]]
[[ $x = "$y" ]]
[ "$x" == "$y" ]
[ "$x" = "$y" ]

Hai biến $ x đầu tiên không phải trích dẫn. Bash thực hiện phân tách từ và mở rộng tên đường dẫn bên trong [nhưng không bên trong [[:

$ x='a b'
$ [ -s $x ]
-bash: [: a: binary operator expected
$ [[ -s $x ]]
$ ls
$ [ a = * ]
-bash: [: a: unary operator expected
$ [[ a = * ]]
$ 

[[ $x = "$y" ]]là một so sánh chuỗi nhưng [[ $x = $y ]]là một biểu thức khớp mẫu:

$ y='a*'; [[ aa = "$y" ]]; echo $?
1
$ y='a*'; [[ aa = $y ]]; echo $?
0

-eq chỉ có nghĩa là được sử dụng với số nguyên:

$ [[ x.x -eq x.x ]]
-bash: [[: x.x: syntax error: invalid arithmetic operator (error token is ".x")
$ x=9; [[ "x" -eq 9 ]]; echo $?
0

Xem thêm BashFAQ / 031: Sự khác biệt giữa thử nghiệm, [và [[? .

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.