ดูเหมือนว่า Bash เป็นภาษาทัวริงที่สมบูรณ์
แนวคิดของทัวริงสมบูรณ์แยกจากแนวคิดอื่น ๆ อีกมากมายที่มีประโยชน์ในภาษาสำหรับการเขียนโปรแกรมในขนาดใหญ่ : การใช้งานการแสดงออกความเข้าใจความเร็ว ฯลฯ
ถ้าทัวริง-ครบถ้วนทุกคนเราจำเป็นที่เราจะไม่ได้มีการเขียนโปรแกรมภาษาใด ๆที่ทุกคนไม่ได้ภาษาประกอบ โปรแกรมเมอร์คอมพิวเตอร์ทุกคนจะเขียนรหัสเครื่องจักรเนื่องจากซีพียูของเรายังเป็นทัวริงที่สมบูรณ์
เหตุใด Bash จึงใช้สคริปต์ที่เรียบง่ายเป็นพิเศษในการเขียน
สคริปต์เชลล์ขนาดใหญ่และซับซ้อน - เช่นconfigure
สคริปต์เอาต์พุตโดย GNU Autoconf - ผิดปกติด้วยเหตุผลหลายประการ:
จนกระทั่งเร็ว ๆ นี้ค่อนข้างที่คุณไม่สามารถนับบนมีเปลือก POSIX ได้ทุกที่
ระบบจำนวนมากโดยเฉพาะอย่างยิ่งระบบที่เก่ากว่านั้นมีเปลือกที่ทำงานร่วมกันได้ POSIX ในบางแห่งในระบบ แต่มันอาจไม่ได้อยู่ในตำแหน่งที่สามารถคาดเดา/bin/sh
ได้ หากคุณเขียนเชลล์สคริปและมันจะต้องทำงานในหลาย ๆ ระบบคุณจะเขียนบรรทัด shebang ได้อย่างไร? ทางเลือกหนึ่งคือการไปข้างหน้าและใช้งาน/bin/sh
แต่เลือกที่จะ จำกัด ตัวเองของภาษา Bourne เชลล์ล่วงหน้า POSIX ในกรณีที่มันถูกเรียกใช้บนระบบดังกล่าว
Pre-POSIX Bourne shells ไม่มีแม้แต่เลขคณิตในตัว คุณต้องโทรออกexpr
หรือbc
ทำสิ่งนั้นให้สำเร็จ
ถึงแม้จะมีเปลือก POSIX คุณจะหายไปหมดในarrays สมาคมและคุณสมบัติอื่น ๆ ที่เราเคยคาดว่าจะพบในระบบปฏิบัติการยูนิกซ์ภาษาสคริปต์ตั้งแต่ Perl แรกที่กลายเป็นที่นิยมในช่วงปี 1990
ความเป็นจริงในประวัติศาสตร์นั้นหมายความว่ามีประเพณีมายาวนานหลายทศวรรษในการเพิกเฉยคุณลักษณะที่ทรงพลังจำนวนมากในล่ามสคริปต์ตระกูล Bourne ตระกูลสมัยใหม่อย่างหมดจดเพราะคุณไม่สามารถไว้ใจได้ทุกที่
นี้ยังคงดำเนินต่อไปในวันนี้ในความเป็นจริง: ทุบตีไม่ได้รับการเชื่อมโยงอาร์เรย์จนถึง 4 รุ่นแต่คุณอาจจะแปลกใจว่าหลายระบบยังคงอยู่ในการใช้งานจะขึ้นอยู่กับทุบตี 3. แอปเปิ้ลยังคงเรือ Bash 3 กับ MacOS ในปี 2017 - เห็นได้ชัดว่า เหตุผลการออกใบอนุญาต - และเซิร์ฟเวอร์ Unix / Linux มักจะทำงานทั้งหมด แต่ไม่ได้ถูกแตะต้องในการผลิตเป็นเวลานานดังนั้นคุณอาจมีระบบเก่าที่เสถียรซึ่งยังคงใช้งาน Bash 3 เช่นกล่อง CentOS 5 หากคุณมีระบบดังกล่าวในสภาพแวดล้อมของคุณคุณไม่สามารถใช้อาเรย์แบบเชื่อมโยงในเชลล์สคริปต์ที่ต้องทำงานกับมัน
หากคำตอบของคุณสำหรับปัญหานั้นคือคุณเขียนเชลล์สคริปต์สำหรับระบบ "ทันสมัย" เท่านั้นคุณต้องรับมือกับข้อเท็จจริงที่ว่าจุดอ้างอิงทั่วไปสุดท้ายสำหรับเชลล์ Unix ส่วนใหญ่คือPOSIX เชลล์มาตรฐานซึ่งส่วนใหญ่ไม่เปลี่ยนแปลงเนื่องจากเป็น เปิดตัวในปี 1989 มีกระสุนจำนวนมากที่แตกต่างกันไปตามมาตรฐานนั้น แต่พวกมันต่างกันที่องศาที่แตกต่างจากมาตรฐานนั้น เพื่อที่จะใช้เชื่อมโยงอาร์เรย์อีกครั้งbash
, zsh
และksh93
ทุกคนมีคุณลักษณะที่ แต่มีการดำเนินการกันไม่ได้หลาย ๆ ทางเลือกของคุณแล้วคือการเพียงใช้ทุบตีหรือเพียงใช้ zsh หรือเพียงksh93
ใช้
หากคำตอบของคุณสำหรับปัญหานั้นคือ "ดังนั้นเพียงแค่ติดตั้ง Bash 4" ksh93
หรืออะไรก็ตามทำไมไม่ "เพียงแค่" ติดตั้ง Perl หรือ Python หรือ Ruby แทน? ที่ยอมรับไม่ได้ในหลายกรณี ค่าเริ่มต้นเป็นเรื่อง
ไม่มีของบอร์นเปลือกครอบครัวสนับสนุนภาษาสคริปต์โมดูล
ที่ใกล้เคียงที่สุดที่คุณสามารถมากับระบบโมดูลในสคริปต์เปลือกเป็น.
คำสั่ง - อาคาsource
ในบอร์นที่ทันสมัยมากขึ้นเปลือกสายพันธุ์ - ซึ่งล้มเหลวในหลายระดับเมื่อเทียบกับระบบโมดูลที่เหมาะสมที่สุดพื้นฐานของซึ่งเป็นnamespacing
ความเข้าใจของมนุษย์เริ่มตั้งค่าสถานะเมื่อไฟล์เดียวในโปรแกรมโดยรวมที่ใหญ่กว่าเกินสองสามบรรทัด เหตุผลที่เราจัดโครงสร้างโปรแกรมขนาดใหญ่เป็นไฟล์จำนวนมากคือเพื่อให้เราสามารถสรุปเนื้อหาของพวกเขาให้เป็นประโยคหนึ่งหรือสองประโยคได้มากที่สุด ไฟล์ A คือตัวแยกวิเคราะห์บรรทัดคำสั่งไฟล์ B คือปั๊ม I / O เครือข่ายไฟล์ C คือ shim ระหว่างไลบรารี่ Z และส่วนที่เหลือของโปรแกรม ฯลฯ เมื่อวิธีการเดียวของคุณสำหรับการประกอบไฟล์จำนวนมากเข้าในโปรแกรมเดียวคือการรวมข้อความ คุณ จำกัด จำนวนโปรแกรมของคุณที่จะเติบโตอย่างมีเหตุผล
สำหรับการเปรียบเทียบมันจะเหมือนกับว่าภาษาการเขียนโปรแกรม Cไม่มีตัวเชื่อมโยง#include
คำสั่งเท่านั้น เช่นภาษา C-Lite จะไม่จำเป็นต้องคำหลักเช่นหรือextern
static
คุณสมบัติเหล่านั้นมีอยู่เพื่อให้เป็นโมดูล
POSIX ไม่ได้กำหนดวิธีในการกำหนดขอบเขตตัวแปรให้กับฟังก์ชั่นเชลล์สคริปต์เพียงไฟล์เดียว
ได้อย่างมีประสิทธิภาพทำให้ตัวแปรทั้งหมดทั่วโลกอีกครั้งซึ่งเจ็บต้นแบบและ composability
มีโซลูชั่นนี้ในเปลือกหอยโพสต์ POSIX - แน่นอนbash
, ksh93
และzsh
แต่ที่เพิ่งจะนำคุณกลับไปยังจุดที่ 1 ข้างต้น - อย่างน้อย
คุณสามารถเห็นผลกระทบของสิ่งนี้ได้ในไกด์นำเที่ยวเกี่ยวกับการเขียนแมโคร GNU Autoconf โดยที่พวกเขาแนะนำให้คุณใส่ชื่อตัวแปรด้วยชื่อของแมโครเองนำไปสู่ชื่อตัวแปรที่ยาวมาก ๆ เพื่อลดโอกาสของการชนจนใกล้ ศูนย์.
แม้แต่ C ก็ยังดีกว่าในคะแนนนี้เป็นไมล์ ไม่เพียง แต่โปรแกรม C ส่วนใหญ่ที่เขียนด้วยตัวแปร function-local เป็นหลักเท่านั้น C ยังรองรับการกำหนดขอบเขตของบล็อกซึ่งอนุญาตให้บล็อกจำนวนมากภายในฟังก์ชันเดียวสามารถนำชื่อตัวแปรมาใช้ใหม่ได้โดยไม่ต้องมีการปนเปื้อนข้าม
ภาษาการเขียนโปรแกรมเชลล์ไม่มีไลบรารีมาตรฐาน
มีความเป็นไปได้ที่จะโต้แย้งว่าไลบรารีมาตรฐานของภาษาสคริปต์เชลล์คือเนื้อหาของPATH
แต่ที่เพิ่งกล่าวว่าเพื่อให้ได้ผลลัพธ์ที่ตามมาเชลล์สคริปต์ต้องเรียกใช้โปรแกรมอื่นทั้งหมดอาจเป็นภาษาที่มีประสิทธิภาพมากกว่าเริ่มด้วย.
ทั้งจะมีการเก็บใช้กันอย่างแพร่หลายของห้องสมุดยูทิลิตี้เปลือกเช่นเดียวกับของ Perl CPAN หากไม่มีไลบรารีขนาดใหญ่ที่มีรหัสยูทิลิตี้ของบุคคลที่สามโปรแกรมเมอร์จะต้องเขียนโค้ดเพิ่มเติมด้วยตนเองดังนั้นเธอจึงทำงานได้น้อยลง
แม้จะไม่สนใจความเป็นจริงที่ว่าส่วนใหญ่เชลล์สคริปต์พึ่งพาโปรแกรมภายนอกมักจะเขียนใน C จะได้รับอะไรที่เป็นประโยชน์ทำมีค่าใช้จ่ายของเหล่านั้นทั้งหมดpipe()
→การfork()
→การexec()
โซ่โทร รูปแบบนั้นค่อนข้างมีประสิทธิภาพใน Unix เมื่อเทียบกับIPCและกระบวนการเปิดตัวในระบบปฏิบัติการอื่น ๆ แต่ที่นี่มันมีประสิทธิภาพแทนที่สิ่งที่คุณทำกับการเรียกรูทีนย่อยในภาษาสคริปต์อื่นซึ่งยังคงมีประสิทธิภาพมากกว่า สิ่งนี้ทำให้ขีด จำกัด สูงสุดของขีด จำกัด สูงสุดของความเร็วการประมวลผลสคริปต์เชลล์
เชลล์สคริปต์มีความสามารถในตัวเล็กน้อยในการเพิ่มประสิทธิภาพผ่านการทำงานแบบขนาน
เปลือกหอยบอร์นได้&
, wait
และท่อนี้ แต่ที่ส่วนใหญ่เท่านั้นที่มีประโยชน์สำหรับการเขียนโปรแกรมหลายโปรแกรมไม่ได้สำหรับการบรรลุ CPU หรือ I / O ขนาน คุณไม่น่าจะตรึงแกนหลักหรือทำให้อาร์เรย์ RAID อิ่มตัวด้วยการทำเชลล์สคริปต์ แต่เพียงอย่างเดียวและถ้าคุณทำเช่นนั้นคุณอาจจะได้รับประสิทธิภาพที่สูงขึ้นในภาษาอื่น ๆ
ท่อโดยเฉพาะอย่างยิ่งเป็นวิธีที่อ่อนแอในการเพิ่มประสิทธิภาพผ่านการดำเนินการแบบขนาน มันอนุญาตให้โปรแกรมสองโปรแกรมทำงานแบบขนานและหนึ่งในสองโปรแกรมนั้นอาจถูกบล็อคบน I / O ไปยังหรือจากอีกโปรแกรมหนึ่งตามเวลาที่กำหนด
มีวิธีหลังวันนี้เช่นxargs -P
และGNUparallel
แต่เพียง devolves ไปยังจุด 4 ข้างต้น
ด้วยประสิทธิภาพที่ไม่สามารถใช้ประโยชน์จากระบบมัลติโปรเซสเซอร์ได้อย่างมีประสิทธิภาพเชลล์สคริปต์จะช้ากว่าโปรแกรมที่เขียนดีในภาษาที่สามารถใช้โปรเซสเซอร์ทั้งหมดในระบบได้เสมอ ในการรับconfigure
ตัวอย่างสคริปต์GNU Autoconf อีกครั้งการเพิ่มจำนวนแกนประมวลผลในระบบจะเพิ่มความเร็วในการทำงานเล็กน้อย
เชลล์ภาษาสคริปต์ไม่ได้มีคำแนะนำหรือการอ้างอิง
สิ่งนี้ทำให้คุณไม่สามารถทำสิ่งต่าง ๆ ได้อย่างง่ายดายในภาษาโปรแกรมอื่น
สำหรับสิ่งหนึ่งที่ไม่สามารถอ้างอิงทางอ้อมไปยังโครงสร้างข้อมูลอื่นในหน่วยความจำของโปรแกรมหมายความว่าคุณ จำกัดโครงสร้างข้อมูลในตัว เชลล์ของคุณอาจมีอาเรย์แบบเชื่อมโยงแต่จะใช้งานอย่างไร มีความเป็นไปได้หลายอย่างแต่ละอย่างมีการแลกเปลี่ยนแตกต่างกัน: ต้นไม้สีแดงดำ , ต้นไม้ AVLและตารางแฮชเป็นเรื่องที่พบได้บ่อยที่สุด แต่มีคนอื่น ๆ หากคุณต้องการชุดแลกเปลี่ยนที่แตกต่างกันคุณติดอยู่เพราะไม่มีการอ้างอิงคุณไม่มีวิธีม้วนโครงสร้างข้อมูลขั้นสูงหลายประเภท คุณติดอยู่กับสิ่งที่คุณได้รับ
หรือมันอาจจะเป็นกรณีที่คุณต้องการโครงสร้างข้อมูลที่ไม่ได้มีทางเลือกที่เพียงพอที่สร้างขึ้นในล่ามสคริปต์เปลือกของคุณเช่นการชี้นำวัฏจักรกราฟซึ่งคุณอาจต้องการเพื่อที่จะจำลองขึ้นกราฟ ฉันได้เขียนโปรแกรมมานานหลายทศวรรษและวิธีเดียวที่ฉันสามารถทำได้ในเชลล์สคริปต์คือการละเมิดระบบไฟล์โดยใช้ symlinks เป็นการอ้างอิงแบบ faux นั่นเป็นวิธีการแก้ปัญหาที่คุณได้รับเมื่อคุณพึ่งพาทัวริง - สมบูรณ์ซึ่งจะบอกอะไรคุณเกี่ยวกับว่าวิธีการแก้ปัญหาเป็นสง่ารวดเร็วหรือเข้าใจง่าย
โครงสร้างข้อมูลขั้นสูงใช้เพียงหนึ่งเดียวสำหรับตัวชี้และการอ้างอิง มีแอปพลิเคชั่นอื่น ๆ อีกมากมายสำหรับพวกเขาซึ่งไม่สามารถทำได้อย่างง่ายดายในภาษาสคริปต์ตระกูล Bourne
ฉันสามารถไปต่อไปได้ แต่ฉันคิดว่าคุณได้รับจุดที่นี่ พูดง่าย ๆ ก็คือมีภาษาการเขียนโปรแกรมที่ทรงพลังกว่าสำหรับระบบ Unix
นี่เป็นข้อได้เปรียบที่ยิ่งใหญ่ที่สามารถชดเชยความธรรมดาของภาษาในบางกรณี
แน่นอนและนั่นคือเหตุผลที่ GNU Autoconf ใช้ชุดย่อยของตระกูลเชลล์สคริปต์ภาษาบอร์นสำหรับconfigure
สคริปต์ออก: เพื่อให้configure
สคริปต์ทำงานได้ทุกที่
คุณอาจจะไม่พบกลุ่มผู้เชื่อขนาดใหญ่ในยูทิลิตี้การเขียนในภาษา Bourne shell แบบพกพาสูงกว่านักพัฒนาของ GNU Autoconf แต่การสร้างของพวกเขาเองถูกเขียนขึ้นในภาษา Perl เป็นหลักรวมถึงบางส่วนm4
เท่านั้น สคริปต์; เอาต์พุตของ Autoconf เท่านั้นคือเชลล์สคริปต์ Bourne แท้ หากนั่นไม่ได้ถามคำถามว่าแนวคิด "Bournewhere" มีประโยชน์เพียงใดฉันก็ไม่รู้ว่าจะทำอะไร
ดังนั้นจึงมีข้อ จำกัด ว่าโปรแกรมดังกล่าวจะซับซ้อนแค่ไหน?
เทคนิคการพูดไม่ใช่ตามที่การสังเกตของทัวริงครบถ้วน
แต่นั่นไม่ใช่สิ่งเดียวกับที่บอกว่าเชลล์สคริปต์ที่มีขนาดใหญ่โดยพลการนั้นมีความสุขในการเขียนง่ายต่อการดีบักหรือดำเนินการอย่างรวดเร็ว
เป็นไปได้ที่จะเขียน, พูด, ไฟล์คอมเพรสเซอร์ / decompressor ในทุบตีบริสุทธิ์?
ทุบตี "บริสุทธิ์" โดยไม่ต้องโทรออกไปหาสิ่งต่าง ๆ ในPATH
? คอมเพรสเซอร์น่าจะเป็นไปได้โดยใช้echo
และลำดับหลบหนี hex แต่มันจะค่อนข้างเจ็บปวดที่จะทำ ตัวขยายการบีบอัดอาจเป็นไปไม่ได้ที่จะเขียนด้วยวิธีนี้เนื่องจากไม่สามารถจัดการข้อมูลไบนารีในเชลล์ได้ คุณจะต้องโทรออกod
และเช่นในการแปลข้อมูลไบนารีเป็นรูปแบบข้อความวิธีการจัดการข้อมูลของเชลล์
เมื่อคุณเริ่มพูดคุยเกี่ยวกับการใช้เชลล์สคริปท์ตามที่ตั้งใจไว้เพราะกาวในการผลักดันโปรแกรมอื่น ๆ ในPATH
ประตูเปิดขึ้นเพราะตอนนี้คุณ จำกัด เฉพาะสิ่งที่สามารถทำได้ในภาษาการเขียนโปรแกรมอื่น ๆ ซึ่งก็คือคุณ ไม่มีขีด จำกัด เลย เชลล์สคริปต์ที่ได้รับทั้งหมดของอำนาจของตนโดยการโทรออกไปยังโปรแกรมอื่น ๆ ในPATH
ไม่ทำงานให้เร็วที่สุดเท่าโปรแกรมเสาหินที่เขียนในภาษาที่มีประสิทธิภาพมากขึ้น แต่มันไม่วิ่ง
และนั่นคือประเด็น หากคุณต้องการให้โปรแกรมทำงานเร็วหรือหากจำเป็นต้องมีประสิทธิภาพในตัวของมันเองแทนที่จะต้องยืมพลังจากโปรแกรมอื่นคุณก็ไม่ต้องเขียนมันลงไปในเชลล์
วิดีโอเกมง่ายๆ?
นี่คือTetris ในเปลือก เกมดังกล่าวมีให้บริการหากคุณไปดู
มีเครื่องมือการดีบักที่ จำกัด เท่านั้น
ฉันจะวางเครื่องมือสนับสนุนการดีบักลงประมาณ 20 ที่ในรายการคุณสมบัติที่จำเป็นในการสนับสนุนการเขียนโปรแกรมในขนาดใหญ่ โปรแกรมเมอร์จำนวนมากต้องพึ่งพาการprintf()
ดีบักมากกว่า debuggers ที่เหมาะสมโดยไม่คำนึงถึงภาษา
ในเปลือกคุณมีecho
และset -x
ซึ่งรวมกันเพียงพอที่จะแก้ปัญหาที่ดีมาก
sh
สคริปต์configure
ซึ่งจะใช้เป็นส่วนหนึ่งของการสร้างกระบวนการสำหรับการที่ดีมากยกเลิก * x แพคเกจไม่เป็น 'ค่อนข้างง่าย'