Linux command line ฉบับมือใหม่: 9 บทเรียนตั้งแต่เปิดเทอร์มินัลจนต่อท่อคำสั่งเป็น
Linux command line ดูเหมือนเป็นหน้าจอดำว่างเปล่าจนไม่รู้จะเริ่มตรงไหน แต่จริง ๆ แล้วมีไวยากรณ์สั้น ๆ แค่ชุดเดียว ไล่ครบ 9 บทเรียนตั้งแต่ pwd, ls, cd ไปจนถึง redirection กับ pipeline แล้วจะใช้เทอร์มินัลได้จริงโดยไม่ต้องท่องจำทั้งหมด

เปิดเทอร์มินัลบน Linux ครั้งแรก สิ่งที่เจอมีแค่หน้าจอดำว่างเปล่า ข้อความสั้น ๆ อย่าง sam@ubuntu:~$ และเคอร์เซอร์กะพริบรอให้พิมพ์ คนส่วนใหญ่ค้างอยู่ตรงนี้ เพราะรู้สึกว่าต้องท่องจำคำสั่งเป็นร้อยถึงจะใช้เป็น แต่ความจริงไม่ใช่แบบนั้น หลักของ Linux command line ทั้งหมดอยู่ที่ไวยากรณ์สั้น ๆ ชุดเดียว คือ command [options] [arguments] พอมองออกว่าทุกคำสั่งอยู่ในรูปเดียวกัน คำสั่งหลายสิบตัวก็เลิกเป็นเรื่องท่องจำทันที
บทความนี้ไล่ตั้งแต่ศูนย์ ไม่ต้องมีพื้นฐาน Linux หรือ command line มาก่อน ผ่าน 9 บทเรียนที่ค่อยๆ ต่อกัน ตั้งแต่เข้าใจว่า shell คืออะไร เดินในระบบไฟล์ จัดการไฟล์และโฟลเดอร์ ไปจนถึงการต่อคำสั่งเล็กๆ หลายตัวเข้าด้วยกัน อ่านจบแล้วเปิดเทอร์มินัลทำตามได้จริงในไม่กี่นาที
หน้าจอดำที่จริงคือ shell
สิ่งที่รับคำสั่งจากเราจริง ๆ ไม่ใช่ตัวเทอร์มินัล แต่เป็นโปรแกรมข้างในที่เรียกว่า shell เทอร์มินัลเป็นแค่หน้าต่างให้เราพิมพ์ ส่วน shell เป็นคนกลางที่รับคำสั่งแล้วส่งต่อให้ระบบปฏิบัติการทำงาน ข้อความ sam@ubuntu:~$ ที่ขึ้นมาก็มีความหมายทุกตัว ชื่อก่อน @ คือ username หลัง @ คือชื่อเครื่อง เครื่องหมาย ~ แทน home directory ที่เรากำลังอยู่ และ $ คือจุดที่เริ่มพิมพ์คำสั่งได้
ลองพิมพ์คำสั่งสั้นๆ เพื่อให้คุ้นมือก่อนสักสองสามตัว
dateบอกวันและเวลาปัจจุบันของเครื่องdfบอกพื้นที่ disk ที่เหลือfreeบอก RAM ที่เหลือ (ในเครื่องตัวอย่างมีอยู่ 4 GB)exitออกจาก shell
ถ้าพิมพ์ผิดหรืออยากเรียกคำสั่งเดิมกลับมา กดลูกศรขึ้นหรือลงเพื่อเลื่อนดูประวัติคำสั่งได้เลย โดย Linux จำคำสั่งล่าสุดไว้ให้อัตโนมัติถึง 1,000 คำสั่ง
เดินในระบบไฟล์โดยไม่หลง
ระบบไฟล์ของ Linux เป็นโครงสร้างแบบต้นไม้ เริ่มจากราก (/) แล้วแตกเป็น directory ย่อยลงไปเรื่อย ๆ คำว่า directory คือสิ่งที่ Windows เรียกว่า folder เพียงแต่ใน Linux ใช้ directory เป็นคำทางการ อีกเรื่องที่ควรจำไว้ตั้งแต่ต้นคือ ใน Linux ทุกอย่างถือเป็นไฟล์ แม้แต่ directory เองก็เป็นไฟล์ชนิดพิเศษชนิดหนึ่ง
คำสั่งหลักสำหรับเดินไปมามีไม่กี่ตัว
pwdบอก path เต็มว่าตอนนี้เราอยู่ directory ไหนlsแสดงรายการไฟล์และ directory ที่อยู่ในนั้นcd <path>ย้ายเข้าไปใน directory ที่ระบุcdเปล่าๆ กลับไป home,cd ..ขึ้นไป 1 ชั้น,cd ../..ขึ้น 2 ชั้น,cd -กลับไป directory ก่อนหน้า
เรื่อง path มีสองแบบที่ต้องแยกให้ออก แบบ absolute เริ่มนับจากราก / เสมอ ส่วนแบบ relative นับจาก directory ที่เราอยู่ตอนนั้น พอเข้าใจสองแบบนี้ก็ไปที่ไหนก็ได้ในระบบ
อยากลองของจริงเลย ให้เปิดเทอร์มินัลแล้วพิมพ์ทีละบรรทัด
pwd
ls
cd ..
ls
สี่บรรทัดนี้คือการถามว่าตอนนี้อยู่ตรงไหน มีอะไรอยู่รอบตัว แล้วขยับขึ้นไปอีกหนึ่งชั้นเพื่อดูว่าข้างบนมีอะไร เท่านี้ก็เริ่มเดินในระบบไฟล์เป็นแล้ว
อ่านระบบให้ออกด้วย ls -l

คำสั่งเกือบทุกตัวรับ options เพื่อปรับว่าจะให้ทำงานแบบไหน และนี่คือที่มาของไวยากรณ์ command [options] [arguments] ที่พูดถึงตั้งแต่ต้น ตัว ls เห็นภาพชัดที่สุด
ls -lแสดงแบบ long format เห็นทั้ง permissions เจ้าของ ขนาด และวันที่ครบในบรรทัดเดียวls -aแสดงไฟล์ซ่อนด้วย คือไฟล์ที่ขึ้นต้นด้วยจุด.- รวม options เข้าด้วยกันได้
ls -laมีค่าเท่ากับls -l -a ls -rเป็น option แบบสั้นของls --reverse
เพราะ Linux ไม่บังคับให้ไฟล์มีนามสกุล เราจึงเดาประเภทไฟล์จากชื่อไม่ได้เสมอไป ทางที่ชัวร์กว่าคือพิมพ์ file <ชื่อไฟล์> ให้ระบบบอกประเภทจริงออกมา ส่วนถ้าจะเปิดอ่านไฟล์ข้อความยาว ๆ ให้ใช้ less <ชื่อไฟล์> แล้วเลื่อนด้วย Enter ทีละบรรทัดหรือ Space ทีละหน้า กด q เพื่อออก
มีจุดสังเกตหนึ่งใน ls -l ที่จะโยงไปหัวข้อถัดไป ถ้าเห็นบรรทัดที่ permission ขึ้นต้นด้วยตัว l แล้วมีลูกศร -> ชี้ไปอีกไฟล์ นั่นคือ symbolic link ที่เดี๋ยวจะอธิบายให้เห็นภาพ
สร้าง คัดลอก ย้าย ลบ ในที่เดียว
พอเดินเป็นแล้ว ขั้นต่อไปคือลงมือจัดการไฟล์จริงๆ ชุดคำสั่งหลักมีดังนี้
mkdir <ชื่อ>สร้าง directory ใหม่ และสร้างทีเดียวหลายอันได้ด้วยmkdir dir1 dir2touch <ชื่อไฟล์>สร้างไฟล์เปล่าขึ้นมาcp <ต้นทาง> <ปลายทาง>คัดลอกไฟล์ ถ้าเติม-rจะคัดลอกทั้ง directory,-iถามก่อนเขียนทับ,-vบอกว่าคัดลอกจากไหนไปไหนmv <ต้นทาง> <ปลายทาง>ย้ายไฟล์ และถ้าปลายทางไม่ใช่ directory ที่มีอยู่แล้ว มันจะกลายเป็นการเปลี่ยนชื่อไฟล์แทนrm <ไฟล์>ลบไฟล์,rm -r <directory>ลบทั้ง directory,rm -iถามก่อนลบทีละไฟล์
ตัวช่วยที่ทำให้คำสั่งพวกนี้ทรงพลังคือ wildcard เครื่องหมาย * แทนอักขระกี่ตัวก็ได้ ใช้ได้กับแทบทุกคำสั่ง เช่น rm *.html ลบไฟล์ HTML ทั้งหมดรวดเดียว
ทางลัดของไฟล์มีให้เลือกสองแบบ
บางครั้งเราอยากให้ไฟล์เดียวกันเข้าถึงได้จากหลายที่ โดยไม่ต้องคัดลอกซ้ำให้เปลืองพื้นที่ Linux ทำเรื่องนี้ได้ด้วย link สองแบบที่ทำงานต่างกัน
แบบแรกคือ hard link สร้างด้วย ln <ไฟล์> <ชื่อลิงก์> มันชี้ไปที่ข้อมูลก้อนเดียวกันบน disk และมี inode number เดียวกันกับไฟล์ต้นฉบับ ต่อให้ลบไฟล์ต้นฉบับไป ก็ยังเข้าถึงข้อมูลผ่านลิงก์ได้ ตรวจได้ด้วย ls -li โดยลิงก์ที่ชี้ข้อมูลก้อนเดียวกันจะมี inode number ตรงกัน
แบบที่สองคือ symbolic link หรือ soft link สร้างด้วย ln -s <ไฟล์> <ชื่อลิงก์> ตัวนี้เหมือนทางลัดที่ชี้ไปยังไฟล์อีกไฟล์ ใช้พื้นที่น้อยมาก ในตัวอย่างที่สาธิตกินแค่ 3 bytes แต่ข้อแลกเปลี่ยนคือ ถ้าลบไฟล์ต้นฉบับ ลิงก์จะพังทันทีและขึ้นเป็นสีแดง
จะเลือกแบบไหน ให้ดูว่าอยากให้ลิงก์อยู่รอดเมื่อไฟล์ต้นฉบับหายไหม ถ้าต้องการแค่ทางลัดที่ชี้ไปยังไฟล์อื่นและเปลี่ยนปลายทางได้ง่าย symbolic link ตอบโจทย์กว่า ตัวอย่างจริงในเครื่องคือ python3 -> python3.10 ที่อยู่ใน /usr/bin เวลาอัปเกรดเป็น Python 3.11 ก็แค่เปลี่ยนปลายทางของ symlink ทุก script ที่เรียก python3 จะใช้เวอร์ชันใหม่ทันที โดยไม่ต้องไล่แก้ทีละไฟล์
คำว่า "คำสั่ง" มีตั้งสี่ชนิด
สิ่งที่เราพิมพ์แล้วเรียกรวม ๆ ว่า "คำสั่ง" จริง ๆ แล้วมี 4 ชนิด ได้แก่ โปรแกรมที่รันได้ (executable), คำสั่งที่ฝังมากับ shell (built-in), ฟังก์ชันของ shell และ alias หรือชื่อย่อที่เราตั้งขึ้นเอง การรู้ว่าตัวไหนเป็นชนิดไหนช่วยให้เข้าใจว่า ทำไมบางคำสั่งถึงหา path ไม่เจอ
type <คำสั่ง>บอกว่าคำสั่งนั้นเป็นชนิดไหน เช่นlsมักเป็น alias ส่วนcdเป็น built-inwhich <คำสั่ง>บอก path ของโปรแกรม แต่ใช้ได้เฉพาะกับ executableman <คำสั่ง>เปิดคู่มือเต็มของคำสั่งนั้น ดู option ได้ครบ กดqเพื่อออกwhatis <คำสั่ง>สรุปหน้าที่ของคำสั่งให้เป็นบรรทัดเดียว
คู่มือพวกนี้เขียนกันจริงจัง แต่ก็แอบมีอารมณ์ขัน ลองพิมพ์ man git ดู มันบรรยาย git ไว้ว่าเป็น "the stupid content tracker" ซึ่งเป็นข้อความจริงในคู่มือ ไม่ได้ยกตัวอย่างสมมติ
ถ้ามีคำสั่งยาว ๆ ที่พิมพ์บ่อย ตั้ง alias ไว้ได้ด้วย alias ชื่อย่อ='คำสั่ง' ถ้าจะใส่หลายคำสั่งใน alias เดียว ให้คั่นด้วย ; ลบทิ้งด้วย unalias ชื่อย่อ หรือพิมพ์ alias เปล่า ๆ เพื่อดูที่ตั้งไว้ทั้งหมด แต่มีกับดักหนึ่งที่ต้องรู้ คือ alias ที่ตั้งในเทอร์มินัลจะหายไปเมื่อปิดหน้าต่าง ถ้าอยากให้อยู่ถาวรต้องบันทึกลงไฟล์ตั้งค่า ซึ่งเป็นเรื่องที่สอนในบทถัดไป เนื้อหาทั้งหมดนี้เป็นบทเริ่มต้นชุดแรกของ คอร์ส Linux ฉบับเต็ม จากช่อง Keep On Coding ที่ยังมีเรื่อง permissions, processes และ environment ต่อกันอีกหลายบท
ส่งผลลัพธ์ไปเก็บไว้ที่อื่น
ปกติคำสั่งจะรับ input จากคีย์บอร์ดแล้วพ่นผลลัพธ์ออกหน้าจอ แต่เราเปลี่ยนทางเข้าและทางออกพวกนี้ได้ Linux แยกช่องทางเหล่านี้เป็นตัวเลข stdin (0) คือทางเข้าจากคีย์บอร์ด, stdout (1) คือผลลัพธ์ปกติที่ออกจอ, stderr (2) คือข้อความ error ที่แยกจากผลลัพธ์ปกติ
>ส่ง stdout ไปเขียนลงไฟล์ โดยเขียนทับของเดิม>>ส่ง stdout ไปต่อท้ายไฟล์ ไม่ลบของเดิม2>ส่งเฉพาะ error ลงไฟล์&>ส่งทั้งผลลัพธ์ปกติและ error ลงไฟล์เดียวกัน ส่วน&>>คือต่อท้ายทั้งคู่<สั่งให้คำสั่งรับ input จากไฟล์แทนคีย์บอร์ด
คำสั่งคู่หูของเรื่องนี้คือ cat <ไฟล์> ที่อ่านไฟล์แล้วพ่นไปที่ stdout และถ้าพิมพ์ cat เปล่า ๆ มันจะรอรับสิ่งที่เราพิมพ์ไปเรื่อย ๆ จนกว่าจะกด Ctrl+D จุดที่ต้องระวังคือ > จะเขียนทับไฟล์ทันทีแม้คำสั่งจะล้มเหลว ไฟล์เดิมจึงอาจเหลือ 0 bytes โดยที่เราไม่ทันตั้งตัว
ต่อท่อคำสั่งเล็กๆ เข้าด้วยกัน

พลังจริงของ command line ไม่ได้มาจากคำสั่งตัวใหญ่ตัวเดียว แต่มาจากการเอาคำสั่งเล็ก ๆ มาต่อกัน เครื่องหมาย | (pipe) จะส่ง stdout ของคำสั่งทางซ้ายไปเป็น stdin ของคำสั่งทางขวา และต่อกันกี่ขั้นก็ได้
cat file1 file2 | sort | uniq | less
บรรทัดเดียวนี้รวมสองไฟล์เข้าด้วยกัน เรียงบรรทัดใหม่ ตัดบรรทัดซ้ำออก แล้วเปิดอ่านแบบเลื่อนทีละหน้า เครื่องมือเล็กๆ ที่หยิบมาต่อท่อบ่อยมีไม่กี่ตัว
sortเรียงลำดับ input ที่รับเข้ามาuniqตัดบรรทัดที่ซ้ำติดกันออก (ต้องsortก่อนถึงจะได้ผล) ส่วนuniq -dโชว์เฉพาะบรรทัดที่ซ้ำgrep <pattern> <ไฟล์>คัดเฉพาะบรรทัดที่ตรงกับรูปแบบที่ระบุheadกับtailดึง 10 บรรทัดแรกและ 10 บรรทัดสุดท้าย ระบุจำนวนเองได้ด้วย-nเช่นhead -n 3tee <ไฟล์>ส่งผลลัพธ์ออกจอและบันทึกลงไฟล์ไปพร้อมกัน
เบื้องหลังที่ shell จัดการให้ก่อน
ก่อน shell จะส่งคำสั่งไปทำงานจริง มันจะ "ขยาย" (expansion) บางอย่างให้ก่อนเงียบๆ คำสั่ง echo <ข้อความ> ที่แค่พิมพ์ข้อความออกมา เหมาะมากสำหรับลองดูว่า shell ขยายอะไรให้บ้าง
- wildcard
*ขยายเป็นชื่อไฟล์ที่ตรงรูปแบบ - tilde
~ขยายเป็น path ของ home directory - arithmetic
$((2+2))คำนวณเลขให้ ใช้ตัวดำเนินการ+-*/%และ**สำหรับยกกำลัง - parameter
$USERแทนค่าตัวแปร เช่นชื่อผู้ใช้ปัจจุบัน - command substitution
$(ls)เอาผลลัพธ์ของคำสั่งมาวางตรงนั้น (รูปแบบเก่าใช้ backtick ครอบแทน)
อยากเห็นตัวแปรสภาพแวดล้อมทั้งหมดในเครื่อง พิมพ์ printenv | less ก็ไล่ดูได้สบายๆ
พอ shell ขยายให้เองอัตโนมัติ บางครั้งเราก็ต้องสั่งไม่ให้มันขยาย นั่นคือหน้าที่ของ quoting การครอบด้วย double quotes "..." จะกันการตัดคำและการขยาย wildcard แต่ยังปล่อยให้ตัวแปร การคำนวณ และ command substitution ทำงานอยู่ ส่วน backslash \ ใช้ escape อักขระตัวถัดไปทีละตัว เช่น \$ เพื่อสั่งไม่ให้ขยายตัวแปร เรื่องที่เจอบ่อยสุดคือชื่อไฟล์ที่มีช่องว่าง ถ้าไม่ครอบด้วย quotes ระบบจะอ่านเป็นหลายไฟล์ ทางที่ง่ายกว่าคือเลี่ยงช่องว่างไปเลย แล้วตั้งชื่อโดยใช้ _ แทน
ไม่ได้จำเยอะ แค่เห็นว่าทุกอย่างต่อกันได้
นับดูจริง ๆ คำสั่งทั้งหมดในบทความนี้มีไม่ถึงสี่สิบตัว และเกือบทั้งหมดอยู่ในรูป command [options] [arguments] เดียวกัน สิ่งที่ทำให้ command line ทรงพลังจึงไม่ใช่จำนวนคำสั่งที่จำได้ แต่คือการที่คำสั่งเล็ก ๆ เหล่านี้ต่อกันได้ จะ pipe ผลของตัวหนึ่งเข้าอีกตัว redirect ลงไฟล์ หรือมัดเป็น alias ไว้ใช้ซ้ำก็ได้ ยิ่งมองมันเป็นชิ้นเล็ก ๆ ที่หยิบมาประกอบกันได้เท่าไร สิ่งที่เราสั่งให้เครื่องทำก็ยิ่งใหญ่ขึ้นเท่านั้น
ที่มา: คลิป Linux Command Line for Beginners จากช่อง Keep On Coding



