Đây là một trường hợp góc rất khó hiểu mà người ta có thể xem xét một lỗi trong cách [
xác định tích hợp kiểm tra ; tuy nhiên, nó phù hợp với hành vi của [
nhị phân thực tế có sẵn trên nhiều hệ thống. Theo như tôi có thể nói, nó chỉ ảnh hưởng đến một số trường hợp và một biến có giá trị phù hợp với một [
nhà khai thác như (
, !
, =
, -e
, và vân vân.
Hãy để tôi giải thích lý do tại sao và cách xử lý xung quanh nó trong shell Bash và POSIX.
Giải trình:
Hãy xem xét những điều sau đây:
x="("
[ "$x" = "(" ] && echo yes || echo no
Không vấn đề gì; các kết quả trên không có lỗi, và đầu ra yes
. Đây là cách chúng tôi mong đợi công cụ để làm việc. Bạn có thể thay đổi chuỗi so sánh thành '1'
nếu bạn thích và giá trị của x
nó và nó sẽ hoạt động như mong đợi.
Lưu ý rằng /usr/bin/[
nhị phân thực tế hoạt động theo cùng một cách. Nếu bạn chạy, ví dụ như '/usr/bin/[' '(' = '(' ']'
không có lỗi, bởi vì chương trình có thể phát hiện ra rằng các đối số bao gồm một hoạt động so sánh chuỗi đơn.
Lỗi xảy ra khi chúng ta và với một biểu thức thứ hai. Không quan trọng biểu thức thứ hai là gì, miễn là nó hợp lệ. Ví dụ,
[ '1' = '1' ] && echo yes || echo no
đầu ra yes
, và rõ ràng là một biểu thức hợp lệ; nhưng, nếu chúng ta kết hợp cả hai,
[ "$x" = "(" -a '1' = '1' ] && echo yes || echo no
Bash từ chối biểu thức khi và chỉ khi x
là (
hoặc !
.
Nếu chúng ta chạy chương trình trên bằng [
chương trình thực tế , tức là
'/usr/bin/[' "$x" = "(" -a '1' = '1' ] && echo yes || echo no
lỗi sẽ hiểu: từ vỏ hiện các thay biến, /usr/bin/[
nhị phân chỉ nhận được các thông số (
=
(
-a
1
=
1
và chấm dứt ]
, nó dễ hiểu thất bại trong việc phân tích xem ngoặc mở bắt đầu một tiểu biểu hiện hay không, có trở thành một và hoạt động liên quan. Chắc chắn, phân tích nó như là hai so sánh chuỗi là có thể, nhưng thực hiện nó một cách tham lam như thế có thể gây ra vấn đề khi áp dụng cho các biểu thức thích hợp với các biểu thức con được ngoặc đơn.
Vấn đề, thực sự, là cái vỏ tích [
hợp hoạt động theo cùng một cách, như thể nó mở rộng giá trị của x
trước khi kiểm tra biểu thức.
(Những sự mơ hồ này và những điều khác liên quan đến việc mở rộng biến đổi, là một lý do lớn khiến Bash thực hiện và hiện khuyên nên sử dụng các [[ ... ]]
biểu thức kiểm tra thay thế.)
Cách giải quyết là tầm thường và thường thấy trong các tập lệnh sử dụng sh
shell cũ . Bạn thêm một ký tự "an toàn", thường x
, ở phía trước các chuỗi (cả hai giá trị được so sánh), để đảm bảo biểu thức được nhận dạng dưới dạng so sánh chuỗi:
[ "x$x" = "x(" -a "x$y" = "x1" ]
[[ "$x" = '1' && "$y" = '1' ]]