TL; DR : ทำไมช่องว่างกลุ่ม POSIX รั้งจำเป็นหลังจาก{
คำสงวน แต่ subshell ไม่หลังจากคำสงวน(
?
ไวยากรณ์ของ POSIX เชลล์กำหนดกลุ่มวงเล็บปีกกาและ subshell ดังนี้
brace_group : Lbrace compound_list Rbrace
subshell : '(' compound_list ')'
ทีนี้ถ้าเราอ่านว่าช่องว่างนั้นสำคัญมาก นี่หมายความว่าจะต้องมีพื้นที่ที่แยกเปิดและปิดวงเล็บปีกกาและวงเล็บเช่นเดียวกับใน
{ echo hello world; }
( echo hello world )
สิ่งนี้จะสอดคล้องกับคำสั่งคำสั่งผสม :
คำสั่งผสมเหล่านี้แต่ละคำมีคำที่สงวนไว้หรือผู้ดำเนินการควบคุมในตอนเริ่มต้นและคำที่สงวนไว้สำหรับคำสั่งสุดท้ายหรือคำว่าผู้ประกอบการที่เกี่ยวข้องในตอนท้าย
อย่างไรก็ตามสิ่งที่ไม่สมเหตุสมผลคือเหตุผล(list)
และ( list )
ทำงานได้ดี ( (
ไม่จำเป็นต้องใช้พื้นที่นั้นหลังจากนั้น) อย่างไรก็ตามการขยายตัวของรั้งต้องมีพื้นที่ชั้นนำเช่น{echo hello;}
ไม่ทำงาน
แน่นอนว่าคำที่สงวนไว้ซึ่งได้รับการปฏิบัติเหมือนคำว่าเชลล์จำเป็นต้องเว้นวรรคเพื่อให้สอดคล้องกับแนวคิดของการแยกฟิลด์อย่างไรก็ตามคำจำกัดความของตัวเองไม่ได้พูดถึงช่องว่าง นอกจากนี้หาก{
และ(
ทั้งคู่ถือว่าคำที่สงวนไว้โดยนิยาม POSIX ของคำสั่งผสมทำไมพวกเขาถึงได้รับการปฏิบัติที่แตกต่างกันเกี่ยวกับอักขระช่องว่างหลังจากคำที่สงวนไว้เหล่านี้? ตอนนี้คู่มือksh (1)ไม่ระบุสถานะ:
คำซึ่งเป็นลำดับของอักขระถูกคั่นด้วยอักขระช่องว่างสีขาว (ช่องว่างแท็บและขึ้นบรรทัดใหม่) หรืออักขระเมตา (<,>, |,;, และ (และ))
กล่าวอีกนัยหนึ่งมันสมเหตุสมผลแล้วที่ ksh จะจำได้(
ว่าเป็นตัวคั่นคำโดยที่คำแรกจะเป็นคำสั่งหรือการกำหนดตัวแปร POSIX แต่ดูเหมือนจะไม่พูดถึง(
ว่าเป็นตัวละครเมตา คำอธิบายที่เป็นไปได้เพียงอย่างเดียวที่ฉันพบเท่าที่ POSIX ไวยกรณ์ไป{
คือถือเป็น "โทเค็น" โดยที่(
ไม่อยู่ในรายการเดียว
/* These are reserved words, not operator tokens, and are
recognized when reserved words are recognized. */
%token Lbrace Rbrace Bang
/* '{' '}' '!' */
ดังนั้นอะไรคือเหตุผลที่แม่นยำสำหรับความคลาดเคลื่อนนี้
หมายเหตุคำตอบที่ยอมรับได้:
ย้ายเครื่องหมายถูกที่ตอบรับไปยังคำตอบของไอแซคเนื่องจากมีรูปแบบมาตรฐานซึ่งตรงกับคำถามของฉัน:
ตัวอย่างเช่น '(' และ ')' เป็นตัวดำเนินการควบคุมดังนั้นจึงไม่
<space>
จำเป็นใน (รายการ) อย่างไรก็ตาม '{' และ '}' เป็นคำที่สงวนไว้ใน {list;} ดังนั้นในกรณีนี้การนำหน้า<space>
และ<semicolon>
จำเป็นยอมรับคำตอบของKusalanandaคำตอบของ Kusalananda กล่าวถึงสิ่งที่ฉันต้องการ แต่ส่วนใหญ่มาจากมุมมองที่ไม่เป็นทางการและเป็นธรรมชาติ มันชี้ให้เห็น{
ว่าเป็นคำสงวนและ(
เป็นผู้ประกอบการ ไมเคิลโฮเมอร์ก็สังเกตเห็นเหมือนกันในความคิดเห็น - ที่คำจำกัดความคำสั่งผสม (เน้นเพิ่ม):คำสั่งรวมเหล่านี้แต่ละคำมีคำที่สงวนไว้หรือผู้ดำเนินการควบคุมที่จุดเริ่มต้น
{
ถูกกำหนดให้เป็นคำสงวนคล้ายกับfor
หรือwhile
อยู่ในรายการในไวยากรณ์ของเชลล์ (ดูบล็อกรหัสสุดท้ายในคำถาม)มาตรา 2.9 ฯ (เน้นเพิ่ม):
โดยเฉพาะการรับรองรวมถึงการเว้นวรรคระหว่างโทเค็นในบางสถานที่ที่
<blank>
ไม่จำเป็นต้องใช้ s (เมื่อโทเค็นตัวใดตัวหนึ่งเป็นตัวดำเนินการ)ในขณะที่มาตรฐานไม่ได้กำหนดอย่างชัดเจน
(
ว่าเป็นโอเปอเรเตอร์(
จะถูกอ้างถึงเป็นโอเปอเรเตอร์ โดยเฉพาะอย่างยิ่งส่วน 2.9.2พูดว่าหากท่อเริ่มต้นด้วยคำสงวน! และ command1 เป็นคำสั่ง subshell แอปพลิเคชั่นจะต้องแน่ใจว่า (ตัวดำเนินการที่จุดเริ่มต้นของ command1 ถูกแยกออกจาก! ด้วยอักขระหนึ่งตัวหรือมากกว่าพฤติกรรมของคำที่สงวนไว้! ตามด้วยตัวดำเนินการทันที
คำถามเกี่ยวกับ Stack Overflowโดย Digital Trauma ชี้ให้เห็นส่วนที่ 2.4 ในคำสงวน:
การรับรู้นี้จะเกิดขึ้นก็ต่อเมื่อไม่มีการอ้างถึงตัวละครและเมื่อใช้คำว่า:
- คำแรกของคำสั่ง
ดังที่กล่าวไว้ในคำตอบของ Kusalananda "ช่องว่างที่แสดงในไวยากรณ์ POSIX ไม่ใช่ช่องว่างที่จำเป็นต้องมีในข้อมูลอินพุตเชลล์ แต่เป็นเพียงวิธีแสดงไวยากรณ์เองมันเป็นความจริงที่วงเล็บปีกกาเป็นคำสงวนที่มีความหมายว่า พวกเขาจะต้องถูกล้อมรอบด้วยช่องว่าง "ตามที่กล่าวไว้โดยไมเคิลโฮเมอร์ในความคิดเห็น:" ถ้าช่องว่างมีความสำคัญในสิทธิของตนเองพวกเขาจะต้องระบุไว้ในการผลิต "
ปิดคดี.
{
และ(
ทั้งคู่ถือว่าคำที่สงวนไว้โดยนิยาม POSIX ของคำสั่งผสม" cf msgstr "คำสั่งผสมเหล่านี้แต่ละคำมีคำสงวนหรือโอเปอเรเตอร์ควบคุมที่จุดเริ่มต้น".
' '
) แต่ช่องว่างจะถูกบอกเป็นนัย ๆ ว่าโทเค็นคืออะไร
command : simple_command | compound_command | compound_command redirect_list | function_definition ;
การผลิตที่บอกว่าคุณสามารถมีคำสั่งได้ที่ใดมันสามารถเป็นหนึ่งในคำสั่งอย่างง่ายคำสั่งผสมหรือคำสั่งผสมที่มีการเปลี่ยนเส้นทางหรือนิยามฟังก์ชัน