หากคุณใช้ 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 ของคุณได้ไหม จะช่วยให้บล็อกเติบโต &ผู้คนจะได้เรียนรู้มากขึ้น 🙂