นี่เป็นกรณีมุมที่คลุมเครือมากซึ่งอาจพิจารณาข้อผิดพลาดในวิธีการทดสอบ[ในตัว อย่างไรก็ตามมันตรงกับพฤติกรรมของ[ไบนารีจริงที่มีอยู่ในหลาย ๆ ระบบ เท่าที่ผมสามารถบอกได้ว่ามันมีผลเฉพาะบางกรณีและตัวแปรที่มีค่าที่ตรงกับที่[ผู้ประกอบการเช่น(, !, =, -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' ]]