$ () subshell หรือไม่


51

ฉันเข้าใจไวยากรณ์ของ subshell (<commands...>)เป็น$()เพียง subshell ที่คุณสามารถดึงค่าตัวแปรได้หรือไม่

หมายเหตุ: สิ่งนี้ใช้กับทุบตี 4.4 ตามถ้อยคำต่าง ๆ ในเอกสารประกอบ


4
ซ้ำกันเป็นไปได้ของการทดแทนคำสั่งในเปลือกคืออะไร?
Julien Lopez

คำตอบ:


75

$(…)เป็น subshell ตามคำนิยาม: เป็นสำเนาของ shell runtime state shell, และการเปลี่ยนแปลงสถานะที่ทำใน subshell ไม่มีผลกระทบกับ parent โดยทั่วไปแล้ว subshell จะถูกนำไปใช้โดยการฟอร์กกระบวนการใหม่ (แต่เชลล์บางตัวอาจปรับให้เหมาะสมในบางกรณี)

ไม่ใช่ subshell ที่คุณสามารถดึงค่าตัวแปรได้ หากการเปลี่ยนแปลงตัวแปรมีผลกระทบกับพาเรนต์มันจะไม่ใช่ subshell มันเป็น subshell ที่เอาท์พุทพาเรนต์สามารถดึงได้ เชลล์ย่อยที่สร้างโดย$(…)มีเอาต์พุตมาตรฐานถูกตั้งค่าเป็นไพพ์และพาเรนต์อ่านจากไพพ์นั้นและรวบรวมเอาต์พุต

มีโครงสร้างอื่น ๆ อีกมากมายที่สร้างเชลล์ย่อย ฉันคิดว่านี่เป็นรายการที่สมบูรณ์สำหรับทุบตี:

  • subshell สำหรับการจัดกลุ่ม : ( … )ไม่ทำอะไรเลยนอกจากสร้าง subshell และรอให้มันยุติ) ความคมชัด{ … }ที่กลุ่มคำสั่งอย่างหมดจดเพื่อวัตถุประสงค์ในการสร้างประโยคและไม่สร้างเชลล์ย่อย
  • พื้นหลัง : … &สร้าง subshell และไม่รอให้มันจบ
  • ไปป์ไลน์ : … | …สร้างสอง subshells หนึ่งสำหรับด้านซ้ายมือและอีกหนึ่งสำหรับด้านขวามือและรอให้ทั้งสองจะยุติ เชลล์สร้างไพพ์และเชื่อมต่อเอาต์พุตมาตรฐานของด้านซ้ายมือกับปลายเขียนของไพพ์และอินพุตมาตรฐานของด้านขวาไปยังปลายอ่าน ในเชลล์บางตัว (ksh88, ksh93, zsh, bash พร้อมชุดlastpipeตัวเลือกและมีผลบังคับใช้) ทางด้านขวามือจะทำงานในเชลล์เดิมดังนั้นการสร้างไปป์ไลน์จะสร้างเชลล์ย่อยเดียวเท่านั้น
  • การทดแทนคำสั่ง : $(…)(สะกดเช่นกัน`…`) สร้างเชลล์ย่อยพร้อมชุดเอาต์พุตมาตรฐานไปยังไพพ์รวบรวมเอาต์พุตในพาเรนต์และขยายไปยังเอาต์พุตนั้นลบบรรทัดใหม่ที่ต่อท้าย (และผลลัพธ์อาจขึ้นอยู่กับการแยกและการโค้งงอ แต่เป็นอีกเรื่อง)
  • การทดแทนโปรเซส : <(…)สร้างเชลล์ย่อยพร้อมชุดเอาต์พุตมาตรฐานไปยังไพพ์และขยายเป็นชื่อของไพพ์ ผู้ปกครอง (หรือกระบวนการอื่น ๆ ) อาจเปิดไปป์เพื่อสื่อสารกับ subshell >(…)ทำสิ่งเดียวกัน แต่กับไพพ์บนอินพุตมาตรฐาน
  • Coprocess : coproc …สร้าง subshell และไม่รอให้มันยุติ อินพุตและเอาต์พุตมาตรฐานของ subshell แต่ละชุดถูกตั้งค่าเป็นไพพ์โดยที่พาเรนต์เชื่อมต่อกับปลายอีกด้านของแต่ละไพพ์

¹ เมื่อเทียบกับการทำงานเปลือกแยกต่างหาก


คุณสามารถรวม${...}ไว้ในคำตอบได้หรือไม่?
user1717828

3
@ user1717828 อะไร ทำไม? การขยายตัวของตัวแปรจากระยะไกลเกี่ยวข้องกับคำถามนี้อย่างไร ฉันจะไม่รวมคู่มือเชลล์ทั้งหมดไว้ในคำตอบของฉัน
Gilles 'หยุดความชั่วร้าย' Gilles

1
การขยายตัวของตัวแปรจากระยะไกลเกี่ยวข้องกับคำถามนี้อย่างไร ฉันไม่รู้ว่านั่นคือเหตุผลที่ฉันถาม :-) ดังนั้นฉันเดาว่าการแทนที่วงเล็บปีกกาแบบไม่มีอะไรเหมือนกับการแทนที่วงเล็บปีกกา
user1717828

@ user1717828: การขยายตัวแปรไม่เกี่ยวข้องกับ subshells; มันเป็นกลไกที่แยกจากกันโดยสิ้นเชิงและคุ้มค่าที่จะอ่านหากคุณเพิ่งเริ่มใช้
0xdd

1
@EnricoMariaDeAngelis ไม่ใช่วิธีเดียว แต่เป็นวิธีที่เป็นธรรมชาติที่สุด อีกวิธีหนึ่งคือcommand | { read line; … }(ขึ้นอยู่กับเปลือกlineอาจหรือไม่อาจยังคงมีอยู่หลังจากท่อ) วิธีทั้งหมดเกี่ยวข้องกับเชลล์ย่อยเนื่องจากคำสั่งที่สร้างเอาต์พุตต้องรันโดยอิสระจากเชลล์ที่อ่านอินพุต หากคำสั่งนั้นอยู่ภายในเชลล์อย่างหมดจด (เฉพาะเชลล์สร้างและบิวด์อินไม่มีคำสั่งภายนอก) เชลล์อาจไม่สร้างกระบวนการย่อย แต่นั่นเป็นเพียงการเพิ่มประสิทธิภาพ แต่ยังคงสร้างเชลล์ย่อย
Gilles 'หยุดความชั่วร้าย'

20

จากหน้า man (1) bash ใน bash เวอร์ชัน 4.4, ส่วน "EXPANSION", ส่วนย่อย "การแทนที่คำสั่ง":

Bash ทำการขยายตัวโดยดำเนินการcommandในสภาพแวดล้อม subshell [... ]



1
ที่น่าสนใจภายใต้ CentOS 7 bashmanpage ไม่ได้พูดถึง subshell ใด ๆ : Bash performs the expansion by executing command and replacing the command substitution with the standard output of the command, with any trailing newlines deleted.ฉันสงสัยว่านี่เป็นการละเลยโดยเจตนา
dr01

6
@ dr01 ตรงกันข้าม bash 4.4 เปลี่ยนถ้อยคำของประโยคนั้นเพื่อรวมคำว่า“ subshell” มันเป็นคำชี้แจง: คู่มือกล่าวอย่างชัดเจนว่าการสร้างอื่น ๆ เป็น subshells แต่จนถึง 4.4 มันไม่ได้ระบุไว้อย่างชัดเจนสำหรับการทดแทนคำสั่ง
Gilles 'หยุดความชั่วร้าย'

ใช่บน CentOS v7.4.1708 (ค่อนข้างเร็ว) ทุบตีคือ v4.2.46
dr01

5

ใช่( commands... )เป็นbashsubshell ที่จะดำเนินการcommands...ในกระบวนการอื่น

ความแตกต่างเฉพาะเมื่อคุณมี$( commands... )ก็คือส่วนหนึ่งของรหัสนี้จะหลังจากการดำเนินการของcommands...ถูกแทนที่ด้วยทุกอย่างที่เขียนถึงcommands...stdout

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