ในคำศัพท์ POSIX สภาพแวดล้อม subshell มีการเชื่อมโยงกับความคิดของเชลล์ประมวลสภาพแวดล้อม
สภาพแวดล้อม subshell เป็นสภาพแวดล้อมการทำงานของเชลล์แยกต่างหากที่สร้างขึ้นซ้ำซ้อนกับสภาพแวดล้อมพาเรนต์ สภาพแวดล้อมการดำเนินการนั้นรวมถึงสิ่งต่าง ๆ เช่นไฟล์ที่เปิด, umask, ไดเร็กทอรีการทำงาน, ตัวแปรเชลล์ / ฟังก์ชัน / นามแฝง
การเปลี่ยนแปลงสภาพแวดล้อม subshell นั้นไม่ส่งผลกระทบต่อสภาพแวดล้อมหลัก
ตามเนื้อผ้าใน Bourne เชลล์หรือ ksh88 ซึ่งเป็นไปตามข้อกำหนด POSIX ซึ่งทำโดยการฟอร์กกระบวนการลูก
พื้นที่ที่ POSIX ต้องการหรืออนุญาตให้คำสั่งรันในสภาพแวดล้อม subshell เป็นพื้นที่ที่ ksh88 ตามปกติจะแยกกระบวนการ child shell
อย่างไรก็ตามมันไม่ได้บังคับให้การใช้งานเพื่อใช้กระบวนการลูกสำหรับสิ่งนั้น
เชลล์สามารถเลือกที่จะใช้สภาพแวดล้อมการดำเนินการแยกต่างหากแทนได้ตามที่พวกเขาต้องการ
ยกตัวอย่างเช่น ksh93 ทำได้โดยบันทึกคุณลักษณะของสภาพแวดล้อมการประมวลผลหลักและเรียกคืนเมื่อสิ้นสุดสภาพแวดล้อม subshell ในบริบทที่สามารถหลีกเลี่ยงการฟอร์กได้
ตัวอย่างเช่นใน:
cd /foo; pwd
(cd /bar; pwd)
pwd
POSIX จำเป็นต้องใช้cd /foo
เพื่อทำงานในสภาพแวดล้อมที่แยกต่างหากและสิ่งที่ต้องการออก:
/foo
/bar
/foo
มันไม่ต้องการให้มันทำงานในกระบวนการที่แยกต่างหาก ตัวอย่างเช่นหาก stdout กลายเป็นไพพ์ที่ขาดการpwd
รันในสภาพแวดล้อม subshell อาจส่ง SIGPIPE ไปยังกระบวนการเชลล์เพียงหนึ่งกระบวนการเท่านั้น
เชลล์ส่วนใหญ่รวมถึงbash
จะใช้มันโดยการประเมินโค้ดที่อยู่(...)
ในกระบวนการลูก (ในขณะที่กระบวนการหลักรอการยกเลิก) แต่ ksh93 จะทำงานแทนเมื่อเรียกใช้โค้ดภายใน(...)
ทั้งหมดในกระบวนการเดียวกัน:
- จำไว้ว่ามันอยู่ในสภาพแวดล้อม subshell
- ให้
cd
บันทึกไดเร็กตอรี่ทำงานก่อนหน้านี้ (โดยทั่วไปคือ file descriptor ที่เปิดด้วย O_CLOEXEC), บันทึกค่าของตัวแปร OLDPWD, PWD และสิ่งที่cd
อาจแก้ไขและทำchdir("/bar")
- เมื่อกลับมาจาก subshell ไดเร็กทอรีการทำงานปัจจุบันจะถูกกู้คืน (พร้อมกับ
fchdir()
fd ที่บันทึกไว้) และทุกอย่างอื่นที่ subshell อาจมีการแก้ไข
มีบริบทที่ไม่สามารถหลีกเลี่ยงกระบวนการลูกได้ ksh93 ไม่แยก:
var=$(subshell)
(subshell)
แต่ทำค่ะ
{ subshell; } &
{ subshell; } | other command
นั่นคือกรณีที่สิ่งต่าง ๆ ต้องทำงานในกระบวนการแยกต่างหากเพื่อให้สามารถทำงานพร้อมกันได้
การเพิ่มประสิทธิภาพ ksh93 ไปไกลกว่านั้น ตัวอย่างเช่นในขณะที่
var=$(pwd)
เปลือกหอยส่วนใหญ่จะแยกกระบวนการที่มีเด็กเรียกใช้pwd
คำสั่งกับ stdout มันเปลี่ยนเส้นทางไปยังท่อpwd
เขียนไดเรกทอรีการทำงานปัจจุบันไปยังท่อนั้นและการปกครองอ่านผลที่ปลายอีกด้านของท่อksh93
เสมือนจริงทั้งหมดว่าด้วยค่า ต้องใช้ส้อมหรือท่อ ส้อมและไพพ์จะใช้สำหรับคำสั่งที่ไม่ได้สร้างขึ้นเท่านั้น
โปรดทราบว่ามีบริบทอื่น ๆ ที่ subshells ที่เปลือกแยกกระบวนการเด็ก ตัวอย่างเช่นในการเรียกใช้คำสั่งที่เก็บไว้ในไฟล์สั่งการแยกต่างหาก (และไม่ใช่สคริปต์ที่มีไว้สำหรับตัวแปลเชลล์เดียวกัน) เชลล์จะต้องแยกกระบวนการเพื่อประมวลผลคำสั่งนั้นมิฉะนั้นจะไม่เป็นเช่นนั้น สามารถเรียกใช้คำสั่งเพิ่มเติมหลังจากที่คำสั่งนั้นกลับมา
ใน:
/bin/echo "$((n += 1))"
นั่นไม่ใช่ subshell คำสั่งจะถูกประเมินในสภาพแวดล้อมการประมวลผลเชลล์ปัจจุบันn
ตัวแปรของสภาพแวดล้อมการดำเนินการเชลล์ปัจจุบันจะเพิ่มขึ้น แต่เชลล์จะแยกกระบวนการลูกเพื่อประมวลผล/bin/echo
คำสั่งนั้นด้วยการขยาย$((n += 1))
เป็นอาร์กิวเมนต์ .
เชลล์จำนวนมากใช้การปรับให้เหมาะสมโดยที่พวกเขาจะไม่แยกกระบวนการย่อยเพื่อรันคำสั่งภายนอกนั้นหากเป็นคำสั่งสุดท้ายของสคริปต์หรือ subshell (สำหรับเชลล์ย่อยที่ถูกใช้เป็นกระบวนการย่อย) ( bash
อย่างไรก็ตามจะทำได้ก็ต่อเมื่อคำสั่งนั้นเป็นคำสั่งเดียวของ subshell)
สิ่งที่หมายถึงคือถ้าใช้เชลล์เหล่านั้นหากคำสั่งสุดท้ายใน subshell เป็นคำสั่งภายนอก subshell จะไม่ทำให้กระบวนการพิเศษเกิดขึ้นอีก ถ้าคุณเปรียบเทียบ:
a=1; /bin/echo "$a"; a=2; /bin/echo "$a"
กับ
a=1; /bin/echo "$a"; (a=2; /bin/echo "$a")
จะมีจำนวนกระบวนการเท่ากันที่สร้างขึ้นเฉพาะในกรณีที่สองเท่านั้นที่จะทำการแยกที่สองก่อนหน้านี้เพื่อให้a=2
มีการเรียกใช้ในสภาพแวดล้อม subshell