Câu trả lời:
Sự khác biệt giữa [[ … ]]
và [ … ]
chủ yếu được đề cập trong việc sử dụng dấu ngoặc đơn hoặc dấu ngoặc kép - bash . Điều quan trọng, [[ … ]]
là cú pháp đặc biệt, trong khi đó [
là một tên trông buồn cười cho một lệnh. [[ … ]]
có quy tắc cú pháp đặc biệt cho những gì bên trong, [ … ]
không.
Với nếp nhăn được thêm vào của ký tự đại diện, đây là cách [[ $a == z* ]]
đánh giá:
[[ … ]]
cấu trúc có điều kiện xung quanh biểu thức điều kiện $a == z*
.==
toán tử nhị phân, với toán hạng $a
và z*
.a
.==
toán tử: kiểm tra xem giá trị của biến có a
khớp với mẫu không z*
.Đây là cách [ $a == z* ]
đánh giá:
[
lệnh với các đối số được hình thành bằng cách đánh giá các từ $a
, ==
, z*
, ]
.$a
thành giá trị của biến a
.a
là chuỗi 6 ký tự foo b*
(thu được bằng cách ví dụ a='foo b*'
) và danh sách các tập tin trong thư mục hiện hành được ( bar
, baz
, qux
, zim
, zum
), sau đó là kết quả của việc mở rộng là danh sách sau đây của chữ: [
, foo
, bar
, baz
, ==
, zim
, zum
, ]
.[
với các tham số thu được trong bước trước.
[
lệnh phàn nàn về lỗi cú pháp và trả về trạng thái 2.Lưu ý: Trong [[ $a == z* ]]
bước 3, giá trị của a
việc không trải qua quá trình phân tách từ và tạo tên tệp, bởi vì đó là trong bối cảnh mà một từ duy nhất được mong đợi (đối số bên trái của toán tử điều kiện ==
). Trong hầu hết các trường hợp, nếu một từ duy nhất có ý nghĩa ở vị trí đó thì việc mở rộng biến sẽ hoạt động giống như trong dấu ngoặc kép. Tuy nhiên, có một ngoại lệ cho quy tắc đó: trong [[ abc == $a ]]
, nếu giá trị của a
các ký tự đại diện, thì a
được khớp với mẫu ký tự đại diện. Ví dụ, nếu giá trị của a
là a*
sau đó [[ abc == $a ]]
là đúng (vì ký tự đại diện *
đến từ việc mở rộng không thể viện chứng của $a
trận đấu *
) trong khi [[ abc == "$a" ]]
là sai (vì nhân vật bình thường*
đến từ việc mở rộng trích dẫn $a
không phù hợp bc
). Bên trong [[ … ]]
, dấu ngoặc kép không tạo sự khác biệt, ngoại trừ ở phía bên tay phải của các nhà khai thác chuỗi khớp ( =
, ==
, !=
và =~
).
[
là một bí danh cho test
lệnh. Phiên bản Unix 6 có if
lệnh, nhưng Phiên bản 7 (1979) đi kèm với trình bao Bourne mới có một vài cấu trúc lập trình bao gồm cấu trúc if-then-other-elif-fi và phiên bản Unix 7 đã thêm một test
lệnh thực hiện hầu hết các lệnh "Các thử nghiệm" được thực hiện bởi if
lệnh trong các phiên bản cũ hơn.
[
đã được tạo thành bí danh test
và cả hai đều được tạo sẵn trong hệ vỏ trong Unix System III (1981) . Mặc dù cần lưu ý rằng một số biến thể Unix không có [
lệnh cho đến sau đó ( cho đến đầu những năm 2000 trên một số BSD sh
dựa trên vỏ Almquist (một phần mềm test
dựng sẵn luôn được đưa vào ash
nguồn, nhưng trên đó BSD ban đầu đã bị vô hiệu hóa)).
Lưu ý rằng test
aka [
là một lệnh để thực hiện "kiểm tra", không có nhiệm vụ nào mà lệnh đó thực hiện, vì vậy không có lý do gì để phân biệt giữa toán tử gán và toán tử đẳng thức, vì vậy toán tử đẳng thức là =
. ==
chỉ được hỗ trợ bởi một vài triển khai gần đây của [
(và chỉ là bí danh cho =
).
Bởi vì [
không có gì nhiều hơn một lệnh, nó được phân tích cú pháp giống như bất kỳ lệnh nào khác bằng shell.
Cụ thể, trong ví dụ của bạn $a
, vì nó không được trích dẫn, sẽ được chia thành nhiều từ theo quy tắc chia tách từ thông thường và mỗi từ sẽ trải qua quá trình tạo tên tệp hay còn gọi là tạo ra các từ có thể tạo ra nhiều từ hơn, mỗi từ đó dẫn đến một đối số riêng cho [
lệnh.
Tương tự, z*
sẽ được mở rộng vào danh sách tên tệp trong thư mục hiện tại bắt đầu bằng z
.
Vì vậy, ví dụ, nếu $a
là b* = x
, và có z1
, z2
, b1
và b2
tập tin trong thư mục hiện hành, Các [
lệnh sẽ nhận được 9 đối số: [
, b1
, b2
, =
, x
, ==
, z1
, z2
và ]
.
[
phân tích các đối số của nó như là một biểu thức điều kiện. 9 đối số đó không thêm vào một biểu thức điều kiện hợp lệ, vì vậy nó có thể sẽ trả về một lỗi.
Cấu [[ ... ]]
trúc được giới thiệu bởi vỏ Korn có lẽ vào khoảng năm 1988 vì ksh86a
năm 1987 không có nó trong khi ksh88
đã có nó từ đầu.
Bên cạnh ksh (tất cả các triển khai), [[...]]
cũng được hỗ trợ bởi bash (kể từ phiên bản 2.02) và zsh, nhưng cả ba triển khai đều khác nhau và có sự khác biệt giữa mỗi phiên bản của cùng một vỏ mặc dù các thay đổi thường tương thích ngược (một ngoại lệ đáng chú ý là bash =~
toán tử đã được biết là phá vỡ một vài tập lệnh sau một phiên bản nhất định khi hành vi của nó thay đổi). [[...]]
không được chỉ định bởi POSIX hoặc Unix hoặc Linux (LSB). Nó đã được xem xét để đưa vào một vài lần, nhưng không được bao gồm vì chức năng phổ biến của nó được hỗ trợ bởi các shell chính đã được bao phủ bởi [
lệnh và case-in-esac
cấu trúc.
Toàn bộ [[ ... ]]
cấu trúc tạo nên một lệnh. Nghĩa là, nó có trạng thái thoát (là tài sản quan trọng nhất của nó vì nó là kết quả của việc đánh giá biểu thức điều kiện), bạn có thể chuyển nó sang một lệnh khác (mặc dù nó sẽ không hữu ích) và thường sử dụng nó ở bất cứ đâu bạn muốn sử dụng bất kỳ lệnh nào khác (chỉ bên trong shell, vì nó là cấu trúc shell) nhưng nó không được phân tích cú pháp như một lệnh đơn giản thông thường. Những gì bên trong được phân tách bởi shell như một biểu thức có điều kiện và các quy tắc thông thường về phân tách từ và tạo tên tệp áp dụng khác nhau.
[[ ... ]]
không biết về ==
từ đầu và tương đương với =
1 . Một sai lầm của ksh's (và đang gây nhầm lẫn và nhiều lỗi) là =
và ==
không phải là toán tử đẳng thức mà là toán tử khớp mẫu (mặc dù khía cạnh khớp có thể bị vô hiệu hóa khi trích dẫn nhưng với các quy tắc không rõ ràng khác với shell).
Trong mã của bạn ở trên [[ $a == z* ]]
, hệ vỏ sẽ phân tích thành nhiều mã thông báo theo quy tắc tương tự như quy tắc thông thường, nhận ra nó là so sánh khớp mẫu, xử lý z*
như một mẫu để khớp với nội dung của a
biến.
Nói chung, việc bắn vào chân bạn khó [[ ... ]]
hơn so với [
lệnh. Nhưng một vài quy tắc như
-a
hoặc -o
vận hành (sử dụng một số [
lệnh và &&
và ||
vỏ khai thác)Làm cho [
đáng tin cậy với vỏ POSIX.
[[...]]
trong các shell khác nhau hỗ trợ các toán tử bổ sung như -nt
, các toán tử khớp với biểu thức chính quy ... nhưng danh sách và hành vi thay đổi từ shell sang shell và phiên bản sang phiên bản.
Vì vậy, trừ khi bạn biết phiên bản vỏ và phiên bản tối thiểu của tập lệnh của bạn sẽ được giải thích bằng cách nào, có lẽ sẽ an toàn hơn khi sử dụng [
lệnh tiêu chuẩn .
1 Một ngoại lệ: [[...]]
đã được thêm vào bash trong phiên bản 2.02
. Cho đến 2.03
khi nó được thay đổi, [[ x = '?' ]]
sẽ trả về true trong khi [[ x == '?' ]]
trả về false. Đó là trích dẫn không ngăn khớp mẫu khi sử dụng =
toán tử trong các phiên bản đó, nhưng đã làm khi sử dụng ==
.
[ '!' = foo -o a = a ]
trong bash
ví dụ.
cả hai đều được sử dụng để đánh giá biểu thức và [[sẽ không hoạt động với vỏ bẻ khóa cũ hơn POSIX và [[cũng hỗ trợ khớp mẫu và biểu thức chính quy. ví dụ thử những
[ $n -eq 0 -a $y -eq 0 ] && echo "Error" || echo "Ok"
[[ $n -eq 0 && $y -eq 0 ]] && echo "Error" || echo "Ok"
[[...]]
hỗ trợ regexps trong một số phiên bản của một số shell, giống như một số phiên bản [
hỗ trợ kết hợp regrec. Để so sánh số học, trong các vỏ hỗ trợ [[
, bạn muốn viết(( n == 0 && y == 0))