ทำไมต้องใช้เครื่องหมายคำพูดคู่ในการทดสอบ [[]]


23

สมมติว่าเรามีจำนวนเต็ม 2 ตัวในสคริปต์ทุบตี:

value1=5
value2=3

แล้วทำไมเราต้องใช้เครื่องหมายคำพูดคู่ในกรณีของการทดสอบ? ตัวอย่างเช่น:

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

ทำไมไม่ลองใช้สิ่งต่อไปนี้?

if [[ $value1 -eq $value2 ]]

สำหรับฉันการเสนอราคาสองครั้งไม่สมเหตุสมผลเลย


5
การอ้างถึงเชลล์นั้นมีส่วนเกี่ยวข้องกับสตริงเพียงเล็กน้อย (เช่นเดียวกับชนิดข้อมูล) มันเกี่ยวกับการป้องกันเชลล์ไม่ให้ทำการแยกคำ (และการขยายประเภทอื่น ๆ )
filbranden

13
ในขณะที่ terdon ชี้ให้เห็นมันไม่จำเป็นต้องอ้างถึงตัวแปรในโครงสร้างเฉพาะนี้ (และแน่นอนด้วยหนึ่งคำ - ค่าที่ใดก็ได้) ฉันต้องการให้คำแนะนำในการพูด vars ของคุณเสมอ คุณรู้หรือไม่ว่าในบริบทใดที่คุณสามารถปล่อยให้ตัวแปรไม่ได้ระบุไว้? เหตุผลในการอ้างถึงแม้ว่าจะไม่จำเป็นด้วย5และ3ก็คือการบำรุงรักษา ค่าอาจเปลี่ยนแปลงในภายหลังและข้อผิดพลาดที่เกิดขึ้นอาจไม่ชัดเจน
Peter - Reinstate Monica

2
@sudodus ฉันไม่คิดว่าเป็นความจริงสำหรับเพียงเพื่อ[[ ]] [ ]
Benjamin W.

1
คุณถูก @BenjaminW การแยกคำไม่ได้เป็นเพียงกรณีเดียวเท่านั้นจึงเป็นความคิดที่ดีที่จะใช้เครื่องหมายคำพูดคู่สำหรับตัวแปร นอกจากนี้ยังมีกรณีเมื่อตัวแปรว่างเปล่า ที่จะทำให้คำสั่งใน [] ล้มเหลว (เช่น [2 -eq] ที่มีข้อผิดพลาด แต่ [[]] ไม่ได้รับความเสี่ยง (เช่นกรณีที่มีการแยกคำ)
sudodus

2
@marcelm, Bash, ksh และ Zsh มีตัวแปรจำนวนเต็มและภายใน[[ ]]ยังบังคับให้ตัวถูกดำเนินการ-eqเป็นจำนวนเต็ม
ilkkachu

คำตอบ:


7

การแยกคำ

ตัวอย่างนี้ไม่น่าจะเป็นไปได้แต่เป็นไปได้ดังนั้นหากคุณต้องการโค้ดป้องกันให้ครอบคลุมแทร็กของคุณด้วยเครื่องหมายคำพูด:

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

ตกลงดีทั้งหมดจนถึงตอนนี้ ลองโยนประแจเข้าเกียร์:

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

อุ่ย

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

อ่า


2
แต่ OP ใช้วงเล็บคู่ดังนั้นจึงไม่มีการแบ่งคำ
user000001

5
ใช่มันไม่เกี่ยวข้องกับการ[[ ]]สร้างของ bash
terdon

1
ใช่มั้ย? [ $value1 -eq $value2 ]ด้วยที่ว่างเปล่าvalue1จะ'[' -eq 3 ']'ไม่มี''ทางด้านซ้ายมือ
Charles Duffy

ฉันก็แปลกใจเหมือนกัน แต่ก็มีหลักฐาน
เกล็นแจ็คแมน

1
คำตอบนี้ไม่ได้โดยตรงที่เกี่ยวข้องกับคำถามที่ว่า ฉันประหลาดใจที่มันได้รับการยอมรับ การตั้งค่าเป็นวิกิชุมชน
เกล็นแจ็คแมน

35

คุณไม่จำเป็นต้องใส่เครื่องหมายคำพูดที่นี่ นี่เป็นหนึ่งในไม่กี่กรณีที่ปลอดภัยที่จะใช้ตัวแปรที่ไม่มีเครื่องหมาย คุณสามารถยืนยันสิ่งนี้ด้วย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!

ตามที่คุณเห็นด้านบนการทดสอบที่ยกมาและไม่มีการอ้างอิงจะได้รับการแก้ไขในสิ่งเดียวกันโดยการทุบตี แบบเดียวกันควรจะเป็นจริงสำหรับzshและฉันคิดว่าเปลือกอื่น ๆ ที่สนับสนุน[[ ]]ผู้ประกอบการ

โปรดทราบว่านี่ไม่ใช่กรณีที่พกพาได้มากกว่า[ ]:

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

การ[ ]สร้างซึ่งแตกต่างจากการก่อสร้าง[[ ]]จะต้องมีการอ้างอิง


ลิงก์ที่มีประโยชน์บางอย่างเพื่อเรียนรู้เพิ่มเติมเกี่ยวกับเวลาและเหตุผลที่ต้องมีการอ้างข้อความ


ในกรณีนี้ที่มีตัวแปรจำนวนเต็มจะเป็นการดีกว่าถ้าจะประกาศให้เป็นเช่นนั้น declare -i var1=คือ0เมื่อประเมิน
Freddy

4
ทราบว่า-eqเป็นทางคณิตศาสตร์การเปรียบเทียบเพื่อให้คุณยังสามารถออกจาก$ออก (ใน[[ .. ]]) [[ a -eq b ]]และการเขียน ด้วยการเปรียบเทียบสตริงคุณต้องการ$แน่นอนดังนั้น[[ $a = $b ]]
ilkkachu

2
@ user000001 จุดที่ดี ถึงแม้ว่าแน่นอนว่าเป็นไปได้มากที่คุณต้องการขยายออก ตัวอย่างเช่นฉันคาดว่าสิ่งนี้จะเป็นการแข่งขัน: var1="afoob"; var2="a*b"; [[ $var1 = $var2 ]] && echo match. หากคุณต้องการใช้ตัวอักษรแบบกลมโดยไม่แสดงตัวเป็นแบบกลมในบริบทแบบวนรอบ (เช่น[[ ]]) คุณต้องพูดใช่
terdon

3
@ilkkachu นั่นทำให้ฉันประหลาดใจ ฉันคิดว่าตัวแปร "เปล่า" จะได้รับการพิจารณาภายในตัวห้อยอาร์เรย์((...))หรือ$((...)เท่านั้น ดูเหมือนว่าจะใช้งานได้ แต่ (ชายชราอารมณ์เสียเปิดใช้งาน) ฉันไม่ชอบ
เกล็นแจ็คแมน

1
@glennjackman ก็ดีขออภัยที่เป็นคนหนึ่งที่บอกคุณว่า แต่ใช่ตัวถูกดำเนินการ-eqและเพื่อน ๆ ข้างใน[[ ]]เป็นบริบททางคณิตศาสตร์เช่นกัน :) (ที่เกี่ยวข้อง: การขยายตัวแปรอัตโนมัติภายในคำสั่ง bash [[]] )
ilkkachu

17

แม้ว่าจะไม่จำเป็นต้องใช้เครื่องหมายคำพูดคู่ แต่เหตุผลในการใช้ก็คือ:

  • ดีปฏิบัติ / นิสัย: ในนี้กรณีที่พวกเขาไม่จำเป็นต้องมี แต่โดยทั่วไปราคาคู่มีการหลีกเลี่ยงการแยกคำที่ไม่ได้ตั้งใจ
  • เพราะvalue1และvalue2เป็นตัวแปรและคุณอาจไม่ทราบว่ามีอะไรบ้าง ไม่เช่นนั้นคุณอาจถามว่า "ทำไมต้องรำคาญกับตัวแปรแทนที่จะตรวจสอบif [[ 5 -eq 3 ]]หรือเอามันไปทำไมต้องใส่ใจกับifสิ่งนั้นเมื่อคุณรู้แล้วว่า 5 ไม่เท่ากับ 3? มันมักจะดีกว่าที่จะป้องกัน (มันเป็นเรื่องจริง การแยกคำนั้นจะไม่เกิดขึ้น[[แต่ในกรณีที่การแบ่งคำไม่เกิดขึ้นจะหายากอีกครั้งดูที่จุดแรก)

1

ไม่เกี่ยวข้องกับคำถามของคุณโดยตรง แต่ฉันใช้

ถ้า (($ value1 == $ value2)); แล้วก็

เมื่อฉันเปรียบเทียบตัวเลข แต่คุณก็ไม่จำเป็นต้องใช้เครื่องหมายคำพูด


2
if (( value1 == value2 )); then. $ในบริบทเลขคณิตคุณไม่จำเป็นที่จะต้อง อย่างไรก็ตามคำถามนี้ดูเหมือนจะมุ่งเน้นไปที่ตัวแปรที่ใช้ใน[[ ... ]]การทดสอบ
Kusalananda

1
ฉันรู้ว่า. แต่ฉันไม่ได้ใช้คุณสมบัตินี้เพราะฉันต้องการให้ชื่อตัวแปรของฉันสอดคล้องและใช้ $ เป็นคำนำหน้าตลอดเวลา
framp

1

คุณพูดถูก!

การอ้างถึงภายในวงเล็บเหลี่ยมสองชั้นไม่สมเหตุสมผลเลยอย่างน้อยก็ในกรณีนี้

แต่เนื่องจากผมใช้คำพูดสองในชีวิตประจำวัน - โดยเฉพาะอย่างยิ่งสำหรับการแสดงออกเดียววงเล็บเหลี่ยมผ่านการขัดแย้งในการทำงานและการใช้สคริปต์เช่นเดียวกับการกำหนดตัวแปรบางครั้ง (ซึ่งจะไม่ได้ผลอย่างสมบูรณ์สำหรับ delcarations ง่าย) - ผมคิดว่าบางคนอย่างน้อยฉันทำ เขียนคำพูดสองรอบการขยายตัวแปรสัญชาตญาณ

การอ้างอิงสองครั้งสามารถช่วยให้คุณประหยัดได้ มันเหมือนกลับบ้านที่มีเครื่องหมายคำพูดคู่กัน - D. Kummer

ประโยชน์ของการทำคำพูดคู่จึงและที่เข้าใจ - แต่มันทำให้รู้สึก - คือว่าเพื่อนร่วมงานที่ยังใหม่กับทุบตีสามารถเรียนรู้วิธีการเขียนสคริปต์มีเสถียรภาพมากขึ้น นอกจากนี้ยังเน้นความจริงที่ว่าศิลปะของการประมวลผลข้อมูลที่มีทุบตีเป็นเรื่องเกี่ยวกับการแยกกระแสข้อมูล (รวมถึงตัวแปร) โดยแยกสนามและท่อพวกเขาผ่านฟิลเตอร์ ทันทีที่คุณแยกชิ้นข้อมูลออกจากสตรีมให้จับคู่กับเครื่องหมายคำพูดคู่กัน!

ประโยชน์ก็อาจจะดีกว่าการอ่านสคริปต์ทุบตีกับสตริงที่ยกมาสองครั้งภายในแก้ไขรหัสไฮไลต์

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.