Pipes | คือ Unix superpower
ต่อ stdout เข้า stdin ด้วย | สร้าง workflow จากคำสั่งเล็กๆ หลายตัว grep/head/tail/sort/uniq/wc + Unix philosophy
บทที่แล้วเห็น stdout ไหลออกจากคำสั่งแล้วไปไฟล์หรือหน้าจอ บทนี้จะทำสิ่งที่ทำให้ Unix กลายเป็น superpower ของวงการ dev คือ ต่อ stdout ของคำสั่งหนึ่งเข้า stdin ของคำสั่งถัดไป ด้วยเครื่องหมายเดียว | เรียกว่า pipe
เข้าใจ pipe แล้วจะรู้สึกว่าคำสั่งเล็กๆ 5-10 ตัว ต่อกันได้ไม่รู้จบ สร้าง workflow ที่เฉพาะเจาะจงได้ในบรรทัดเดียว โดยไม่ต้องเขียน script
Pipe คืออะไร
คำสั่ง1 | คำสั่ง2 แปลตรงตัวคือ “รันคำสั่ง1 แล้วเอา stdout ของมันไปเป็น stdin ให้คำสั่ง2” ทำต่อเป็น chain ได้ไม่จำกัด
$ ls | grep .ts | sort | head -5
# ls → grep → sort → head → output
# คำสั่งเล็ก 4 ตัวต่อกันทำงานเฉพาะเจาะจงสิ่งสำคัญที่ต้องจำ pipe ส่งเฉพาะ stdout stderr ยังไปที่ screen ปกติ ถ้าอยากให้ pipe เอา error ไปด้วย ต้องใช้ 2>&1 (จากบท 5) รวมก่อน เช่น cmd 2>&1 | less
Unix philosophy: ทำอย่างเดียวให้เก่ง
ทำไมต้องต่อหลายคำสั่งแทนที่มีคำสั่งใหญ่ตัวเดียว คำตอบคือปรัชญาที่ Unix ยึดถือมาตลอด
- แต่ละคำสั่งทำเรื่องเดียว แต่ทำให้เก่งที่สุด
- ออกแบบให้รับ text เป็น input ส่ง text เป็น output
- ต่อกันผ่าน pipe เพื่อแก้ปัญหาใหม่ๆ โดยไม่ต้องเขียน code
ผลคือ toolkit เล็กๆ 20-30 ตัว (cat, grep, sort, head, tail, wc, cut, awk, sed, tr, xargs, jq, ...) รวมกันทำได้เกือบทุกอย่างที่ต้องการ
4 เครื่องมือที่ใช้บ่อยสุดใน pipe
grep ใช้กรองบรรทัดที่ match pattern
$ cat app.log | grep ERROR # เฉพาะ error
$ cat app.log | grep -i error # case-insensitive
$ cat app.log | grep -v INFO # กลับด้าน (ไม่มี INFO)
$ grep -r TODO src/ # ค้นทั้ง folder แบบ recursivehead / tail ใช้ดูบรรทัดแรกหรือบรรทัดสุดท้าย
$ cat big.log | head -20 # 20 บรรทัดแรก
$ cat big.log | tail -20 # 20 บรรทัดสุดท้าย
$ tail -f server.log # ดู log real-time (follow)sort / uniq ใช้เรียงและลบบรรทัดซ้ำ
$ cat names.txt | sort # เรียง alphabetical
$ cat names.txt | sort | uniq # ลบซ้ำ (ต้อง sort ก่อน)
$ cat names.txt | sort | uniq -c # นับจำนวนว่าแต่ละตัวซ้ำกี่ครั้งwc ใช้นับบรรทัด คำ หรือตัวอักษร (count)
$ cat file.txt | wc -l # นับบรรทัด
$ cat file.txt | wc -w # นับคำ
$ ls | wc -l # นับไฟล์ใน folderลองสร้าง pipeline ดู
Widget ข้างล่างจำลอง pipeline จริง เลือก preset ดูว่าข้อมูลไหลผ่านแต่ละ stage แล้วถูก filter/transform เหลือเท่าไหร่ สังเกต line count ที่แต่ละ stage จะเห็นได้ชัดว่าข้อมูลลดลงเรื่อยๆ จนเหลือแค่ที่ต้องการ
Pattern ที่เจอบ่อยในชีวิตจริง
# หา process ที่ใช้ port ไหน
$ lsof -i :3000 | grep LISTEN
# นับจำนวน error ใน log วันนี้
$ cat today.log | grep ERROR | wc -l
# ดู process ทั้งหมดของตัวเอง เรียงจาก memory เยอะสุด
$ ps aux | grep $USER | sort -k 4 -rn | head -10
# ดู commit ของตัวเองเดือนนี้
$ git log --author=$USER --since="1 month ago" | grep "^commit" | wc -l
# ดู history เก่าๆ เอาเฉพาะ git command
$ history | grep git | tail -20สรุป
|ต่อ stdout ของคำสั่งซ้ายเข้า stdin ของคำสั่งขวา- Unix philosophy: คำสั่งเล็กทำอย่างเดียวให้เก่ง ต่อ pipe เพื่อแก้ปัญหาใหญ่
- 4 เครื่องมือยอดฮิต:
grep,head/tail,sort/uniq,wc - pipe ส่งเฉพาะ stdout stderr ยังไปหน้าจอ ถ้าอยากรวมใช้
2>&1ก่อน teeแยกเก็บเป็นไฟล์พร้อมส่งต่อ,xargsแปลง stdin เป็น argument
ต่อคำสั่งเป็น chain ได้แล้ว แต่จะเกิดอะไรถ้าคำสั่งที่รัน ไม่จบ (เช่น dev server ที่ listen ตลอด) หรือค้าง หรือใช้ port 3000 ซ้ำกับอีกอัน บทต่อไปจะเรียนเรื่อง processes การคุมคำสั่งที่รันอยู่ Ctrl+C / Ctrl+Z หา process ที่ใช้ port และจัดการ background jobs