คำพูดซ้อนคู่ในหนึ่งคะแนนโหวตสูง


20

คำตอบ StackOverflow ด้วย> 3.5K โหวตให้คุณสมบัติหนึ่งซับสำหรับการกำหนดไปDIRยังไดเรกทอรีของสคริปต์ทุบตีปัจจุบัน:

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

ฉันงงกับคำพูดซ้อนคู่ เท่าที่ฉันสามารถบอกได้ชิ้นส่วนต่อไปนี้เป็นเครื่องหมายคำพูดคู่:

"$( cd "
"${BASH_SOURCE[0]}"
" && pwd )"

... และทุกอย่างอื่นทางด้านขวาของ=(เช่น$( dirnameและ)) ไม่มีการอ้างอิง ในคำอื่น ๆ ฉันคิดว่าตัวละครที่ 2, 4 และ 6 ""ปิด" ตัวที่ 1, 3 และ 5 "ตามลำดับ

ฉันเข้าใจว่าการเสนอราคาสองเท่าในการ"${BASH_SOURCE[0]}"บรรลุผลสำเร็จ แต่อะไรคือจุดประสงค์ของการเสนอราคาสองคู่อื่น ๆ

หากในอีกทางหนึ่ง (และคะแนนโหวตสูงถึงแม้จะมี) ตัวอย่างข้างต้นไม่ถูกต้องสิ่งที่เป็นวิธีที่เหมาะสมเพื่อให้บรรลุเจตนาที่ระบุ?

(โดยเจตนาที่ระบุฉันหมายถึง: รวบรวมค่าที่ส่งคืนโดยpwdหลังจากการcdเข้าสู่ไดเรกทอรีที่ส่งคืนโดยครั้งแรกdirname "${BASH_SOURCE[0]}"และทำการcd-ing ใน sub-shell เพื่อให้$PWDเชลล์ parent ยังคงไม่เปลี่ยนแปลง)


1
มันเป็นเพราะคุณสมบัติของ $ ( ... ) $( here, it's a subshell, but you are writing code as if you were writing it on the "first level" of the shell .... )ที่อยู่:
Olivier Dulac

ฉันมาที่นี่เพราะสคริปต์ติดตั้งนักเทียบท่า เพื่อค้นหาชื่อของ distro:lsb_dist="$(. /etc/os-release && echo "$ID")"; echo "$lsb_dist"
David Tonhofer

โปรดทราบว่าไม่จำเป็นต้องใช้ช่องว่างในบรรทัด: ใช้DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"งานได้เช่นกัน
David Tonhofer

คำตอบ:


12

ปริศนาของคุณไม่ถูกต้องเกี่ยวกับวิธีที่bash(และเชลล์โดยทั่วไป) แยกวิเคราะห์อินพุต ใน:

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

ขั้นแรกให้bashแยกทางด้านขวามือของการกำหนดให้กับสตริงที่ยาวหนึ่งอัน$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )เนื่องจากเครื่องหมายคำพูดคู่สามารถปรากฏในเครื่องหมายคำพูดคู่ได้

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

cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd

เชลล์แยกวิเคราะห์คำสั่ง compound ดังกล่าวต่อไปแบ่งเป็นสองส่วน:

  • cd "$( dirname "${BASH_SOURCE[0]}" )"
  • รหัสผ่าน

จากนั้นใช้กฎการแยกวิเคราะห์แบบเดียวกันcd "$( dirname "${BASH_SOURCE[0]}" )"แต่คราวนี้การเสนอราคาซ้ำไม่ได้ซ้ำซ้อน แต่สมเหตุสมผล พวกเขาป้องกันการแยกฟิลด์ตามผลลัพธ์$( dirname "${BASH_SOURCE[0]}" )และการขยายของ${BASH_SOURCE[0]}(ตรงกันข้ามกับเครื่องหมายอัญประกาศคู่นอกส่วนใหญ่จะไม่จำเป็นใน RHS ของการกำหนดตัวแปรเพื่อป้องกันsplit+glob )


กฎนี้นำไปใช้แทนคำสั่งในทุกเปลือก POSIX ขึ้นปริศนารายละเอียดที่คุณสามารถอ่านในส่วนของการรับรู้ Token POSIX ข้อมูลจำเพาะ


21

เมื่อมีสิ่งใดสิ่งหนึ่งอยู่ภายในการ$(...)อ้างอิงจะเริ่มต้นใหม่ทั้งหมดตั้งแต่ต้น

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

ดังนั้นให้พิจารณา:

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

ข้างใน$(...)คือ:

dirname "${BASH_SOURCE[0]}"

ในข้างต้น${BASH_SOURCE[0]}เป็นคู่ที่ยกมา เครื่องหมายอัญประกาศคู่หรือเดี่ยวด้านนอกใด ๆ$(...)จะไม่เกี่ยวข้องเมื่อพิจารณาว่า${BASH_SOURCE[0]}เป็นเครื่องหมายคำพูดคู่

ด้านนอก$(...)ประกอบด้วย:

cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd

ที่นี่การแสดงออก$( dirname "${BASH_SOURCE[0]}" )เป็นคู่ที่ยกมา ความจริงที่ว่ามีคำพูดอยู่ด้านนอกด้านนอก$(...)นั้นไม่เกี่ยวข้องเมื่อพิจารณาจากสิ่งที่อยู่ข้างใน ความจริงที่ว่ามีคำพูดอยู่ภายใน$(...)ก็ไม่เกี่ยวข้องเช่นกัน

นี่คือการจับคู่คำพูดคู่กัน:

ป้อนคำอธิบายรูปภาพที่นี่


คุณหมายถึงirrelevantอะไร ยกเว้นวงเล็บส่วนใหญ่ด้านนอกอื่น ๆ ทั้งหมดมีความหมายของตัวเอง
cuonglm

4
และนี่คือเหตุผลที่คุณไม่ควรใช้ backticks: กฎการอ้างถึงแปลกมากและไม่ง่าย
Wildcard

ประโยค“ $(...)ผูกแน่นกว่า"..."” ไม่สมเหตุสมผล พวกเขาไม่ใช่ผู้ดำเนินการมัดและไม่มีลำดับชั้นระหว่างพวกเขา (ถ้ามีก็หมายความว่าอัญประกาศไม่สามารถอยู่ในวงเล็บหรือวงเล็บไม่สามารถอยู่ในเครื่องหมายคำพูด แต่นั่นไม่ใช่กรณี) คำศัพท์ทางเทคนิคคือ$(…)และ"…"รัง
Gilles 'หยุดความชั่วร้าย'

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