Tại sao `==` lại cư xử khác trong `[]] trong zsh và bash?


9

Tôi nhận được những gì tôi mong đợi khi làm điều này trong bash:

[ "a" == "a" ] && echo yes

Nó đã cho tôi yes.

Nhưng khi tôi làm điều này zsh, tôi nhận được như sau:

zsh: = not found

Tại sao cùng một lệnh ( /usr/bin/[) hành xử khác nhau trong các shell khác nhau?


5
đó không phải là cùng một lệnh - một lệnh dựng sẵn được tìm thấy trước đó $PATHđược tìm kiếm. và ==không phải là testcú pháp hợp lệ cho /usr/bin/[anway. Chỉ =là tốt thôi
mikeerv

Câu trả lời:


18

Nó không phải /usr/bin/[là một trong hai vỏ. Trong Bash, bạn đang sử dụng built-in test/ [lệnh , và tương tự như trong zsh .

Sự khác biệt là zsh cũng có một bản =mở rộng : =foomở rộng đường dẫn đến footệp thực thi. Điều đó có nghĩa ==là được coi là cố gắng tìm một lệnh được gọi =trong của bạnPATH . Vì lệnh đó không tồn tại, bạn gặp lỗi

zsh: = not found

mà bạn đã thấy (và trên thực tế, điều tương tự sẽ xảy ra ngay cả khi bạn thực sự đang sử dụng /usr/bin/[).


Bạn có thể sử dụng ==ở đây nếu bạn thực sự muốn. Điều này hoạt động như bạn mong đợi trong zsh:

[ "a" "==" "a" ] && echo yes

bởi vì trích dẫn ngăn cản =wordmở rộng chạy. Bạn cũng có thể vô hiệu hóa equalstùy chọn với setopt noequals.


Tuy nhiên, bạn cũng nên tốt hơn:

  • Sử dụng đơn =, kiểm tra đẳng thức tương thích POSIX ; hoặc là
  • Vẫn tốt hơn, sử dụng các [[điều kiện có== trong cả Bashzsh . Nói chung, [[chỉ tốt hơn và an toàn hơn xung quanh, bao gồm tránh loại vấn đề này (và các vấn đề khác) bằng cách có các quy tắc phân tích cú pháp đặc biệt bên trong.

Sự khác biệt chính xác giữa [và là [[gì? (Tìm kiếm trên Google chỉ [ vs [[mang lại cho tôi kết quả vs, LOL)
Johnson Steward

2
[[hỗ trợ phạm vi thử nghiệm rộng hơn trong cả hai trường hợp và có các quy tắc phân tích cú pháp tùy chỉnh để tránh phải trích dẫn các biến, toán tử, v.v. Nếu bạn đặc biệt sử dụng Bash hoặc zsh, hãy sử dụng [[. Nếu bạn đang viết một tập lệnh di động, hãy viết vào lệnh [/ tương thích POSIX test(có thể hoặc không phải là một lệnh thực sự trên hệ thống đang chạy của bạn).
Michael Homer

1
Chỉ cần sử dụng [[ở đó và quên [tồn tại.
Michael Homer

1
bạn biết ... tôi không đồng ý với đề nghị của bạn. [[khác nhau có khả năng. Hãy thử nó với nó : for f in *; do [ -e "$f" ] && for a in f d h p S b c; do [ "-$a" "$f" ] && for p in r w x u g; do [ "-$p" "$f" ] || p=-; a=$a$p; done && break; done && printf "%s:\t%s\n" "$a" "$f"; done.
mikeerv

3
Vâng, =/ ==được cho là một trường hợp [[không phải là tốt hơn so với [, như [[ a == b ]]làm "a" phù hợp với "b" mô hình chứ không phải là "a" bằng "b" như bạn mong muốn. Điều đó có nghĩa là bạn cần phải viết [[ $a == "$b" ]]ví dụ. Ít nhất, với [lệnh, nếu bạn biết cách phân tích cú pháp hoạt động, bạn biết bạn cần phải viết nó [ "$a" = "$b" ]để ngăn toán tử split + global như trong các lệnh khác. Với ý nghĩ đó và nếu bạn không sử dụng -a hoặc -o, [sẽ an toàn trong việc triển khai tuân thủ POSIX.
Stéphane Chazelas

2

Và zsh, và bash đưa ra cùng một câu trả lời ( typecũng được tích hợp cho cả hai shell):

$ type -a [
[ is a shell builtin
[ is /usr/bin/[

2

[ là một lệnh dựng sẵn shell trong bash và trong zsh:

$ type [
[ is a shell builtin

Từ tài liệu Lệnh dựng sẵn Shell :

Các lệnh dựng sẵn được chứa trong chính shell . Khi tên của lệnh dựng sẵn được sử dụng làm từ đầu tiên của lệnh đơn giản (xem Lệnh đơn giản ), shell sẽ thực thi lệnh trực tiếp mà không cần gọi chương trình khác. Các lệnh dựng sẵn là cần thiết để thực hiện chức năng không thể hoặc bất tiện để có được với các tiện ích riêng biệt.

Tài liệu chính thức ( $ help test) chỉ cho phép sử dụng =:

CHUINGI1 = CHUING2

Đúng nếu các chuỗi bằng nhau.

Vì vậy, biểu thức chính xác sẽ là:

$ [ "a" = "a" ] && echo yes
yes

Điều gì xảy ra là bash ít nghiêm ngặt hơn một chút. Hỗ trợ ==toán tử [ dường như là một phần mở rộng bash và không nên sử dụng nó:

chuỗi1 == chuỗi2

chuỗi1 = chuỗi2

Đúng nếu các chuỗi bằng nhau. Khi được sử dụng với lệnh [[, lệnh này thực hiện khớp mẫu như được mô tả ở trên (xem Cấu trúc có điều kiện ).

'=' nên được sử dụng với lệnh kiểm tra sự phù hợp POSIX.

Nếu bạn muốn sử dụng ==, bạn nên sử dụng [[từ khóa:

$ [[ "a" == "a" ]] && echo yes
yes

Hãy nhớ rằng [[ít di động hơn (không phải là POSIX). Nhưng cả bash và zsh đều hỗ trợ nó.


1

Trong cả hai shell, bashzsh, [tiện ích là một shell được tích hợp. Đây là triển khai shell của công cụ đó, nó được sử dụng theo sở thích nhị phân /usr/bin/[. Các kết quả khác nhau mà bạn gặp phải được gây ra bởi các triển khai khác nhau.


Trong bash, [tiện ích chấp nhận CONDITIONAL EXPRESSIONS[[lệnh ghép. Theo trang bashs man cả ===đều hợp lệ:

string1 == string2
string1 = string2
        True if the strings are equal.  = should be used with the test command for POSIX
        conformance.

Trong đó zsh, [tiện ích cố gắng triển khai POSIX và các tiện ích mở rộng trong đó các tiện ích được chỉ định. Trong đặc tả của tiện ích kiểm tra POSIX không có ==toán tử được xác định.

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.