นี่เป็นกรณีมุมที่คลุมเครือมากซึ่งอาจพิจารณาข้อผิดพลาดในวิธีการทดสอบ[
ในตัว อย่างไรก็ตามมันตรงกับพฤติกรรมของ[
ไบนารีจริงที่มีอยู่ในหลาย ๆ ระบบ เท่าที่ผมสามารถบอกได้ว่ามันมีผลเฉพาะบางกรณีและตัวแปรที่มีค่าที่ตรงกับที่[
ผู้ประกอบการเช่น(
, !
, =
, -e
และอื่น ๆ
ให้ฉันอธิบายว่าทำไมและวิธีแก้ไขในเชลล์ Bash และ POSIX
คำอธิบาย:
พิจารณาสิ่งต่อไปนี้:
x="("
[ "$x" = "(" ] && echo yes || echo no
ไม่มีปัญหา; yes
อัตราผลตอบแทนดังกล่าวข้างต้นไม่มีข้อผิดพลาดและเอาท์พุท นี่คือวิธีที่เราคาดหวังสิ่งที่ทำงาน คุณสามารถเปลี่ยนสตริงเปรียบเทียบเป็น'1'
หากคุณต้องการและคุณค่าของx
มันและมันจะทำงานตามที่คาดไว้
โปรดทราบว่า/usr/bin/[
ไบนารีจริงจะทำงานในลักษณะเดียวกัน หากคุณเรียกใช้เช่น'/usr/bin/[' '(' = '(' ']'
ไม่มีข้อผิดพลาดเพราะโปรแกรมสามารถตรวจพบว่าข้อโต้แย้งประกอบด้วยการดำเนินการเปรียบเทียบสตริงเดียว
ข้อผิดพลาดเกิดขึ้นเมื่อเราและด้วยการแสดงออกที่สอง ไม่สำคัญว่านิพจน์ที่สองจะเป็นอย่างไรตราบใดที่มันถูกต้อง ตัวอย่างเช่น,
[ '1' = '1' ] && echo yes || echo no
ผลลัพธ์yes
และเห็นได้ชัดว่าเป็นการแสดงออกที่ถูกต้อง; แต่ถ้าเรารวมสอง
[ "$x" = "(" -a '1' = '1' ] && echo yes || echo no
ทุบตีปฏิเสธการแสดงออกและถ้าหากx
เป็นหรือ(
!
ถ้าเราจะเรียกใช้ข้างต้นโดยใช้[
โปรแกรมจริงเช่น
'/usr/bin/[' "$x" = "(" -a '1' = '1' ] && echo yes || echo no
ข้อผิดพลาดจะสามารถเข้าใจได้: เนื่องจากเชลล์ทำการแทนที่ตัวแปร/usr/bin/[
ไบนารีจะรับพารามิเตอร์(
=
(
-a
1
=
1
และการยกเลิก]
เท่านั้นจึงไม่สามารถแยกวิเคราะห์ได้ว่าวงเล็บเปิดจะเริ่มการแสดงออกหรือไม่มีการ ดำเนินการและเกี่ยวข้อง แน่นอนว่าการแยกวิเคราะห์เป็นสองการเปรียบเทียบสตริงเป็นไปได้ แต่การทำอย่างโลภอย่างที่อาจทำให้เกิดปัญหาเมื่อนำไปใช้กับการแสดงออกที่เหมาะสมกับการแสดงออกย่อยย่อยวงเล็บ
ปัญหาที่แท้จริงคือเชลล์[
ในตัวทำงานในลักษณะเดียวกันราวกับว่ามันขยายค่าx
ก่อนที่จะตรวจสอบนิพจน์
(ความกำกวมเหล่านี้และอื่น ๆ ที่เกี่ยวข้องกับการขยายตัวของตัวแปรเป็นสาเหตุใหญ่ที่ทำให้ Bash ดำเนินการและตอนนี้แนะนำให้ใช้[[ ... ]]
นิพจน์ทดสอบแทน)
วิธีแก้ปัญหาเล็กน้อยและมักพบเห็นในสคริปต์ที่ใช้sh
เชลล์รุ่นเก่า คุณเพิ่มอักขระ "ปลอดภัย" ซึ่งมักจะx
อยู่ด้านหน้าของสตริง (ทั้งสองค่าจะถูกเปรียบเทียบ) เพื่อให้แน่ใจว่านิพจน์ได้รับการยอมรับว่าเป็นการเปรียบเทียบสตริง:
[ "x$x" = "x(" -a "x$y" = "x1" ]
[[ "$x" = '1' && "$y" = '1' ]]