จากสิ่งที่ฉันได้อ่านการวางคำสั่งในวงเล็บควรเรียกใช้ใน subshell คล้ายกับการเรียกใช้สคริปต์ ถ้าเป็นจริงมันจะเห็นตัวแปร x ถ้า x ไม่ถูกส่งออกได้อย่างไร
x=1
การรัน(echo $x)
บนบรรทัดคำสั่งจะส่งผลให้ 1
การรันecho $x
สคริปต์จะไม่ส่งผลอะไรตามที่คาดไว้
จากสิ่งที่ฉันได้อ่านการวางคำสั่งในวงเล็บควรเรียกใช้ใน subshell คล้ายกับการเรียกใช้สคริปต์ ถ้าเป็นจริงมันจะเห็นตัวแปร x ถ้า x ไม่ถูกส่งออกได้อย่างไร
x=1
การรัน(echo $x)
บนบรรทัดคำสั่งจะส่งผลให้ 1
การรันecho $x
สคริปต์จะไม่ส่งผลอะไรตามที่คาดไว้
คำตอบ:
เชลล์ย่อยเริ่มต้นเป็นสำเนาที่เหมือนกันเกือบของกระบวนการเชลล์เริ่มต้น ภายใต้ประทุนเปลือกเรียกfork
ระบบโทร1ซึ่งจะสร้างกระบวนการใหม่ที่มีรหัสและหน่วยความจำที่เป็นสำเนา2 เมื่อสร้างเชลล์ย่อยมีความแตกต่างน้อยมากระหว่างมันกับพาเรนต์ โดยเฉพาะพวกเขามีตัวแปรเดียวกัน แม้แต่$$
ตัวแปรพิเศษยังคงค่าเดียวกันใน subshells: เป็นรหัสกระบวนการของเชลล์ดั้งเดิม ในทำนองเดียวกัน$PPID
เป็น PID ของผู้ปกครองของเปลือกเดิม
เชลล์บางตัวเปลี่ยนตัวแปรบางตัวในเชลล์ย่อย Bash ตั้งค่าBASHPID
เป็น PID ของกระบวนการเชลล์ซึ่งเปลี่ยนเป็น subshells Bash, zsh และ mksh จัด$RANDOM
ให้มีค่าที่แตกต่างกันในผู้ปกครองและใน subshell แต่นอกเหนือจากกรณีพิเศษในตัวเช่นนี้ตัวแปรทั้งหมดมีค่าเหมือนกันในเชลล์ย่อยในเชลล์ดั้งเดิมสถานะการเอ็กซ์พอร์ตเดียวกันสถานะอ่านอย่างเดียวเดียวกัน ฯลฯ นิยามฟังก์ชันทั้งหมดนิยาม alias และตัวเลือกเชลล์และ การตั้งค่าอื่น ๆ ได้รับการสืบทอดเช่นกัน
เชลล์ย่อยที่สร้างโดย(…)
มีตัวให้คำอธิบายไฟล์เดียวกับผู้สร้าง วิธีการอื่นในการสร้าง subshells แก้ไขไฟล์ descriptor บางตัวก่อนเรียกใช้งานรหัสผู้ใช้ ตัวอย่างเช่นด้านซ้ายมือของไปป์วิ่งใน subshell 3กับเอาต์พุตมาตรฐานที่เชื่อมต่อกับไปป์ เชลล์ย่อยเริ่มต้นด้วยไดเรกทอรีปัจจุบันเดียวกัน, หน้ากากสัญญาณที่เหมือนกัน, ฯลฯ หนึ่งในข้อยกเว้นบางประการคือ subshells ไม่สืบทอดกับดักที่กำหนดเอง: ละเว้นสัญญาณ ( ) ยังคงถูกละเว้นใน subshell แต่กับดักอื่น ๆ ( SIGNAL ) ถูกรีเซ็ต เป็นการกระทำเริ่มต้น4 .trap '' SIGNAL
trap CODE
เชลล์ย่อยนั้นแตกต่างจากการเรียกใช้งานสคริปต์ สคริปต์เป็นโปรแกรมแยกต่างหาก โปรแกรมแยกนี้อาจบังเอิญเป็นสคริปต์ซึ่งดำเนินการโดยล่ามเดียวกับผู้ปกครอง แต่บังเอิญนี้ไม่ได้ให้โปรแกรมแยกต่างหากการมองเห็นพิเศษเกี่ยวกับข้อมูลภายในของผู้ปกครอง ตัวแปรที่ไม่ได้ส่งออกมีข้อมูลภายในดังนั้นเมื่อล่ามสำหรับสคริปต์เปลือกเด็กจะดำเนินการก็ไม่ได้ดูตัวแปรเหล่านี้ ตัวแปรที่ส่งออกเช่นตัวแปรสภาพแวดล้อมจะถูกส่งไปยังโปรแกรมที่ดำเนินการ
ดังนั้น:
x=1
(echo $x)
พิมพ์1
เนื่องจากเชลล์ย่อยเป็นการจำลองแบบของเชลล์ที่วางไว้
x=1
sh -c 'echo $x'
เกิดขึ้นกับการเรียกใช้เชลล์เป็นกระบวนการลูกของเชลล์ แต่x
ในบรรทัดที่สองไม่มีการเชื่อมต่อกับx
บนบรรทัดที่สองมากกว่าใน
x=1
perl -le 'print $x'
หรือ
x=1
python -c 'print x'
1 ข้อยกเว้นคือksh93
เปลือกหอยที่มีการปรับการฟอร์กให้เหมาะที่สุดและผลข้างเคียงส่วนใหญ่จะถูกจำลอง
2 ความหมายคือสำเนา จากมุมมองของการนำไปใช้งานมีการแบ่งปันเกิดขึ้นมากมาย
3 สำหรับด้านขวามันขึ้นอยู่กับเปลือก
4 หากคุณทดสอบสิ่งนี้โปรดทราบว่าสิ่งต่าง ๆ เช่น$(trap)
อาจรายงานกับดักของเปลือกเดิม โปรดทราบว่ากระสุนจำนวนมากมีข้อบกพร่องในกรณีมุมที่เกี่ยวข้องกับกับดัก ตัวอย่างเช่นninjaljตั้งข้อสังเกตว่า ณ ทุบตี 4.3 bash -x -c 'trap "echo ERR at \$BASH_SUBSHELL \$BASHPID" ERR; set -E; false; echo one subshell; (false); echo two subshells; ( (false) )'
เรียกใช้ERR
กับดักจาก subshell ที่ซ้อนกันในกรณี "สอง subshells" แต่ไม่ใช่ERR
กับดักจาก subshell กลาง - set -E
ตัวเลือกควรเผยแพร่ERR
กับดักทั้งหมด subshell แต่ subshell กลางได้รับการปรับให้เหมาะสมและดังนั้นจึงไม่ได้มีการเรียกใช้ERR
กับดัก
echo $(x=2; echo $x)
ชิ้นส่วน$(x=2; echo $x)
จะต้องมีการขยาย x=2; echo $x
เรื่องนี้ต้องมีการประเมินคำสั่ง การขยายตัวของที่เกิดขึ้นในระหว่างการประเมินผลนี้หลังจากการประเมินผลส่วนหนึ่ง$x
x=2
x
ตั้งค่า) หรือecho $(echo foo >somefile)${x-$(cat somefile)}
echo $(echo $x),${x=1}
./file
ไม่ได้ดำเนินการใน subshell ดูเพิ่มเติมที่unix.stackexchange.com/q/261638และunix.stackexchange.com/a/157962
เห็นได้ชัดว่าใช่ตามที่เอกสารทั้งหมดกล่าวว่าคำสั่งวงเล็บถูกเรียกใช้ใน subshell
เปลือกย่อยสืบทอดสำเนาของตัวแปรทั้งหมดของผู้ปกครอง ความแตกต่างคือการเปลี่ยนแปลงใด ๆ ที่คุณทำใน subshell นั้นยังไม่ได้ทำใน parent
หน้าคน ksh ทำให้ชัดเจนกว่าทุบตีเล็กน้อย:
man ksh
:คำสั่งวงเล็บถูกดำเนินการในเปลือกย่อยโดยไม่ต้องลบตัวแปรที่ไม่ได้ส่งออก
man bash
:
(
รายการ)
รายการจะถูกดำเนินการในสภาพแวดล้อมของ subshell (ดูคำสั่งการดำเนินการด้านสิ่งแวดล้อมด้านล่าง) การกำหนดตัวแปรและคำสั่ง builtin ที่ส่งผลกระทบต่อสภาพแวดล้อมของเชลล์จะไม่มีผลบังคับใช้หลังจากคำสั่งเสร็จสิ้น
การปฏิบัติตามคำสั่งด้านสิ่งแวดล้อม
เชลล์มีสภาพแวดล้อมการประมวลผลซึ่งประกอบด้วยสิ่งต่อไปนี้: [... ] พารามิเตอร์เชลล์ที่ตั้งค่าโดยการกำหนดตัวแปร [... ]
การทดแทนคำสั่งคำสั่งที่จัดกลุ่มด้วยวงเล็บและคำสั่งแบบอะซิงโครนัสถูกเรียกใช้ในสภาพแวดล้อม subshell ที่ซ้ำซ้อนกับสภาพแวดล้อมของเชลล์ [... ]
When a simple command other than a builtin or shell function is to be executed, it is invoked in a separate execution environment that consists of the following.
ซึ่งมีรายการ: · shell variables and functions marked for export, along with variables exported for the command, passed in the environment
(จากman bash
ส่วนเดียวกัน) ซึ่งอธิบายว่าเหตุใดecho $x
-script จึงไม่พิมพ์อะไรเลยหากx
ไม่ได้ถูกส่งออก
x=out; (x=in; echo $x)
)