เริ่มทุกคำสั่งด้วยเครื่องหมายจุลภาค (2009)
(rhodesmill.org)- ผู้ใช้ Unix ที่ใส่สคริปต์ส่วนตัวไว้ใน
~/bin/แล้วเพิ่มลงในPATHอาจเจอชื่อคำสั่งสั้น ๆ ชนกับ คำสั่งของระบบ ใหม่ได้ - ในสภาพแวดล้อมที่มีคำสั่งให้มาจำนวนมากอย่าง Debian/Ubuntu ความเสี่ยงยิ่งสูงขึ้น โดยตัวอย่างโน้ตบุ๊ก Ubuntu เครื่องหนึ่งนับคำสั่งใน
/usr/binได้ 21,733 รายการ - หากเติม เครื่องหมายจุลภาค (
,) ไว้หน้าคำสั่งส่วนตัว เชลล์และเครื่องมือต่าง ๆ จะมองว่าเป็นอักขระธรรมดาในชื่อไฟล์ ขณะเดียวกันก็แยกจากคำสั่งของระบบได้ง่าย - เครื่องหมายจุลภาคพิมพ์ได้โดยไม่ต้องกด Shift และมีโอกาสชนต่ำกว่าวงเล็บ แบ็กสแลช โคลอน แบ็กทิก อัญประกาศเดี่ยว สแลช และจุด ซึ่งล้วนมีความหมายพิเศษในเชลล์
- กด Tab หลัง
,เพื่อไล่ดูรายการคำสั่งส่วนตัวได้ทันที ทำให้ดูแลชื่อคำสั่งใน~/bin/ให้เป็นระเบียบได้ง่าย
ทำไมชื่อคำสั่งส่วนตัวถึงชนกัน
- ผู้ใช้ Unix จำนวนมากจะสร้าง
~/bin/ไว้ในโฮมไดเรกทอรีและเพิ่มลงในPATHเพื่อใช้คำสั่งอำนวยความสะดวกและเชลล์สคริปต์ของตัวเอง - ปัญหาคือชื่อสคริปต์ส่วนตัวมักเป็น ตัวพิมพ์เล็กสั้น ๆ จึงคล้ายกับคำสั่งระบบพื้นฐานได้ง่าย
- เมื่อดิสทริบิวชัน Linux เพิ่มคำสั่งใหม่ ชื่อของมันอาจไปตรงกับคำสั่งส่วนตัวเดิมโดยบังเอิญ
- ในสภาพแวดล้อมสาย Debian ที่มีคำสั่งมาให้จำนวนมาก ปัญหานี้ยิ่งเกิดขึ้นได้จริงมากขึ้น
- หากนับจำนวนคำสั่งใต้
/usr/binโดยตรงบนโน้ตบุ๊ก Ubuntu ตัวอย่างเครื่องหนึ่ง จะได้21,733รายการ apt-file search -x '^/usr/bin/[^/]*$' | wc -l
- หากนับจำนวนคำสั่งใต้
ข้อดีของการใส่จุลภาคเป็นคำนำหน้า
- วิธีแก้คือเปลี่ยนชื่อคำสั่งส่วนตัวให้พิมพ์ง่าย แต่ก็ไม่ใช่รูปแบบที่มักถูกเลือกไปเป็นชื่อคำสั่งของระบบ
- เกณฑ์ด้านความสะดวกในการพิมพ์คือ ไม่ต้องใช้ปุ่ม Shift และเมื่อกำหนดเงื่อนไขนี้แล้ว อักขระที่ปลอดภัยก็เหลือไม่มาก
- ตัวพิมพ์เล็กถูกใช้ในคำสั่งระบบอยู่แล้วอย่างแพร่หลาย
- วงเล็บ แบ็กสแลช โคลอน แบ็กทิก และอัญประกาศเดี่ยว มีความหมายพิเศษในเชลล์
- สแลชใช้เป็นตัวคั่นไดเรกทอรี จึงใช้ในชื่อไฟล์ไม่ได้
- จุดเมื่ออยู่หน้าชื่อไฟล์หมายถึงไฟล์ซ่อน และในตำแหน่งอื่นก็มักใช้แยกนามสกุลไฟล์
- ตัวเลือกที่เหลือจึงเป็น เครื่องหมายจุลภาค (
,) แบบตรงไปตรงมา ซึ่งเครื่องมือรอบข้างและเชลล์จะมองเป็นอักขระธรรมดาในชื่อไฟล์ - หากเติมจุลภาคเป็นคำนำหน้าให้ทุกคำสั่งส่วนตัว ก็จะแยกจากคำสั่งระบบได้ชัดเจนและเลี่ยงปัญหาชื่อชนกันได้ง่าย
- เมื่อนำไปใช้ร่วมกับ Tab completion ก็เพียงพิมพ์
,แล้วตรวจดูรายการคำสั่งส่วนตัวได้ทันที- รายการตัวอย่างมี
,complete-scp,,complete-ssh,,coreoff,,coreon,,find,,go-thpgp,,gr,,hss,,mount-thpgp,,mount-twt,,range,,svn-store-password,,umountเป็นต้น
- รายการตัวอย่างมี
- วิธีนี้ถูกใช้งานมาราว 10 ปีแล้ว และแนะนำว่าเป็นแนวทางที่ดีในการจัดระเบียบชื่อคำสั่งใน
~/bin/ส่วนตัวให้สะอาดเรียบร้อย
2 ความคิดเห็น
ความคิดเห็นจาก Hacker News
ตอนเห็นแค่ชื่อเรื่อง นึกว่าจะเป็นไอเดียที่แย่มาก แต่พอเอาเข้าจริงกลับค่อนข้างชอบ โดยเฉพาะส่วนที่ใช้ Tab แสดงรายการเครื่องมือของตัวเองทั้งหมด
ช่วงหลัง ๆ ผมไม่ได้เจอปัญหา namespace ชนกันมากนัก และก็จริงที่หลังจากย้ายไปสายบริหารแล้ว ความรู้สึกทางเทคนิคก็หย่อนลงไปบ้าง สแต็กเทคโนโลยีของผมให้ความรู้สึกว่า ล้าหลังไปราว 10 ปี เลยสงสัยว่าถ้าจะกลับมาตามให้ทันความรู้สึกยุคใหม่ ควรเริ่มจากตรงไหนดี
วิธีที่ผมทำคือสร้างเครื่องมือที่ทำให้ชีวิตตัวเองสะดวกขึ้นเอง เช่น ถ้าที่บริษัทมีเว็บเซอร์วิสที่ใช้ค้นข้อมูลง่าย ๆ บ่อย ๆ ผมก็จะดูว่ามี API ไหม แล้วเขียน CLI เพื่อให้งานประจำวันเร็วขึ้น ปรับแต่งจนพอใจแล้วค่อยแชร์ให้ทีม แต่การโน้มน้าวให้คนอื่นลองใช้นั้นยากอยู่ดี ถึงอย่างนั้นผมก็ใช้มันทุกวัน เลยไม่ได้กังวลมากนัก
เป้าหมายคือเพื่อเห็นมุมมองใหม่ ๆ และคุยเรื่องเทรนด์ได้ ซึ่งบางส่วนตอนนี้ก็ถูกนำมาใช้ในงานแล้วด้วย ทำให้ผมเข้าใจคอมโพเนนต์เก่า ๆ ได้ลึกขึ้นด้วย
ผมไม่ค่อยเข้าใจปัญหานี้ แค่วางไดเรกทอรี
binของผมไว้หน้าสุดของ$PATHแทนที่จะเป็นท้ายสุดก็พอ ถ้าจะดูคำสั่งของตัวเองก็แค่รันls ~/bin$0อยู่ในพาธของระบบ แต่พอมันพังขึ้นมา ก็จะเริ่มการดีบักที่น่าหงุดหงิดสุดท้ายก็เป็นเรื่องว่าจะเลือกยาพิษฝั่งไหน
fzfได้ เช่น ใน fish คุณพิมพ์ตัวอักษรแรกของคำสั่งแล้วกด Tab เพื่อเรียกfzfขึ้นมาได้แบบนั้นแค่
,+Tab ก็กรองคำสั่งที่ผู้ใช้กำหนดเองได้เร็วมาก ในขณะที่ls ~/binต้องพิมพ์หลายตัวเกินไปสำหรับงานที่ทำบ่อย หรือไม่ก็อาจต้องใช้ls+ลูกศรขึ้นหลายครั้งเพื่อหา autocomplete ก่อนls ~/binพิมพ์ช้ากว่า,มากผมใช้ชื่อคำสั่งที่กำหนดเองแบบสั้น ๆ เช่น
aa,st,di,dp,cm,leสำหรับ wrapper บาง ๆ ที่ครอบgitหนึ่งในนั้นชนกับยูทิลิตีที่ติดตั้งมาเป็นค่าเริ่มต้นจริง ๆ ในบางระบบ แต่ไดเรกทอรี
binของผมอยู่หน้าไดเรกทอรีของระบบใน$PATHของผม ของผมเลยชนะ และผมก็ไม่ได้สนใจเครื่องมือที่ชนกันนั้นเท่าไร ถ้าเครื่องมืออื่นที่มีประโยชน์กับผมมาชนกับเครื่องมือของผม ผมน่าจะตั้ง alias ที่ไม่ชนให้เครื่องมืออื่นนั้น มากกว่าจะเปลี่ยนชื่อเครื่องมือของตัวเอง เครื่องมือสองตัวอักษร เหล่านี้สะดวกเกินไปapt-get upgradeไปเรียก Dwarf Fortress ขึ้นมาhttps://askubuntu.com/questions/938606/dwarf-fortress-starti...
gitของผมส่วนใหญ่ทำเป็นชุดสองตัวอักษรที่ขึ้นต้นด้วยgเช่นgsคือgit statusแต่บางครั้งก็ต้องใช้ GhostScript จริง ๆ เหมือนกัน มันยอดเยี่ยมมากเวลาต้อง embed ฟอนต์ในไฟล์ PDF ปกติกรณีนั้นผมจะใช้
env gsjตอนjavaโผล่มาก็เลยสนุกขึ้นพอสมควร การใช้เครื่องหมายจุลภาคเป็นไอเดียที่ค่อนข้างน่าสนใจแต่ก็ยังดีที่ไม่ได้ขึ้นต้นด้วย
kเพราะ KDE :)เช่น ผมคิดว่า
mkfsควรถูกเรียกแบบsys::mkfsอะไรทำนองนั้น เส้นแบ่งระหว่างคำสั่งระบบกับคำสั่งผู้ใช้สามารถกำหนดได้หลายแบบ และก็คงมีส่วนที่คลุมเครืออยู่ แต่ถ้าผู้ใช้สามารถเผลอรันคำสั่งที่ไม่รู้ด้วยซ้ำว่ามีอยู่ และไม่เคยติดตั้งเองอย่างชัดเจน คำสั่งนั้นก็ไม่ควรถูกเปิดเผยอยู่ใน global namespace โดยตรงมีคำถามที่เกี่ยวข้องอยู่
ผมใช้ Windows เป็นส่วนใหญ่ และเหมือนกับผู้เขียน ผมเขียนสคริปต์ CLI ที่เน้น Python ไว้หลายตัว แล้ววางไว้ในตำแหน่งเทียบเท่า
~/bin/พอตั้งpython.exeให้เป็นโปรแกรมเริ่มต้นของส่วนขยาย.pyและเพิ่ม.pyเข้าไปใน%pathext%ก็สามารถพิมพ์แค่helloจากพาธไหนก็ได้เพื่อรัน~/bin/hello.pyและใช้วันละหลายร้อยครั้ง ช่วงนี้ผมใช้ Linux มากขึ้น แต่ยังเป็นมือใหม่ เลยยังทำแบบเดียวกันไม่ได้ ใน Linux ดูเหมือนจะไม่มีแนวคิด “โปรแกรมที่เชื่อมโยงไว้” จึงเรียกไฟล์.pyตรง ๆ แล้วให้เชลล์รันด้วย Python ไม่ได้ แน่นอนว่าสามารถchmod +xให้สคริปต์ได้ แต่แบบนั้นต้องใส่ shebang ไว้ในตัวสคริปต์เอง รู้สึกเหมือนฮาร์ดโค้ดจึงไม่ค่อยสบายใจ ถ้าภายหลังอยากรันสคริปต์.pyด้วย/usr/bin/nohtypแทน/usr/bin/pythonจะทำอย่างไร อีกอย่าง ผมก็ยังหาวิธีละส่วน.pyตอนเรียกสคริปต์ไม่ได้ด้วย ผมไม่ได้จะวิจารณ์การออกแบบของ Linux และรู้ว่ามันมีข้อดีมากมาย แต่ผมอยากรันhello.pyที่อยู่ใน$PATHด้วยชื่อhelloจริง ๆmy_pythonไว้ในพาธ แล้วเขียน shebang เป็น/usr/bin/env my_pythonก็ได้ถ้าต้องการแนวทางที่เป็นหลักการกว่านี้ ให้ดูเครื่องมือ
update-alternativesมันให้ abstraction แบบนี้ในลักษณะทั่วไปกว่า: https://linuxconfig.org/how-to-set-default-programs-using-up...ใน Linux หรือจริง ๆ แล้วในแพลตฟอร์มส่วนใหญ่ที่ไม่ใช่ Windows ความหมายของ นามสกุลไฟล์ อ่อนกว่ามาก ไฟล์ปฏิบัติการทุกชนิดถูกกำหนดว่ารันได้หรือไม่ด้วยแฟล็กอย่าง
+xไม่ใช่นามสกุล ข้อดีคือแม้เปลี่ยนภาษา implementation ก็เขียนใหม่ได้โดยไม่ทำให้ฝั่งที่เรียกพัง นามสกุล.pyมีความหมายกับโมดูลที่ import มาใช้เท่านั้น ถ้าเป็นสคริปต์ที่ถูกรัน ก็แค่ดู shebang เมื่อจำเป็น สคริปต์ที่แจกจ่ายภายนอกมักใช้#!/usr/bin/env pythonส่วนสคริปต์ที่อยู่ในแพ็กเกจของดิสโทรมักถูกเขียนทับเป็น#!/usr/bin/pythonเป็นต้น อีกอย่าง shebang ไม่รองรับหลายอาร์กิวเมนต์ แต่ GNUenvรองรับอาร์กิวเมนต์-Sที่เลียนแบบเรื่องนี้ได้ อย่างไรก็ดี ปัญหาความยาวของอาร์กิวเมนต์ยังคงอยู่.pyออกจากชื่อไฟล์ก็พอ เรียกว่า"hello"ได้ ไม่มีปัญหาเลยผมนึกข้อเสียของ shebang ไม่ค่อยออก ถ้าอยากรันด้วยอินเทอร์พรีเตอร์อื่นจริง ๆ ก็ระบุชัด ๆ แบบ
"nohtyp hello"ได้ ถ้ายังรู้สึกขัดใจมาก ก็สามารถกำหนด alias ในไฟล์เริ่มต้นของเชลล์ได้ เช่นใน bash ทำได้แบบalias hello="python3 /path/to/hello.py"และถ้าตั้งใจจริง ๆ ก็เขียนสคริปต์สั้น ๆ ให้สร้าง alias แบบนี้อัตโนมัติสำหรับเนื้อหาในไดเรกทอรีที่กำหนดได้ในเชลล์สคริปต์ ปกติจะเพิ่ม shebang และทำให้ไฟล์รันได้ เพื่อประกาศไฟล์ปฏิบัติการไว้ในตัวสคริปต์เอง คิดว่า shebang เป็นเหมือนนามสกุลไฟล์ชนิดหนึ่งก็ได้ ถ้าหลังจาก
chmod +x ./malware.pyแล้ว./malware.pyไม่ทำงาน ให้ตรวจดูพาธที่ shebang ชี้ไป หากอินเทอร์พรีเตอร์สามารถรันสคริปต์เป็นอาร์กิวเมนต์ทั่วไปได้ ก็สามารถทำพฤติกรรมคล้ายกันด้วยวิธีอย่างxdg-open malware.pyได้ น่าจะเหมือนกับการดับเบิลคลิกในตัวจัดการไฟล์เริ่มต้น ตอนที่ใช้ Linux เป็นระบบปฏิบัติการเดสก์ท็อปหลัก ผมเคยมี alias ชื่อxopแต่ใช้เฉพาะกับไฟล์ข้อมูลอย่างรูปภาพหรือเอกสารที่พฤติกรรมเริ่มต้นถูกต้องอยู่แล้ว ไม่แนะนำให้ตั้งโปรแกรมเริ่มต้นของสคริปต์ที่รันได้เป็นอินเทอร์พรีเตอร์ เพราะโดยทั่วไปคุณอาจอยากเปิดสคริปต์ในเอดิเตอร์แทนที่จะรันมัน ผมคิดว่าxdg-openเป็นเครื่องมือฝั่ง Gnome แต่ไม่ได้หมายความว่าเดสก์ท็อปอื่นใช้ไม่ได้ และผมก็เคยใช้ใน Xubuntu ด้วย ถ้าคุณอยากให้ไฟล์ Python ทุกไฟล์ถูกรันเป็นค่าเริ่มต้นแม้ในบริบท GUI จริง ๆ ก็ตั้งค่าเริ่มต้นแบบนั้นได้ แต่man xdg-openอาจช่วยได้ ขอย้ำว่าไม่ใช่คำแนะนำที่ดี#!/usr/bin/env pythonแม้จะมีข้อควรระวังอยู่บ้างตาม https://unix.stackexchange.com/a/29620แบบนี้จะรัน
pythonตัวแรกที่เจอในพาธ ถ้าภายหลังอยากรันด้วย/usr/bin/nohtypแทน/usr/bin/pythonก็สร้าง symlink ชื่อpythonที่ชี้ไปยัง/usr/bin/nohtypไว้ในไดเรกทอรีที่ถูกค้นหาก่อน/usr/binได้ เช่นเพิ่ม~/myCommandPreferencesไว้หน้าสุดของ$PATHอีกวิธีในการหลีกเลี่ยงการชนกันใน
$PATHคือ ตั้งชื่อไฟล์ปฏิบัติการให้ยาวมากจนไฟล์ปฏิบัติการอื่นไม่น่าจะใช้ แล้วใส่ alias สั้น ๆ ในbashrcalias จะไม่กระทบไฟล์ปฏิบัติการที่ถูกเรียกจากภายในสคริปต์ และในสคริปต์ของผมเองก็ยังอ้างอิงด้วยชื่อยาวต่อไปได้ ข้อเสียคือจะไม่ได้ ความสะดวกของการเติมคำอัตโนมัติด้วย Tab ในระดับเดียวกัน ซึ่งส่วนนั้นยอดเยี่ยมจริง ๆ อีกอย่าง สคริปต์ที่ต้องถูก
sourceไม่ใช่รันเป็นโปรเซสลูก เช่นสคริปต์เปิดใช้งานvenvของ Python ก็ยังอาจเกิดการชนกันได้ แต่กรณีแบบนั้นมีไม่บ่อยzshการเติมคำอัตโนมัติแบบนั้นก็ทำได้ด้วยวิธีขึ้นต้นด้วยจุลภาคเป็นเทคนิคที่พบได้ทั่วไปในชุมชน ตัวขยายข้อความ/การแทนที่ข้อความ ด้วย
,ช่วงหลังผมลองดู
~/.local/bin/แล้วพบว่ามีไฟล์ปฏิบัติการหลายสิบตัวที่จำไม่ได้ว่าเคยใส่ไว้ส่วนใหญ่เกี่ยวกับ pyside แต่ก็มีสคริปต์อื่นด้วย ผมต้องเปิดดูทีละไฟล์เพื่อจำว่าอันไหนผมเขียนเอง และอันไหนคนอื่นทำ ถ้าตั้งชื่อสคริปต์ของผมให้ขึ้นต้นด้วยจุลภาค ก็คงเร็วกว่านี้มาก และยังช่วยให้นึกออกก่อนเปิดไฟล์ด้วยว่าแต่ละสคริปต์สร้างไว้ทำไม
~/.local/bin/ใช้สำหรับสคริปต์ที่ติดตั้งมา ส่วนของที่เขียนเองในเครื่องจะไว้ใน~/bin/ขอผ่าน วาง
binส่วนตัวไว้หน้าสุดของ$PATHแล้วถ้าจะอ้างถึงโปรแกรมที่ถูกบังไว้ก็ใช้/usr/binหรือ/binก็พอรายการเครื่องมือที่ปรับแต่งเองสามารถไล่ดูได้ด้วย
~/bin/[Tab]ถ้าไม่ชอบ
grepของระบบ เช่นgrepของ Solaris แล้วอยากใช้ GNUgrepที่ตัวเองชอบ ทำไมไม่แค่ปล่อยให้มันชื่อgrepไปเลย?การได้เจอไอเดียนี้เมื่อ 5 ปีก่อนช่วยจัดระเบียบคลังทริกเชลล์ของผมได้ ตอนนี้มี คำสั่งแบบจุลภาค รวมทั้ง alias และ
~/binมากกว่า 50 รายการ ทำให้ชีวิตบนเชลล์ลื่นไหลกว่าสภาพปนเปกันในอดีตมากเคยมีการถกเถียงกันในปี 2020 ด้วย: https://news.ycombinator.com/item?id=22778988 (90 ความคิดเห็น)
, macroexpandStart all of your commands with a comma (2009) - https://news.ycombinator.com/item?id=31846902 - มิถุนายน 2022 (121 ความคิดเห็น)
Start all of your commands with a comma (2009) - https://news.ycombinator.com/item?id=22778988 - เมษายน 2020 (89 ความคิดเห็น)
แล้วการใช้
'_'ล่ะ?