Tại sao sử dụng dấu ngoặc kép trong bài kiểm tra [[]]?


23

Giả sử chúng ta có 2 số nguyên trong tập lệnh bash:

value1=5
value2=3

Vậy thì tại sao chúng ta cần sử dụng dấu ngoặc kép trong trường hợp kiểm tra? Ví dụ:

if [[ "$value1" -eq "$value2" ]]

Tại sao không chỉ sử dụng sau đây?

if [[ $value1 -eq $value2 ]]

Đối với tôi, dấu ngoặc kép không có ý nghĩa gì.


5
Trích dẫn trong trình bao không liên quan nhiều đến các chuỗi (như trong các kiểu dữ liệu.) Đó thực sự là về việc ngăn chặn trình bao thực hiện phân tách từ (và các loại mở rộng khác.)
filbranden

13
Trong khi, như terdon đã chỉ ra, không cần thiết phải trích dẫn các biến trong cấu trúc cụ thể này (và tất nhiên, với các giá trị một từ ở bất cứ đâu), tôi muốn đưa ra lời khuyên để luôn trích dẫn các vars của bạn. Bạn có thực sự biết trong bối cảnh wich bạn có thể để các biến không được trích dẫn không? Lý do để trích dẫn tất cả, ngay cả khi nó không cần thiết với 53, là khả năng duy trì. Các giá trị có thể thay đổi sau đó và các lỗi kết quả có thể không rõ ràng.
Peter - Phục hồi lại

2
@sudodus Tôi không nghĩ điều đó đúng [[ ]], chỉ dành cho [ ].
Benjamin W.

1
Bạn nói đúng, @BenjaminW. Chia tách từ không phải là trường hợp duy nhất tại sao nên sử dụng dấu ngoặc kép cho các biến. Cũng có trường hợp khi một biến trống. Điều đó sẽ khiến cho câu lệnh trong [] không thành công (ví dụ [2 -eq] có lỗi, nhưng [[]] không dễ bị tổn thương (như trường hợp chia tách từ).
sododus

2
@marcelm, Bash, ksh và Zsh có các biến số nguyên và bên trong [[ ]]chúng cũng ép buộc các toán hạng của -eqsố nguyên.
ilkkachu

Câu trả lời:


7

Chia từ.

Ví dụ này rất khó khả thi, nhưng có thể , vì vậy nếu bạn muốn viết mã phòng thủ, hãy che dấu vết của bạn bằng dấu ngoặc kép:

$ set -x
$ value1=5
+ value1=5
$ value2=3
+ value2=3
$ [ $value1 -eq $value2 ]
+ '[' 5 -eq 3 ']'

OK, tất cả đều tốt cho đến nay. Hãy ném cờ lê vào bánh răng:

$ IFS=456
+ IFS=456
$ [ $value1 -eq $value2 ]
+ '[' '' -eq 3 ']'
bash: [: : integer expression expected

Rất tiếc.

$ [ "$value1" -eq "$value2" ]
+ '[' 5 -eq 3 ']'

À


2
Nhưng OP sử dụng dấu ngoặc kép, do đó không có sự phân tách từ nào diễn ra.
user000001

5
Vâng, điều này không thực sự liên quan đến [[ ]]cấu trúc của bash .
terdon

1
Ơ [ $value1 -eq $value2 ]với một khoảng trống value1sẽ '[' -eq 3 ']'không có ''ở phía bên tay trái.
Charles Duffy

Tôi cũng ngạc nhiên, nhưng có bằng chứng.
glenn jackman

1
Câu trả lời này không liên quan trực tiếp đến câu hỏi. Tôi ngạc nhiên khi nó được chấp nhận. Đặt làm wiki cộng đồng.
glenn jackman

35

Bạn thực sự không cần báo giá ở đây. Đây là một trong số rất ít trường hợp an toàn khi sử dụng biến không được trích dẫn. Bạn có thể xác nhận điều này với set -x:

$ var1=""
$ var2="3"
$ set -x
$ if [[ $var1 -eq $var2 ]]; then echo "match!"; else echo "no match!"; fi
+ [[ '' -eq 3 ]]
+ echo 'no match!'
no match!
$ if [[ "$var1" -eq "$var2" ]]; then echo "match!"; else echo "no match!"; fi
+ [[ '' -eq 3 ]]
+ echo 'no match!'
no match!

Như bạn có thể thấy ở trên, các phiên bản được trích dẫn và không trích dẫn của bài kiểm tra được giải quyết theo cùng một điều chính xác bằng bash. Điều tương tự cũng đúng với zshvà, tôi nghĩ, bất kỳ shell nào khác hỗ trợ [[ ]]toán tử.

Lưu ý rằng đây không phải là trường hợp di động hơn [ ]:

$ if [ $var1 -eq $var2 ]; then echo "match!"; else echo "no match!"; fi
+ '[' -eq 3 ']'
sh: [: -eq: unary operator expected
+ echo 'no match!'
no match!

Cấu [ ]trúc, không giống như [[ ]]cái, không yêu cầu trích dẫn.


Một số liên kết hữu ích để tìm hiểu thêm về thời điểm và lý do trích dẫn là bắt buộc:


Trong trường hợp này với các biến số nguyên, tốt hơn là khai báo chúng như vậy. declare -i var1=0khi đánh giá.
Freddy

4
Lưu ý rằng đó -eqlà so sánh số học , do đó bạn thậm chí có thể bỏ $qua (trong [[ .. ]]) và viết [[ a -eq b ]]. Với so sánh chuỗi, tất nhiên, bạn cần $, vì vậy[[ $a = $b ]]
ilkkachu

2
@ user000001 điểm tốt. Mặc dù, tất nhiên, rất có thể bạn muốn những thứ đó được mở rộng. Ví dụ, tôi mong đợi đây sẽ là một trận đấu : var1="afoob"; var2="a*b"; [[ $var1 = $var2 ]] && echo match. Nếu bạn muốn sử dụng các ký tự toàn cầu mà không đóng vai trò là một quả địa cầu trong bối cảnh toàn cầu (chẳng hạn như [[ ]]) thì bạn cần phải trích dẫn, vâng.
terdon

3
@ilkkachu, điều đó làm tôi ngạc nhiên. Tôi nghĩ rằng các biến "trần" sẽ chỉ được xem xét trong một chỉ mục mảng hoặc ((...))hoặc $((...). Nó có vẻ hoạt động, nhưng (ông già gắt gỏng, cho phép) Tôi không thích nó.
glenn jackman

1
@glennjackman, tốt, xin lỗi vì là người nói với bạn điều đó, nhưng vâng, các toán hạng cho -eqvà bạn bè bên trong [[ ]]cũng là bối cảnh số học. :) (Liên quan: Mở rộng biến tự động bên trong lệnh bash [[]] )
ilkkachu

17

Mặc dù dấu ngoặc kép không cần thiết, lý do để sử dụng chúng là:

  • Thói quen tốt / thói quen: Trong này trường hợp họ không cần thiết, nhưng nói chung dấu ngoặc kép để tránh tách từ ngoài ý muốn.
  • Bởi vì value1value2là biến, và bạn có thể không biết chúng chứa gì. Nếu không, bạn cũng có thể hỏi, "Tại sao phải bận tâm với các biến thay vì kiểm tra if [[ 5 -eq 3 ]]? Hoặc đưa nó đi xa hơn, tại sao lại bận tâm với iftất cả khi bạn đã biết rằng 5 không bằng 3? Điều đó thường tốt hơn để phòng thủ. việc chia tách từ đó sẽ không xảy ra [[, nhưng trường hợp phân tách từ không xảy ra là hiếm. Một lần nữa, hãy xem điểm đầu tiên.)

1

Không liên quan trực tiếp đến câu hỏi của bạn, nhưng tôi sử dụng

if (($ value1 == $ value2)); sau đó

Khi tôi so sánh các con số nhưng ở đó bạn cũng không phải sử dụng dấu ngoặc kép.


2
if (( value1 == value2 )); then. Trong bối cảnh số học, bạn thậm chí không cần $. Câu hỏi này, tuy nhiên, dường như tập trung vào các biến được sử dụng trong [[ ... ]]các bài kiểm tra.
Kusalananda

1
Tôi biết. Nhưng tôi thực sự không sử dụng tính năng này bởi vì tôi muốn các tên biến của mình nhất quán và do đó sử dụng $ làm tiền tố mọi lúc.
framp

1

Bạn hoàn toàn đúng!

Việc trích dẫn trong dấu ngoặc vuông đôi không có ý nghĩa gì cả, ít nhất là trong trường hợp này.

Nhưng vì tôi sử dụng dấu ngoặc kép hàng ngày - đặc biệt là cho các biểu thức dấu ngoặc vuông đơn, chuyển các đối số cho các hàm và tập lệnh, cũng như việc gán biến đôi khi (điều này hoàn toàn vô dụng đối với các biểu đồ đơn giản) - tôi đoán một số người, ít nhất là tôi làm, viết dấu ngoặc kép xung quanh mở rộng biến theo bản năng .

Trích dẫn đôi có thể cho bạn một cảm giác man rợ. Nó giống như về nhà, nơi báo giá gấp đôi. - D. Kummer

Một lợi ích của việc thực hiện các trích dẫn kép do đó một cách toàn diện và toàn diện - nhưng chỉ khi nó có ý nghĩa - là các đồng nghiệp mới làm quen với bash có thể học cách viết các kịch bản ổn định hơn . Nó cũng nhấn mạnh thực tế rằng nghệ thuật xử lý dữ liệu bằng bash liên quan nhiều hơn đến việc tách các luồng dữ liệu (bao gồm các biến) bằng các dấu tách trường và dẫn chúng qua các bộ lọc . Ngay sau khi bạn tách các khối dữ liệu của mình khỏi luồng, hãy giữ chúng cùng với dấu ngoặc kép!

Một lợi ích khác có thể là khả năng đọc các tập lệnh bash tốt hơn với các chuỗi được trích dẫn kép trong trình soạn thảo tô sáng mã .

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.