หากคุณใช้ Linux หรือ Mac ทุกครั้งที่คุณเปิดเทอร์มินัล แสดงว่าคุณกำลังใช้แอปพลิเคชันเชลล์อยู่
เชลล์เป็นส่วนต่อประสานที่ช่วยให้คุณรันคำสั่งในระบบของคุณ
เชลล์โฮสต์ตัวแปรสภาพแวดล้อม &มีคุณสมบัติที่มีประโยชน์ เช่น ประวัติคำสั่งและการเติมข้อความอัตโนมัติ
หากคุณเป็นคนประเภทที่ชอบเรียนรู้ว่าสิ่งต่างๆ ทำงานอย่างไร โพสต์นี้เหมาะสำหรับคุณ!
เชลล์ทำงานอย่างไร
ในการสร้างแอปพลิเคชันเชลล์ของเราเอง มาคิดกันว่าเชลล์คืออะไร:
ขั้นแรก จะมีข้อความแจ้ง โดยปกติจะมีข้อมูลเพิ่มเติม เช่น ผู้ใช้ปัจจุบันและไดเร็กทอรีปัจจุบันของคุณ จากนั้นให้พิมพ์คำสั่ง &เมื่อคุณกด Enter ผลลัพธ์จะปรากฏบนหน้าจอของคุณ
ใช่ ฟังดูธรรมดามาก แต่นี่ไม่ได้ทำให้คุณนึกถึงอะไรเหรอ
หากคุณกำลังนึกถึง pry
ถ้าอย่างนั้นคุณพูดถูก!
เชลล์ใน REPL (Read-Eval-Print-Loop) สำหรับระบบปฏิบัติการของคุณโดยพื้นฐาน
เมื่อรู้ว่าเราสามารถเขียนเวอร์ชันแรกของเชลล์ของคุณ :
prompt = "> " print prompt while (input = gets.chomp) break if input == "exit" system(input) print prompt end
สิ่งนี้จะทำให้เรามีเปลือกที่เล็กที่สุด แต่ใช้งานได้จริง เราสามารถปรับปรุงสิ่งนี้ได้โดยใช้ไลบรารีที่แอปพลิเคชันที่คล้ายกับ REPL อื่นๆ ใช้
ห้องสมุดนั้นชื่อ Readline
.
การใช้ไลบรารี Readline
Readline เป็นส่วนหนึ่งของ Ruby Standard Library ดังนั้นจึงไม่มีอะไรต้องติดตั้ง คุณเพียงแค่ต้อง require
มัน.
ข้อดีอย่างหนึ่งของการใช้ Readline
คือสามารถเก็บประวัติคำสั่งให้เราได้โดยอัตโนมัติ
นอกจากนี้ยังสามารถดูแลการพิมพ์พรอมต์คำสั่งและสิ่งอื่น ๆ อีกมากมาย
นี่คือเชลล์ v2 ของเรา คราวนี้ใช้ Readline
:
require 'readline' while input = Readline.readline("> ", true) break if input == "exit" system(input) end
ดีมาก เรากำจัด puts
. สองอัน เพื่อความรวดเร็ว &ตอนนี้เราสามารถเข้าถึงความสามารถอันทรงพลังจาก Readline
. ตัวอย่างเช่น เราสามารถใช้แป้นพิมพ์ลัดเพื่อลบคำ (CTRL + W
) หรือแม้แต่ค้นหาประวัติ (CTRL + R
)!
มาเพิ่มคำสั่งใหม่เพื่อพิมพ์ประวัติทั้งหมด:
require 'readline' while input = Readline.readline("> ", true) break if input == "exit" puts Readline::HISTORY.to_a if input == "hist" # Remove blank lines from history Readline::HISTORY.pop if input == "" system(input) end
เกร็ดน่ารู้:หากคุณลองใช้โค้ดนี้แบบงี่เง่า คุณจะได้รับประวัติคำสั่งของ pry! เหตุผลก็คือ pry ก็ใช้
Readline
และReadline::HISTORY
เป็นสถานะที่ใช้ร่วมกัน
ตอนนี้คุณสามารถพิมพ์ hist
เพื่อรับประวัติคำสั่งของคุณ 🙂
การเพิ่มการเติมข้อความอัตโนมัติ
ด้วยคุณสมบัติเติมข้อความอัตโนมัติของเชลล์ที่คุณชื่นชอบ คุณจะสามารถบันทึกการพิมพ์ได้มาก Readline ทำให้การรวมคุณลักษณะนี้เข้ากับเชลล์ของคุณเป็นเรื่องง่าย
เริ่มต้นด้วยการเติมคำสั่งอัตโนมัติจากประวัติของเรา
ตัวอย่าง :
comp = proc { |s| Readline::HISTORY.grep(/^#{Regexp.escape(s)}/) } Readline.completion_append_character = " " Readline.completion_proc = comp ## rest of the code goes here ##
ด้วยรหัสนี้ คุณจะสามารถเติมคำสั่งที่พิมพ์ไว้ก่อนหน้านี้โดยอัตโนมัติโดยกด <tab>
กุญแจ. ตอนนี้ ไปขั้นตอนต่อไป &เพิ่มการเติมไดเร็กทอรีอัตโนมัติ
ตัวอย่าง :
comp = proc do |s| directory_list = Dir.glob("#{s}*") if directory_list.size > 0 directory_list else Readline::HISTORY.grep(/^#{Regexp.escape(s)}/) end end
completion_proc
ส่งคืนรายชื่อผู้สมัครที่เป็นไปได้ ในกรณีนี้ เราเพียงแค่ต้องตรวจสอบว่าสตริงที่พิมพ์นั้นเป็นส่วนหนึ่งของชื่อไดเร็กทอรีโดยใช้ Dir.glob
. Readline จะดูแลส่วนที่เหลือ!
การนำวิธีการของระบบไปใช้
ตอนนี้คุณควรมีเชลล์ที่ใช้งานได้พร้อมประวัติและการเติมข้อความอัตโนมัติ ไม่เลวสำหรับโค้ด 25 บรรทัด 🙂
แต่มีบางอย่างที่ฉันต้องการเจาะลึกลงไป ดังนั้นคุณสามารถรับข้อมูลเชิงลึกเกี่ยวกับสิ่งที่เกิดขึ้นเบื้องหลังของการรันคำสั่งจริงๆ
สิ่งนี้ทำโดย system
วิธีใน C วิธีนี้จะเพียงแค่ส่งคำสั่งของคุณไปที่ /bin/sh
ซึ่งเป็นแอปพลิเคชันเชลล์ มาดูกันว่าคุณจะใช้ /bin/sh
. อะไรได้บ้าง ทำใน Ruby
หมายเหตุ :ใช้งานได้บน Linux / Mac เท่านั้น 🙂
วิธีการของระบบ:
def system(command) fork { exec(command) } end
สิ่งที่เกิดขึ้นที่นี่คือ fork
สร้างสำเนาใหม่ของกระบวนการปัจจุบัน จากนั้นกระบวนการนี้จะถูกแทนที่ด้วยคำสั่งที่เราต้องการเรียกใช้ผ่าน exec
กระบวนการ. นี่เป็นรูปแบบทั่วไปในการเขียนโปรแกรม Linux
ถ้าคุณไม่ fork กระบวนการปัจจุบันจะถูกแทนที่ ซึ่งหมายความว่าเมื่อคุณเรียกใช้คำสั่ง (ls
, cd
หรืออย่างอื่น) เสร็จแล้วโปรแกรม Ruby ของคุณจะยุติการทำงานด้วย
คุณจะเห็นสิ่งที่เกิดขึ้นที่นี่:
def system(command) exec(command) end system('ls') # This code will never run! puts "after system"
บทสรุป
ในโพสต์นี้ คุณได้เรียนรู้ว่าเชลล์เป็นส่วนต่อประสานที่เหมือน REPL (คิดว่า irb
/ pry
) สำหรับการโต้ตอบกับระบบของคุณ คุณยังได้เรียนรู้วิธีสร้างเชลล์ของคุณเองโดยใช้ Readline
. อันทรงพลัง ไลบรารีซึ่งมีฟีเจอร์ในตัวมากมาย เช่น ประวัติและการเติมข้อความอัตโนมัติ (แต่คุณต้องกำหนดวิธีการทำงาน)
และหลังจากนั้นคุณก็ได้เรียนรู้เกี่ยวกับ fork
+ exec
รูปแบบที่ใช้กันทั่วไปในโครงการการเขียนโปรแกรม Linux
หากคุณชอบโพสต์นี้ คุณช่วยฉันและแบ่งปันกับเพื่อน Ruby ของคุณได้ไหม จะช่วยให้บล็อกเติบโต &ผู้คนจะได้เรียนรู้มากขึ้น 🙂