สคริปต์ที่เขียนเองและใช้งานบ่อย
(evanhahn.com)- แนะนำ shell script หลากหลายตัวที่เขียนขึ้นระหว่างการดูแล dotfiles มานานกว่า 10 ปี โดยคัดเฉพาะตัวที่ใช้งานบ่อยที่สุด
- แบ่งเป็นหมวด คลิปบอร์ด·การจัดการไฟล์·อินเทอร์เน็ต·การประมวลผลข้อความ·ตัวเรียก REPL·วันที่/เวลา·AV·โปรเซส·ข้อมูลอ้างอิงด่วน·ระบบ·เบ็ดเตล็ด และแต่ละสคริปต์นำเสนอในรูปแบบแรปเปอร์สั้น ๆ พร้อม ตัวอย่างใช้งานจริง
- สคริปต์ส่วนใหญ่ทำงานได้ทั้งบน macOS และ Linux โดยแนวคิดหลักคือ “ทำให้ รายละเอียดจุกจิกที่ยุ่งยากของเครื่องมือที่มีอยู่แล้วเรียบง่ายขึ้น”
- ผสาน ยูทิลิตี้มาตรฐาน อย่าง
pbcopy/xclip,python3 -m http.server,yt-dlp,ffmpeg,mpvเป็นต้น
- ผสาน ยูทิลิตี้มาตรฐาน อย่าง
- ตัวที่ใช้บ่อยที่สุด ได้แก่
copy/pasta/pastas/cpwd,mkcd/tempe/trash/mksh,serveit/getsong/getpod/getsubs,scratch/straightquote/markdownquote,timer/boop/tunesเป็นต้น
แนะนำสคริปต์ที่ใช้งานบ่อยที่สุดซึ่งสร้างขึ้นระหว่างการดูแล dotfiles ของฉัน
- ในบรรดา shell script หลากหลายตัวที่สร้างขึ้นระหว่างการจัดการ dotfiles ส่วนตัวมานานกว่า 10 ปี บทความนี้จัดหมวดหมู่สคริปต์ที่ใช้งานบ่อยตามประเภทงาน
- แต่ละสคริปต์ให้ทั้งวัตถุประสงค์ ความถี่ในการใช้งาน และตัวอย่างเด่น เพื่อเพิ่ม ความพร้อมสำหรับนำไปใช้ได้ทันที
- เป้าหมายร่วมกันคือ ลดงานซ้ำ ๆ, สร้าง abstraction ข้ามแพลตฟอร์ม, และ เพิ่มความปลอดภัยกับความอ่านง่าย
สคริปต์เกี่ยวกับคลิปบอร์ด
copyและpasta: แรปเปอร์ที่ครอบตัวจัดการคลิปบอร์ดของระบบ โดยอิงกับpbcopyของ macOS หรือxclipของ Linuxcopy: คัดลอกผลลัพธ์ไปยังคลิปบอร์ดpasta: ดึงข้อความจากคลิปบอร์ดแล้วแสดงผล- ตัวอย่าง:
run_some_command | copy,pasta > file.txt,vim "$(pasta)",pasta | base64 --decode
pastas: เครื่องมือที่แสดงเนื้อหาใหม่แบบเรียลไทม์ทุกครั้งที่สถานะคลิปบอร์ดเปลี่ยน- มีประโยชน์สำหรับบันทึกลิงก์ทั้งหมดที่คัดลอกไว้ลงไฟล์ หรือดาวน์โหลดหลายลิงก์แบบรวดเดียว
- ตัวอย่าง:
pastas > everything_i_copied.txt,pastas | wget -i -
cpwd: คัดลอกพาธของไดเรกทอรีปัจจุบันไปยังคลิปบอร์ด- สะดวกเมื่อย้ายไดเรกทอรีระหว่างหลายแท็บเทอร์มินัล
สคริปต์จัดการไฟล์
mkcd foo: สร้างไดเรกทอรีและย้ายเข้าไปทันที (ย่อจากmkdir foo && cd foo)tempe: ย้ายไปยังไดเรกทอรีชั่วคราว (cd "$(mktemp -d)") ไม่ต้องเก็บกวาดเมื่อต้องทำงานชั่วคราวในสภาพแวดล้อมแบบ sandbox- ตัวอย่าง:
# Download a file and extract it tempe wget 'https://example.com/big_file.tar.xz' tar -xf big_file.tar.xz # ...do something with the file... # Write a quick throwaway script to try something out tempe vim foo.py python3 foo.py
- ตัวอย่าง:
trash: ย้ายไฟล์ไปถังขยะ (รองรับ macOS/Linux) เพื่อป้องกันความผิดพลาดเมื่อเทียบกับrmแบบตรง ๆmksh: สร้างไฟล์ shell script ใหม่ ตั้งให้รันได้ และเปิดด้วยเอดิเตอร์ทันที
สคริปต์เกี่ยวกับอินเทอร์เน็ต
serveit: รัน static file server จากไดเรกทอรีในเครื่อง (พอร์ตเริ่มต้น 8000 และมีทางเลือกสำรองหากไม่มี Python)getsongใช้yt-dlpเพื่อดาวน์โหลดไฟล์เสียงคุณภาพสูงสุดgetpodเป็นแรปเปอร์สำหรับดึงวิดีโอมาเป็นเสียงสำหรับพอดแคสต์getsubsใช้ลอจิกเลือกซับทางการก่อนและ fallback เป็นซับอัตโนมัติ เพื่อ ดึงซับภาษาอังกฤษ เหมาะสำหรับ pipeline การสรุป และการสำรองข้อมูล- ตัวอย่าง :
getsubs https://video.example/foo | ollama run llama3.2 "Summarize this"
- ตัวอย่าง :
wifi off/on/toggle: ควบคุม WiFi ของระบบ ใช้เมื่อต้องแก้ปัญหาเครือข่ายurl: แยกและดึงส่วนประกอบของสตริง URL เช่น โปรโตคอล โฮสต์ พาธ คิวรี แฮช เป็นต้น
สคริปต์ประมวลผลข้อความ
line 10: แสดงบรรทัดที่กำหนดจาก standard input (คล้ายhead,tail)scratch: ใช้เปิดบัฟเฟอร์ข้อความชั่วคราวใน Vim อย่างรวดเร็วในลักษณะ$EDITOR $(mktemp)เหมาะกับการจดบันทึกครั้งเดียวหรือแปลงข้อความเล็ก ๆstraightquote: แปลง smart quote ให้เป็น quote แบบตรง เพื่อป้องกันปัญหาเครื่องหมายอัญประกาศในโค้ดและลดขนาดไฟล์markdownquote: เติม>หน้าทุกบรรทัดเพื่อสร้าง Markdown blockquotelength: คืนค่าความยาวของสตริงที่ป้อนเข้า (ใช้แทนwc -cได้)jsonformat: จัดรูปแบบ JSON ให้อ่านง่ายuppered/lowered: แปลงสตริงเป็นตัวพิมพ์ใหญ่/ตัวพิมพ์เล็กnato bar: แปลงสตริงที่ป้อนเข้าเป็นรหัสอักษร NATO (Bravo Alfa Romeoเป็นต้น)u+ 2025: ค้นหาชื่อและสัญลักษณ์ของอักขระ Unicodesnippets foo: ดึงวลีลัดที่กำหนดไว้จากพจนานุกรมสไนเป็ตส่วนตัวsnippet arrowคือ ลูกศร→,snippet recruiterคือเทมเพลตข้อความอย่าง “not interested”
เกี่ยวกับตัวเรียก REPL
- ได้แรงบันดาลใจจาก
irbของ Ruby เพื่อเรียก REPL ของหลายภาษาอย่างรวดเร็ว:iclj: Clojureijs: Deno (ถ้าไม่มีจะใช้ Node)iphp: PHPipy: Pythonisql: SQLite (โหมด in-memory จาก Bash)
สคริปต์วันที่และเวลา
hoy: แสดงวันที่ปัจจุบันในรูปแบบ ISO (ตัวอย่าง: 2020-04-20) ใช้เป็นคำนำหน้าไฟล์ได้timer 10m: ตัวจับเวลา (เช่น 10 นาที) เมื่อครบจะส่งเสียงและแจ้งเตือนผ่าน OSrn: ใช้dateและcalเพื่อแสดงเวลาปัจจุบันและปฏิทินรายเดือนให้อ่านง่าย
การจัดการเสียง วิดีโอ และภาพ
ocr: ดึงข้อความจากไฟล์ภาพบน macOS (มีแผนขยายต่อ)boop: แจ้งเตือนด้วยเสียงตามผลสำเร็จ/ล้มเหลวของคำสั่งก่อนหน้า (ใช้งานได้อย่างเป็นธรรมชาติหลังรันเทสต์ เป็นต้น)sfx: เล่นไฟล์เสียงเอฟเฟกต์ (.ogg) ที่กำหนด และเชื่อมใช้กับboop,timerได้tunes: เล่นไฟล์เสียงด้วยmpv(รองรับ shuffle)pix: ดูภาพถ่ายด้วยmpvradio: ตัวเรียกด่วนสำหรับสถานีวิทยุอินเทอร์เน็ตที่ชอบspeak: อ่านข้อความจาก stdin แล้วลบ Markdown ก่อนส่งเข้า text-to-speech (TTS)shrinkvid: บีบอัดไฟล์วิดีโอด้วยffmpegremoveexif: ลบข้อมูล EXIF จาก JPEG และมีแผนรองรับหลายฟอร์แมตในอนาคตtuivid: ดูวิดีโอภายในเทอร์มินัล แม้ใช้งานจริงไม่บ่อยแต่เป็นฟังก์ชันที่แปลกดี
การจัดการโปรเซส
each: ทางเลือกแทนxargs,find ... -execที่ช่วยให้รันคำสั่งซับซ้อนได้ง่ายขึ้นrunning foo: ค้นหาโปรเซสที่กำลังรันอยู่ด้วยคีย์เวิร์ดที่กำหนด (PID, คำสั่ง ฯลฯ) แล้วแสดงผลในรูปแบบที่อ่านง่ายmurder: ตัวครอบkillที่ค่อย ๆ ปิดโปรแกรมจากสัญญาณแบบนุ่มนวลไปจนถึงบังคับปิดทีละขั้น เพื่อลดความผิดพลาดเวลาให้โปรแกรมจบการทำงานwaitfor $PID: รอจนกว่า PID ที่กำหนดจะจบการทำงาน โดยคงสถานะตื่นไว้ตลอดbb my_command: รันคำสั่งในโหมด background จริง เหมาะกับงานอย่างเดมอนprettypath: แสดง$PATHแบบขึ้นบรรทัดใหม่ให้อ่านง่ายในภาพรวม (มีประโยชน์เวลา debug)tryna my_command/trynafail my_command: รันซ้ำจนกว่าจะสำเร็จ (run until success) หรือจนกว่าจะล้มเหลว (run until fail) ประยุกต์ใช้กับเครือข่ายและงานอัตโนมัติอื่น ๆ ได้
เครื่องมืออ้างอิงด่วน
emoji: ค้นหาและแสดง emoji ด้วยคีย์เวิร์ดhttpstatus: แสดงรายการ HTTP status code ทั้งหมด และดูคำอธิบายของโค้ดที่ต้องการalphabet: แสดงตัวอักษรภาษาอังกฤษพิมพ์เล็กและพิมพ์ใหญ่ทั้งหมด (ใช้งานบ่อยกว่าที่คิด)
การจัดการระบบ
theme 0/theme 1: เปลี่ยนธีมทั้งระบบ (มืด/สว่าง) และเชื่อมกับ Vim, Tmux ฯลฯsleepybear: ให้ระบบเข้าสู่โหมดสลีป (macOS, Linux)ds-destroy: ลบไฟล์.DS_Storeแบบ recursive มีประโยชน์เวลาเก็บกวาดโฟลเดอร์บน macOS
อื่น ๆ
catbin foo: ดูซอร์สโค้ดของไฟล์ใน PATH ได้ทันทีnotify: ส่งการแจ้งเตือนระดับ OS ทันทีเมื่อทำงานที่ใช้เวลานานเสร็จuuid: สร้าง UUID เวอร์ชัน 4
สรุป
- สคริปต์ที่แนะนำในบทความนี้เป็นเครื่องมือที่ผู้เขียนใช้งานอยู่บ่อยจริง
- สคริปต์คำสั่งลัดที่ทำขึ้นเองมีประสิทธิภาพมากในการ เพิ่มประสิทธิภาพการทำงาน ป้องกันความผิดพลาด และยกระดับผลิตภาพ
- ขอแนะนำให้ทุกคนลองสร้างและใช้งานสคริปต์อัตโนมัติในแบบของตัวเอง
2 ความคิดเห็น
ทำให้นึกถึงโพสต์บน GeekNews ที่ชื่อว่า Ask GN: มี shell snippet ที่ใช้บ่อยกันไหม? เหมือนกันนะ
ความคิดเห็นจาก Hacker News
คำสั่ง
trash a.txt b.pngคือการย้ายไฟล์a.txtและb.pngไปที่ถังขยะ รองรับทั้ง Mac และ Linux วิธีที่ฉันเคยใช้ก่อนหน้านี้จะจัดการทีละไฟล์ ทำให้ได้ยินเสียงลบทุกไฟล์ และกู้คืนได้แค่ไฟล์ล่าสุดผ่าน ⌘Z ใน Finder เท่านั้น จะปรับปรุงก็ได้ แต่จริง ๆ แล้วใช้คำสั่งtrashอย่างเป็นทางการที่มีมากับ macOS สะดวกกว่า เพราะไม่ได้ใช้ Finder เลยจึงไม่มีเสียงหรือการกู้คืนด้วย ⌘Z แต่เร็วกว่าและยังใช้ฟังก์ชัน “Put Back” ได้ด้วย ส่วนการ pretty-print JSON ถ้าใช้ jq แทน node ก็เขียนสั้นกว่าเยอะ และทุกวันนี้ macOS ก็ติดตั้ง jq มาให้แล้ว เช่นเดียวกันกับการพิมพ์ uuid ถ้าต้องการ v4 UUID การใช้ uuidgen ก็เป็นทางเลือกที่ตรงไปตรงมา(ดู man page)หลายครั้งการใช้ความสามารถที่มีมาให้ในระบบก็ดีกว่าเขียนสคริปต์เอง เช่น ใน vim แทนที่จะใช้ markdownquote ก็แค่เลือกคอลัมน์แรกด้วย ctrl-v แล้วกด "i> " จากนั้นกด escape ก็พอ สั้นและมีประสิทธิภาพกว่า ฉันสงสัยว่าทำไม u+ 2025 ถึงคืนค่า ñ ทั้งที่ค่า Unicode จริงคือ U+00F1 และ
catbin fooก็เท่ากับcat "$(which foo)"ถ้าใช้ zsh คำสั่งcat =fooจะสั้นกว่าและทรงพลังกว่า ใน zsh มี auto-complete หลังเครื่องหมาย = ทำให้ใช้กับคำสั่งยาว ๆ ได้อย่างปลอดภัย ฉันใช้บ่อย เช่นfile =firefox,vim =myscript.shฉันเดาว่าผู้เขียนคงไม่รู้จัก uuidgen สิ่งที่ดีของการแชร์ความรู้หรือการตั้งค่าแบบนี้คือมันมักเผย blind spot ของตัวเองออกมา นั่นแหละทำไมการแชร์ถึงสำคัญ
Python ก็ pretty-print JSON ได้ในตัว
ขอบคุณสำหรับข้อมูลเรื่อง
trashตลอดมาฉันใช้ AppleScript แบบ "tell app "Finder" to move {%s} to trash" เพื่อส่งหลายไฟล์ไปถังขยะถ้าเป็นทางเลือกแทน rm กับ trash ก็ขอแนะนำ rip ด้วย ลิงก์โปรเจกต์ rip
วงจรชีวิตของนักพัฒนานี่น่าสนใจมาก ตอนเริ่มต้นก็ใช้แค่สภาพแวดล้อมเชลล์แบบ vanilla แต่พอทำงานได้ 1–2 ปี ก็เริ่มเขียนสคริปต์และ bash alias กันเป็นร้อยบรรทัด ตอนนี้ทำมา 15 ปีแล้วกลับกลายเป็นพยายามใช้แค่เชลล์พื้นฐานที่สุด ไม่ใช้ alias และเรื่องที่ซับซ้อนก็ย้ายไปทำใน Python หรือ Go
แนวโน้มนี้ดูไม่ใช่เพราะบรรลุอะไรบางอย่าง แต่เหมือนมาจากความขี้เกียจมากกว่า (พูดแบบนี้ได้เพราะฉันก็เป็นเหมือนกัน) เพื่อนร่วมงานที่ชอบปรับแต่งสภาพแวดล้อมช่วยให้ฉันได้รู้จักเครื่องมือใหม่ ๆ บ่อยมาก ช่วงหลังก็เพิ่มเครื่องมืออย่าง atuin, fzf ลงใน Linux ด้วย
ฉันใส่ alias กับ function ไว้ใน dotfile เพื่อบันทึก/ช่วยจำคำสั่งที่ใช้บ่อย อัปเดตชุดเครื่องมือที่ใช้ประจำได้เรื่อย ๆ และย้ายไปเครื่องใหม่ก็ง่าย
สมัยก่อนตอนมีเครื่อง nix แค่เครื่องเดียว ฉันอยากปรับแต่งเต็มที่ แต่ตอนนี้ใช้หลายเครื่องพร้อมกัน ก็เลยติดตั้งแค่แพ็กเกจที่จำเป็นเพื่อให้สภาพแวดล้อมเหมือนกัน
สิ่งที่เขียนด้วย Python ฉันก็ยังเรียกว่า script อยู่ คิดว่าคำว่า script ไม่ได้จำกัดแค่ shell script
ทุกวันนี้พอทำงานกับวิศวกรรุ่นใหม่แล้วเห็นพวกเขาใช้ dotfiles หลายชุด ก็รู้สึกว่า “เมื่อก่อนฉันก็เคยทำแบบนั้น มันยุ่งเหมือนกันนะ” ตอนนี้ฉันเลือกใช้เครื่องมือเท่าที่จำเป็นและปรับให้ยืดหยุ่นตามงาน พร้อมทั้งเคารพสไตล์ของคนอื่นด้วย
ฉันชอบมากที่เจอโพสต์ทิปใช้งานจริงแบบนี้ใน HN อยากรู้ว่านักพัฒนาคนอื่นทำงานกันจริง ๆ อย่างไร และมีอะไรที่ฉันเรียนรู้แล้วเอาไปใช้ได้บ้าง ตอนแรกอาจคิดว่า “คงไม่จำเป็นกับฉันหรอก” แต่ถ้างานบางอย่างทำได้ง่ายขึ้น มันก็อาจสร้าง workflow ใหม่ขึ้นมาเลย ดังนั้นฉันมักจะลองก่อนแล้วค่อยเก็บสิ่งที่เข้ากับตัวเองไว้ ฉันยังชอบสไตล์ของโพสต์ต้นฉบับด้วย—การบอกความถี่ในการใช้งานจริงนี่มีประโยชน์มาก สำหรับงานง่าย ๆ ฉันมักเปิด browser devtools แล้วใช้ JavaScript จบเลย (เช่น เวลาแปลงสตริงเป็นตัวพิมพ์เล็ก)
น่าสนใจดีถ้าจะลองทำ cost-benefit analysis จริง ๆ โดยเทียบเวลาที่วิธีของผู้เขียนกับวิธีของฉันใช้ รวมถึงต้นทุนของการสร้างสคริปต์ การจำ การอ้างอิง และการย้ายสภาพแวดล้อม
ภาพชีตสรุปคีย์ลัด Bash นี้ ช่วยได้มาก
แทนที่จะใช้สคริปต์ line การพิมพ์บรรทัดที่ต้องการด้วย sed ง่ายกว่า
ใช้พิมพ์บรรทัดที่สองได้ และถ้าจะพิมพ์หลายบรรทัดก็ใช้
ได้ด้วย จึงได้เปรียบกว่าสคริปต์ line
ฉันมีสคริปต์ง่าย ๆ ที่ใช้บ่อยอยู่หลายตัว เช่น:
ฉันตั้งชื่อสคริปต์ส่วนตัวให้ขึ้นต้นด้วย , (comma) เพื่อจะได้สลับไปใช้ได้เร็ว ฉันคิดว่าการเอาสคริปต์ส่วนตัวของตัวเองมาทำสถิติจาก history เป็นระยะ ๆ แล้วเก็บตัวที่ไม่ค่อยได้ใช้ออกไปนั้นมีคุณค่า
ถึงจะยังทำให้เป็นทั่วไปไม่ได้ แต่ฉันใช้งานสคริปต์
unmvแล้วรู้สึกว่าสะดวกมากมีทิปดี ๆ เยอะเลย แต่โดยรวมฉันมักเรียนรู้และใช้ utility มาตรฐาน (sed, awk, grep, xargs ฯลฯ) เพราะต้องทำงานข้ามหลายระบบ และสคริปต์ส่วนตัวกับ alias ของฉันส่วนใหญ่ไม่ได้ติดตั้งไว้ทุกที่ แต่ utility มาตรฐานทำได้แทบทุกอย่าง
ขอแชร์สคริปต์แตกไฟล์ที่ฉันชอบที่สุด
ฉันก็อยากทำตัว counterpart ที่ใช้บีบอัดเป็นฝั่งตรงข้ามของมันเหมือนกัน
ฉันใช้ dtrx เพราะมันจะแตกไฟล์ลงในโฟลเดอร์ให้โดยอัตโนมัติ ชอบตรงนี้มาก
ฉันว่า aunpack ใช้ง่ายกว่า
เรียบง่ายดีจริง ๆ
ถ้าเพิ่ม inotify กับ systemd user service เข้าไปก็น่าจะไปได้อีกขั้น เหมือนเวอร์ชันที่มีเป็นแพ็กเกจอยู่แล้ว สิ่งที่ทำเองนี่ให้ความรู้สึกเหมือนประดิษฐ์ล้อขึ้นมาใหม่
ฉันมีฟังก์ชันอยู่สองตัวที่ใช้ประจำเวลา encode หรือตัด mp4 โดยแฟล็กที่ใช้ทำให้รองรับกับสภาพแวดล้อมหลายแบบได้สูงมาก เช่น WhatsApp, Discord บนมือถือ ฯลฯ
fftimeจะตัดได้เร็วโดยไม่ re-encode ต้นฉบับ แต่บางครั้งอาจมีปัญหาเล็กน้อยกับวิดีโอบางไฟล์ (เช่น เล่นไม่ได้) ถ้าจะ re-encode ก็เอา-c copyออกทุกครั้งที่สร้างและทดสอบ alias หรือ function ฉันชอบให้
~/.zshrcมีผลทันที เลยใช้ alias แบบนี้และบน Mac ฉันใช้ function ด้านล่างสำหรับ grep ในไฟล์ docx
อีกอย่าง เวลาจะเอาข้อความจาก clipboard บน Mac ไปแปะในที่สาธารณะ เช่น ChatGPT หรือ Slack ภายในบริษัท ฉันจะรันฟังก์ชันด้านล่างเพื่อทำให้ไม่ระบุตัวตนสำหรับใช้ดีบักได้ ฟังก์ชันนี้จะแสดง clipboard ที่แปลงแล้วออกทาง stdout ด้วย จึงเช็กได้ว่ามีอะไรหลุดไปหรือไม่