เหตุใดจึงlsต้องมีกระบวนการแยกต่างหากสำหรับการดำเนินการ ฉันรู้ว่าสาเหตุที่คำสั่งเช่นcdไม่สามารถดำเนินการได้โดยกลไกการฟอร์กกิ้ง แต่มีอันตรายใด ๆ หากlsถูกสั่งการโดยไม่ฟอร์กกิ้ง?
เหตุใดจึงlsต้องมีกระบวนการแยกต่างหากสำหรับการดำเนินการ ฉันรู้ว่าสาเหตุที่คำสั่งเช่นcdไม่สามารถดำเนินการได้โดยกลไกการฟอร์กกิ้ง แต่มีอันตรายใด ๆ หากlsถูกสั่งการโดยไม่ฟอร์กกิ้ง?
คำตอบ:
คำตอบนั้นมากขึ้นหรือน้อยลงที่lsสามารถเรียกใช้งานได้จากภายนอก type -p lsคุณสามารถดูสถานที่ของตนโดยการเรียกใช้
ทำไมไม่lsสร้างไว้ในเชลล์ล่ะ? ทำไมมันถึงเป็นอย่างนั้น? งานของเชลล์ไม่ได้รวมทุกคำสั่งที่มีอยู่ แต่เพื่อจัดเตรียมสภาพแวดล้อมที่สามารถเรียกใช้งานได้ กระสุนสมัยใหม่บางรุ่นมีecho, printfและ, ตระกูลของพวกเขาเป็น builtins, ซึ่งโดยทางเทคนิคไม่จำเป็นต้องเป็น buildins, แต่ถูกสร้างขึ้นมาเพื่อเหตุผลด้านประสิทธิภาพเมื่อพวกมันถูกเรียกใช้ซ้ำ ๆ เชลล์จะต้องแยกและดำเนินกระบวนการใหม่สำหรับการเรียกแต่ละครั้งซึ่งอาจช้ามาก
อย่างน้อยที่สุดการรันไฟล์เรียกทำงานlsภายนอกต้องรันหนึ่งในตระกูล exec ของการเรียกระบบ คุณสามารถทำได้โดยไม่ต้องฟอร์ก แต่จะแทนที่เชลล์หลักที่คุณใช้อยู่ คุณสามารถดูว่าเกิดอะไรขึ้นในอินสแตนซ์นั้นโดยทำสิ่งต่อไปนี้:
exec ls; echo "this never gets printed"
เนื่องจากอิมเมจกระบวนการเชลล์ของคุณถูกแทนที่เชลล์ปัจจุบันจะไม่สามารถเข้าถึงได้หลังจากทำสิ่งนี้แล้ว เพื่อให้เชลล์สามารถรันต่อไปหลังจากรัน ls คำสั่งจะต้องสร้างขึ้นในเชลล์
Forking อนุญาตให้เปลี่ยนกระบวนการที่ไม่ใช่เชลล์หลักของคุณซึ่งหมายความว่าคุณสามารถรันเชลล์ต่อได้ในภายหลัง
echo, printfฯลฯ
cdไม่สามารถเรียกใช้งานภายนอกได้
cdที่ปฏิบัติการในระบบปฏิบัติการที่สอดคล้องกับ POSIX ( ดูที่นี่ ) หากคุณต้องการ chdir () จริง ๆ ในกระบวนการปัจจุบันคุณต้องสร้างมันไว้ในเชลล์
คำสั่งในตัวมีความจำเป็นต่อการใช้งานฟังก์ชั่นที่เป็นไปไม่ได้หรือไม่สะดวกในการขอรับด้วยยูทิลิตี้แยก
นั่นคือเปลือกหอยถูกออกแบบมาเพื่อเท่านั้นรวมคำสั่งในตัวเท่านั้นหาก:
lsคำสั่งไม่เหมาะสมใด ๆ ของข้อกำหนดดังกล่าวข้างต้น
อย่างไรก็ตามนี่คือข้อ จำกัด การเขียนโปรแกรมที่จะป้องกันไม่ให้ lsถูกฝังอยู่ในตัวที่กำลังดำเนินการในกระบวนการเดียวกับล่ามทุบตี เหตุผลการออกแบบสำหรับคำสั่งที่ไม่ได้รับการฝังอยู่ในตัวเชลล์คือ:
เกี่ยวกับเหตุผลแรก - คุณต้องการให้เชลล์มีความเป็นอิสระและมีความยืดหยุ่นมากที่สุด คุณไม่ต้องการให้เชลล์ติดกับlsNFS mount นั่นคือ "ไม่ตอบสนองยังคงพยายาม"
เกี่ยวกับเหตุผลข้อที่สอง - ในหลาย ๆ กรณีคุณอาจต้องการใช้เชลล์สำหรับระบบที่ใช้ Busybox หรือระบบไฟล์อื่น ๆ ที่มีการlsใช้งานที่แตกต่างกัน หรือแม้แต่ใช้เชลล์ซอร์สเดียวกันใน OS ของที่มีความแตกต่างกันlsการใช้งานที่
เกี่ยวกับเหตุผลที่สาม - สำหรับการแสดงออกเช่นfind . -type d | xargs ls -ladมันจะเป็นเรื่องยากหรือเป็นไปไม่ได้ที่จะใช้lsในกระบวนการเดียวกับล่ามเปลือก
เกี่ยวกับเหตุผลข้อที่สี่ - lsคำสั่งบางคำสั่งอาจใช้เวลานานกว่าจะสำเร็จ คุณอาจต้องการให้เชลล์ดำเนินการอย่างอื่นต่อไปในระหว่างนี้
หมายเหตุ: ดูโพสต์ที่เป็นประโยชน์นี้โดยWarren Youngเพื่อตอบคำถามที่คล้ายกัน
lsลงในกระบวนการภายนอก มันสามารถทำได้ แต่มันจะซับซ้อน
bash alias | grep lsอินพุตcat /etc/passwd | while read a; do echo "$a"; done
lsไม่ต้องใช้กระบวนการแยกต่างหาก จริง ๆ แล้วคำสั่งน้อยมากต้องการกระบวนการแยกต่างหาก: เฉพาะคำสั่งที่ต้องการเปลี่ยนสิทธิ์
ตามกฎแล้วเชลล์ใช้คำสั่งเป็นบิลด์เมื่อจำเป็นต้องใช้คำสั่งเหล่านั้นเป็นบิลด์ คำสั่งเช่นalias, cd, exit, export, jobs, ... ต้องอ่านหรือแก้ไขบางรัฐภายในของเปลือกและดังนั้นจึงไม่สามารถเป็นโปรแกรมแยก คำสั่งที่ไม่มีข้อกำหนดดังกล่าวสามารถแยกคำสั่งได้ ด้วยวิธีนี้พวกเขาสามารถเรียกจากเปลือกหรือโปรแกรมอื่น ๆ
การดูรายการบิวด์อินใน bash เฉพาะบิวด์อินต่อไปนี้เท่านั้นที่สามารถใช้เป็นคำสั่งแยก สำหรับบางคนอาจมีการสูญเสียฟังก์ชันการทำงานเล็กน้อย
command- แต่มันจะเสียประโยชน์ในสถานการณ์ที่PATHอาจไม่สามารถตั้งค่าได้อย่างถูกต้องและสคริปต์ใช้commandเป็นส่วนหนึ่งของการตั้งค่าecho - มันเป็น builtin สำหรับประสิทธิภาพhelp - มันสามารถใช้ฐานข้อมูลแยกจากกันได้ แต่การฝังข้อความช่วยเหลือลงในเชลล์ที่สามารถเรียกใช้งานได้นั้นมีข้อดีของการทำให้เชลล์สามารถเรียกทำงานได้ในตัวkill - มีข้อดีสองประการในการมี builtin: มันสามารถรับรู้ตำแหน่งงานนอกเหนือจาก ID กระบวนการและสามารถใช้งานได้แม้ว่าจะมีทรัพยากรไม่เพียงพอที่จะเริ่มกระบวนการแยกต่างหากprintf- ด้วยเหตุผลเดียวกันกับechoและเพื่อสนับสนุน-vตัวเลือกในการใส่ผลลัพธ์ในตัวแปรpwd - builtin มีความสามารถเพิ่มเติมของการติดตามไดเรกทอรีโลจิคัลปัจจุบัน (ปล่อยให้ลิงก์สัญลักษณ์ไม่เสียหายแทนที่จะขยายออก)test- มันมีประสิทธิภาพในตัว (และทุบตีด้วยเวทมนตร์ด้วยไฟล์ที่เรียกว่า/dev/fd/…ระบบปฏิบัติการบางระบบ)กระสุนจำนวนหนึ่งมีจำนวนบิวด์อินเพิ่มขึ้นจำนวนมาก มีสายสะพายซึ่งเป็นเชลล์ที่ออกแบบมาให้เป็นไบนารีแบบสแตนด์อโลนสำหรับการซ่อมแซมฉุกเฉิน (เมื่อคำสั่งภายนอกบางอย่างอาจไม่สามารถใช้งานได้) แต่ก็มีในตัวlsเรียกว่า-lsเช่นเดียวกับเครื่องมืออื่น ๆ เช่นและ-grep -tarบิวด์อินของ Sash มีความสามารถน้อยกว่าคำสั่งแบบเต็ม ข้อเสนอ zsh builtins ที่คล้ายกันบางอย่างในของzsh โมดูล มันไม่ได้มีlsแต่การขยายตัวสัญลักษณ์ ( echo *) และzstatสามารถให้บริการฟังก์ชั่นที่คล้ายกัน
ฉันคิดว่าสิ่งที่คนขาดหายไปในที่นี้คือความซับซ้อนของการเฉือนของlsโปรแกรมGNU บน Linux เมื่อเปรียบเทียบขนาดที่สามารถใช้งานได้ของlsไปยังbashและdashเชลล์บนระบบ Debian ของเราเราเห็นว่ามันมีขนาดค่อนข้างใหญ่:
graeme@graeme:~$ ls -lh /bin/{ls,bash,dash}
-rwxr-xr-x 1 root root 953K Mar 30 2013 /bin/bash
-rwxr-xr-x 1 root root 115K Dec 25 20:25 /bin/dash
-rwxr-xr-x 1 root root 108K Jul 20 22:52 /bin/ls
การรวมฟีเจอร์lsเต็มรูปแบบเช่นเดียวกับ GNU เวอร์ชั่นbashจะเพิ่มขนาดไฟล์เรียกทำงานได้ 10% มันเกือบจะเป็นขนาดเดียวกับdashกระสุนเต็ม!
บิวด์เชลล์ส่วนใหญ่จะถูกเลือกเพราะมันรวมเข้ากับเชลล์ในวิธีที่เอ็กซีคิวต์ภายนอกไม่สามารถทำได้ (คำถามชี้ให้เห็นcdแต่อีกตัวอย่างหนึ่งคือเวอร์ชันทุบตีของkillการรวมเข้ากับการควบคุมงานทุบตี) หรือเพราะเป็นคำสั่งที่ง่ายมาก ให้ความเร็วที่มากเทียบกับขนาดผลตอบแทน ( trueและfalseเป็นเรื่องง่ายเท่าที่จะได้รับ)
GNU lsมีวัฏจักรการพัฒนาที่ยาวนานและอาจมีตัวเลือกในการปรับแต่งผลลัพธ์ที่แสดง การใช้ builtin ls เป็นค่าเริ่มต้นอาจสูญเสียฟังก์ชันการทำงานนี้หรือเพิ่มความซับซ้อนและขนาดของเชลล์
cdถูกสร้างขึ้นในเปลือกเป็นโปรแกรมแยกต่างหากที่คุณจะเห็นที่ls/bin/ls
ทำสิ่งที่คุณกำลังมองหา:
printf "%s\n" *
นอกจากนี้คุณสามารถจัดเก็บชื่อไฟล์ในอาร์เรย์:
files=(`printf "%s\n" *`) #items are separated by whitespace
echo ${#files[*]} files
for index in ${!a[*]}
do printf "%d: %s\n" $index ${a[$index]};
done
แต่มันไม่สนใจช่องว่างในชื่อ
สิ่งนี้ส่งผ่านไปยังตัวแปรและไม่สนใจช่องว่าง:
printf "%s\n" * | while read a; do echo $a; done
lsจะเป็นโปรแกรมภายนอกecho *หรือecho * .*(ขึ้นอยู่กับตัวเลือกของเชลล์) ทำงานได้ค่อนข้างดีในการแสดงรายการไฟล์โดยไม่ต้องฟอร์ก