ดูเหมือนว่ามีบางคนเข้าใจผิดเกี่ยวกับ Bash builtin trueและที่เฉพาะเจาะจงมากขึ้นเกี่ยวกับวิธีที่ Bash ขยายและตีความนิพจน์ภายในวงเล็บ
รหัสในคำตอบของ mikuนั้นไม่มีอะไรเกี่ยวข้องกับ Bash builtin trueหรือ/bin/trueอย่างใดtrueอย่างหนึ่ง ในกรณีtrueนี้ไม่มีอะไรมากไปกว่าสตริงอักขระแบบง่าย ๆ และไม่มีการเรียกtrueคำสั่ง / บิลด์อินใด ๆ เลยไม่ว่าจะเป็นการกำหนดตัวแปรหรือการประเมินนิพจน์เงื่อนไข
รหัสต่อไปนี้เป็นหน้าที่เหมือนกับรหัสในคำตอบของ miku:
the_world_is_flat=yeah
if [ "$the_world_is_flat" = yeah ]; then
echo 'Be careful not to fall off!'
fi
ข้อแตกต่างเพียงอย่างเดียวที่นี่คือการเปรียบเทียบอักขระสี่ตัวคือ 'y', 'e', 'a' และ 'h' แทน 't', 'r', 'u' และ 'e' แค่นั้นแหละ. มีความพยายามไม่ทำเพื่อเรียกคำสั่งหรือการ builtin ชื่อเป็นyeahและไม่มี (ในตัวอย่างของ Miku) เรียงลำดับใด ๆ trueของการจัดการพิเศษที่เกิดขึ้นเมื่อทุบตีแยกโทเค็น มันเป็นเพียงแค่สตริงและหนึ่งในนั้น
Update (2014-02-19):หลังจากติดตามลิงก์ในคำตอบของ miku ตอนนี้ฉันเห็นว่าความสับสนมาจากไหน คำตอบของ Miku ใช้เครื่องหมายวงเล็บเดียว แต่ข้อมูลโค้ดที่เขาลิงก์ไปนั้นไม่ได้ใช้วงเล็บ มันเป็นเพียง:
the_world_is_flat=true
if $the_world_is_flat; then
echo 'Be careful not to fall off!'
fi
ตัวอย่างโค้ดทั้งสองจะทำงานในลักษณะเดียวกัน แต่วงเล็บจะเปลี่ยนสิ่งที่เกิดขึ้นภายใต้ประทุนอย่างสมบูรณ์
นี่คือสิ่งที่ Bash ทำในแต่ละกรณี:
ไม่มีวงเล็บ:
- ขยายตัวแปรสตริง
$the_world_is_flat"true"
- พยายามแยกสตริง
"true"เป็นคำสั่ง
- ค้นหาและเรียกใช้
trueคำสั่ง (ทั้งในตัวหรือ/bin/trueขึ้นอยู่กับรุ่น Bash)
- เปรียบเทียบรหัสทางออกของ
trueคำสั่ง (ซึ่งเป็น 0 เสมอ) กับ 0 เรียกคืนว่าในเชลล์ส่วนใหญ่รหัสทางออก 0 หมายถึงความสำเร็จและสิ่งอื่น ๆ บ่งชี้ความล้มเหลว
- เนื่องจากรหัสออกเป็น 0 (สำเร็จ) ให้รันประโยค
ifของthenคำสั่ง
วงเล็บ:
- ขยายตัวแปรสตริง
$the_world_is_flat"true"
string1 = string2แยกนิพจน์เงื่อนไขในขณะนี้อย่างเต็มที่ขยายตัวซึ่งเป็นของแบบฟอร์ม =ผู้ประกอบการคือการทุบตีของการเปรียบเทียบสตริงประกอบการ ดังนั้น...
- ทำเปรียบเทียบสตริงและ
"true""true"
- ใช่ทั้งสองสายเหมือนกันดังนั้นค่าของเงื่อนไขเป็นจริง
- ดำเนินการ
ifคำสั่งของthenประโยค
รหัส no-brackets ทำงานได้เนื่องจากtrueคำสั่งส่งคืนรหัสออกเป็น 0 ซึ่งบ่งชี้ความสำเร็จ รหัสวงเล็บทำงานเพราะค่าของ$the_world_is_flatเป็นเหมือนตัวอักษรสตริงที่ด้านขวาของtrue=
เพียงขับรถกลับบ้านให้พิจารณาโค้ดสองตัวอย่างต่อไปนี้:
รหัสนี้ (หากทำงานด้วยสิทธิ์พิเศษระดับราก) จะรีบูตคอมพิวเตอร์ของคุณ:
var=reboot
if $var; then
echo 'Muahahaha! You are going down!'
fi
รหัสนี้แค่พิมพ์ "ลองดี" คำสั่ง reboot ไม่ได้ถูกเรียก
var=reboot
if [ $var ]; then
echo 'Nice try.'
fi
Update (2014-04-14)เพื่อตอบคำถามในความคิดเห็นเกี่ยวกับความแตกต่างระหว่าง=และ==: AFAIK ไม่มีความแตกต่าง ==ประกอบเป็นคำพ้องทุบตีที่เฉพาะเจาะจงสำหรับ=, และเท่าที่ผมเคยเห็นพวกเขาทำงานเหมือนกันในทุกบริบท
อย่างไรก็ตามโปรดทราบว่าฉันกำลังพูดถึงตัวดำเนินการเปรียบเทียบ=และ==สตริงโดยเฉพาะที่ใช้ในการทดสอบ[ ]หรือ [[ ]]ฉันไม่ได้แนะนำสิ่งนั้น=และ==สามารถใช้แทนกันได้ทุกที่ในการทุบตี
ตัวอย่างเช่นคุณไม่สามารถกำหนดค่าตัวแปรได้==อย่างชัดเจนเช่นvar=="foo"(ในทางเทคนิคคุณสามารถทำสิ่งนี้ได้ แต่ค่าvarจะเป็น"=foo"เพราะ Bash ไม่เห็น==ผู้ประกอบการที่นี่เห็นผู้ดำเนินการ=(ที่ได้รับมอบหมาย) ตามด้วย ค่าตัวอักษร="foo"ซึ่งเพิ่งจะกลายเป็น"=foo")
นอกจากนี้แม้ว่า=และ==สามารถใช้แทนกันคุณควรเก็บไว้ในใจว่าวิธีการที่ทำงานการทดสอบไม่ขึ้นอยู่กับว่าคุณกำลังใช้ภายใน[ ]หรือ[[ ]]และยังหรือไม่ว่าตัวถูกดำเนินการที่มีการอ้าง คุณสามารถอ่านเพิ่มเติมเกี่ยวกับสิ่งนั้นได้ในคู่มือการใช้สคริปต์การทุบตีขั้นสูง: 7.3 ตัวดำเนินการเปรียบเทียบอื่น ๆ (เลื่อนลงไปที่การอภิปราย=และ==)
trueและfalseในบริบทของตัวอย่างส่วนใหญ่ที่อยู่ด้านล่างเป็นเพียงสตริงธรรมดาไม่bash built-ins!!! โปรดอ่านคำตอบของ Mike Holt ด้านล่าง (นี่คือตัวอย่างหนึ่งที่คำตอบที่ได้รับการโหวตอย่างสูงและได้รับการยอมรับคือ IMHO ทำให้เกิดความสับสนและเงาเนื้อหาที่ลึกซึ้งในคำตอบที่ได้รับการโหวตน้อยกว่า)