/static/codemoomoo2.png

3. Basic Linux Commandline

บทนี้มุ่งปูพื้นฐานการใช้งาน บรรทัดคำสั่ง (Command Line Interface, CLI) บนระบบปฏิบัติการ Linux อย่างเป็นระบบ ตั้งแต่แนวคิดของ Shell, การเคลื่อนที่ในระบบไฟล์, การจัดการไฟล์และโพรเซส ไปจนถึงการประมวลผลข้อความด้วย Pipeline เพื่อให้ผู้เรียนสามารถทำงานบนเซิร์ฟเวอร์ที่ไม่มี GUI ได้อย่างมั่นใจและมีประสิทธิภาพ


3.1 พื้นฐาน Shell และ Terminal

Shell คือโปรแกรมตัวแปลคำสั่ง (Command Interpreter) ที่ทำหน้าที่รับคำสั่งจากผู้ใช้ แล้วแปลและส่งต่อให้ Kernel ประมวลผล ส่วน Terminal คือหน้าต่างหรืออุปกรณ์ที่ใช้ป้อนคำสั่งและแสดงผล การเข้าใจความแตกต่างและความสัมพันธ์ของสิ่งเหล่านี้เป็นรากฐานสำคัญก่อนจะลงมือใช้งานคำสั่งใด ๆ

3.1.1 Terminal Emulator vs Shell vs Console vs TTY

สี่คำนี้มักถูกใช้สลับกันในภาษาพูด แต่แท้จริงหมายถึงสิ่งที่แตกต่างกัน:

ลำดับชั้นการทำงาน:

flowchart LR
    U[User / ผู้ใช้] -->|keystroke| TE[Terminal Emulator
เช่น Alacritty, Kitty] TE -->|pty| TTY[TTY Device
/dev/pts/0] TTY -->|stdin| SH[Shell
bash / zsh / fish] SH -->|fork exec| K[Kernel
Linux Kernel] K -->|stdout| TTY TTY -->|pixel| TE TE --> U style U fill:#458588,stroke:#83a598,color:#fbf1c7 style TE fill:#689d6a,stroke:#8ec07c,color:#fbf1c7 style TTY fill:#d79921,stroke:#fabd2f,color:#282828 style SH fill:#b16286,stroke:#d3869b,color:#fbf1c7 style K fill:#cc241d,stroke:#fb4934,color:#fbf1c7

3.1.2 ประเภทของ Shell: bash, zsh, fish, dash, ksh

Shell แต่ละชนิดมีปรัชญาและความสามารถต่างกัน ผู้ใช้ Linux ควรรู้จักทางเลือกเพื่อเลือกใช้ให้เหมาะสม:

Shell ปีที่ออก จุดเด่น จุดด้อย
sh (Bourne Shell) 1977 ต้นแบบ POSIX Shell, เล็ก, พกพาได้ ฟีเจอร์น้อยมาก
bash 1989 มาตรฐานของ Linux ส่วนใหญ่, เข้ากันได้กับ sh Scripting ช้ากว่าบางตัว
zsh 1990 Auto-completion ทรงพลัง, Plugin (Oh My Zsh, Prezto) กำหนดค่าซับซ้อน
fish 2005 User-friendly, Syntax highlight ในตัว, Auto-suggestion ไม่เข้ากับ POSIX 100%
dash 2002 เล็กและเร็ว, ใช้รัน /bin/sh บน Debian/Ubuntu ไม่มี interactive features
ksh (Korn Shell) 1983 ต้นแบบของ bash หลายฟีเจอร์, นิยมบน AIX/Solaris ใน Linux ไม่ค่อยใช้

ตรวจสอบ Shell ที่ใช้อยู่และรายการ Shell ที่ระบบอนุญาต:

# ดู Shell ปัจจุบันของผู้ใช้
echo $SHELL                    # แสดงค่า environment variable
echo $0                        # แสดงชื่อของ shell ที่รันอยู่จริง

# ดูรายการ shell ที่ระบบอนุญาตให้ใช้เป็น login shell
cat /etc/shells

# เปลี่ยน default shell ของผู้ใช้ปัจจุบันเป็น zsh
chsh -s /usr/bin/zsh           # ต้องใส่รหัสผ่าน, effect เมื่อ login ใหม่

# ตัวอย่างผลลัพธ์จาก cat /etc/shells:
# /bin/sh
# /bin/bash
# /usr/bin/zsh
# /usr/bin/fish

3.1.3 Prompt, Environment (PS1, PS2)

Prompt คือข้อความที่ Shell แสดงเพื่อรอรับคำสั่ง ค่านี้ควบคุมผ่านตัวแปร PS1 (Primary Prompt) และ PS2 (Secondary Prompt สำหรับคำสั่งหลายบรรทัด)

ตัวอย่างการปรับแต่ง Prompt ใน bash:

# ดูค่า PS1 ปัจจุบัน
echo "$PS1"

# เปลี่ยน PS1 ให้แสดง user@host:path$ แบบมีสี
# \u = username, \h = hostname, \w = current working directory, \$ = # หรือ $
# \[\e[32m\] = เริ่มสีเขียว, \[\e[0m\] = คืนสีเดิม
export PS1='\[\e[32m\]\u@\h\[\e[0m\]:\[\e[34m\]\w\[\e[0m\]\$ '

# PS2 ใช้เมื่อคำสั่งยังไม่จบ (เช่น เปิด quote ค้าง)
export PS2='→ '

# ทดสอบ PS2 โดยพิมพ์ quote ค้าง:
echo "hello
# จะเห็นสัญลักษณ์ → รอให้พิมพ์ต่อ
world"

หากต้องการให้ค่าคงอยู่ถาวร ให้ใส่บรรทัด export PS1='...' ลงในไฟล์ ~/.bashrc (สำหรับ bash) หรือ ~/.zshrc (สำหรับ zsh)

3.1.4 Command History (history, !!, !n, Ctrl+R)

Shell บันทึกคำสั่งทั้งหมดที่พิมพ์ไว้ในไฟล์ ~/.bash_history (bash) หรือ ~/.zsh_history (zsh) เพื่อให้เรียกใช้ซ้ำได้

# ดูประวัติคำสั่งทั้งหมด (มีเลขลำดับกำกับ)
history

# ดู 10 คำสั่งล่าสุด
history 10

# รันคำสั่งล่าสุดซ้ำ
!!

# รันคำสั่งลำดับที่ 125 จากประวัติ
!125

# รันคำสั่งล่าสุดที่ขึ้นต้นด้วย "git"
!git

# รันคำสั่งล่าสุดที่มีคำว่า "docker" อยู่ตรงไหนก็ได้
!?docker

# แทนที่ข้อความในคำสั่งก่อนหน้า: ถ้าเพิ่งพิมพ์ "ls /etc" แล้วพิมพ์:
^etc^home          # จะรัน "ls /home" ทันที

# ค้นหาย้อนหลังแบบ Incremental Search
# กด Ctrl+R แล้วพิมพ์คำบางส่วน เช่น "dock" → จะโผล่คำสั่ง docker ที่เคยใช้
# กด Ctrl+R ซ้ำ เพื่อหาอันที่เก่ากว่า
# กด Enter เพื่อรัน หรือ Esc/ลูกศรเพื่อแก้ไขก่อนรัน

# ล้างประวัติทั้งหมด (ใช้เมื่อเผลอพิมพ์รหัสผ่านลงไป)
history -c && history -w

# ป้องกันไม่ให้คำสั่งที่ขึ้นต้นด้วยช่องว่างถูกบันทึก (ใช้ใน ~/.bashrc)
export HISTCONTROL=ignorespace:ignoredups
export HISTSIZE=10000
export HISTFILESIZE=20000

3.1.5 Tab Completion

การกด Tab ให้ Shell เดาและเติมคำให้อัตโนมัติ เป็นฟีเจอร์ที่ประหยัดเวลาที่สุดของ Command Line

ตัวอย่าง:

# พิมพ์แค่ "cd /etc/net" แล้วกด Tab → จะกลายเป็น "cd /etc/network/" (ถ้ามี)
cd /etc/net<TAB>

# พิมพ์ "sudo apt install fire" แล้วกด Tab 2 ครั้ง
# จะแสดง: firefox, firefox-esr, firejail, firewalld

# bash-completion ช่วยให้เติมได้ลึกขึ้น เช่น
git che<TAB>        # → git checkout
git checkout <TAB><TAB>   # → แสดง branch ทั้งหมดในโปรเจกต์
systemctl status ng<TAB>  # → nginx.service

การติดตั้ง bash-completion (บน Ubuntu/Debian):

sudo apt install bash-completion
# เพิ่มใน ~/.bashrc (ถ้ายังไม่มี)
# [ -f /etc/bash_completion ] && . /etc/bash_completion

3.1.6 Keyboard Shortcut

คีย์ลัดของ Shell (โดยเฉพาะ Readline ที่ bash ใช้) ช่วยให้การพิมพ์คำสั่งเร็วขึ้นมาก:

Shortcut หน้าที่
Ctrl+C ส่ง SIGINT ยกเลิกคำสั่งที่กำลังรัน
Ctrl+Z ส่ง SIGTSTP หยุด (suspend) คำสั่งไว้ชั่วคราว
Ctrl+D ส่ง EOF ปิด stdin / logout จาก shell
Ctrl+L ล้างหน้าจอ (เท่ากับคำสั่ง clear)
Ctrl+A เลื่อน cursor ไปหัวบรรทัด
Ctrl+E เลื่อน cursor ไปท้ายบรรทัด
Ctrl+U ลบข้อความจาก cursor ย้อนไปหัวบรรทัด
Ctrl+K ลบข้อความจาก cursor ไปจนท้ายบรรทัด
Ctrl+W ลบคำที่อยู่ก่อน cursor
Ctrl+Y วางข้อความที่ลบล่าสุด (Yank)
Ctrl+R ค้นหาประวัติคำสั่งย้อนหลัง
Alt+B / Alt+F ย้าย cursor ทีละคำ (ย้อน/ไปข้างหน้า)
Alt+. แทรกอาร์กิวเมนต์สุดท้ายของคำสั่งก่อนหน้า

3.2 การเคลื่อนที่และสำรวจระบบไฟล์

ระบบไฟล์ของ Linux เป็นโครงสร้างต้นไม้ (Tree) ที่มีรากเดียวคือ / ทุกอุปกรณ์และทุกพาร์ทิชันจะถูก "mount" เข้ามาเป็นสาขาของต้นไม้นี้ การเคลื่อนที่ให้คล่องเป็นทักษะพื้นฐานที่ต้องทำให้เป็นอัตโนมัติ

3.2.1 pwd, cd (รวม cd -, cd ~)

# แสดงตำแหน่งปัจจุบัน (Print Working Directory)
pwd
# ตัวอย่างผลลัพธ์: /home/moo/projects

# เข้าไปในไดเรกทอรี
cd /var/log

# กลับไปที่ home ของผู้ใช้ (สามเท่ากัน)
cd
cd ~
cd $HOME

# กลับไปที่ไดเรกทอรี "ก่อนหน้า" ที่เพิ่งอยู่ (เหมือนปุ่ม Back)
cd -

# ขึ้นหนึ่งชั้น / สองชั้น
cd ..
cd ../..

# เข้า home ของผู้ใช้อื่น
cd ~moo          # เท่ากับ /home/moo
cd ~root         # เท่ากับ /root

# ตัวอย่างการสลับไปมาระหว่าง 2 โฟลเดอร์
cd /etc/nginx
cd /var/log/nginx
cd -             # กลับ /etc/nginx
cd -             # กลับ /var/log/nginx

3.2.2 ls พร้อม option -l, -a, -h, -R, -t, -S

คำสั่ง ls มี option มากมาย แต่ที่ใช้บ่อยคือ:

ls              # แสดงรายชื่อพื้นฐาน
ls -l           # แสดงแบบ long listing (สิทธิ์, เจ้าของ, ขนาด, วันที่)
ls -a           # แสดงไฟล์ที่ขึ้นต้นด้วย . ด้วย (hidden file)
ls -h           # แสดงขนาดในหน่วย human-readable (K, M, G)
ls -R           # แสดงแบบ recursive (เข้าลึกทุกโฟลเดอร์)
ls -t           # เรียงตามเวลา modify (ล่าสุดก่อน)
ls -S           # เรียงตามขนาด (ใหญ่ก่อน)
ls -r           # กลับลำดับการเรียง (reverse)

# รวม option ยอดนิยม
ls -lah         # รายละเอียดเต็ม + hidden + human-readable size
ls -lhtr        # เรียงจากเก่าไปใหม่ (ล่าสุดอยู่ล่างสุด - เห็นง่ายบน terminal)
ls -lhS /var/log   # ดูไฟล์ log เรียงตามขนาด

# ใช้ alias ทำให้พิมพ์สั้น (ใส่ใน ~/.bashrc)
alias ll='ls -lah'
alias la='ls -A'
alias l='ls -CF'

ตัวอย่างผลลัพธ์ ls -lah และความหมาย:

drwxr-xr-x  3 moo  moo   4.0K Oct 15 14:32 projects/
-rw-r--r--  1 moo  moo    1.2K Oct 14 09:10 notes.md
-rwxr-xr-x  1 root root    15K Sep  1 2024  backup.sh

แต่ละคอลัมน์:

  1. ประเภท+สิทธิ์ (d=dir, -=file, l=symlink)
  2. จำนวน hard link
  3. เจ้าของ (user)
  4. กลุ่ม (group)
  5. ขนาดไฟล์
  6. วันที่ modify
  7. ชื่อไฟล์

3.2.3 tree

คำสั่ง tree แสดงโครงสร้างไดเรกทอรีแบบต้นไม้ที่อ่านง่ายมาก ต้องติดตั้งเพิ่ม:

# ติดตั้ง
sudo apt install tree           # Debian/Ubuntu
sudo pacman -S tree             # Arch
sudo dnf install tree           # Fedora/RHEL

# แสดงโครงสร้างทั้งหมดของโฟลเดอร์ปัจจุบัน
tree

# จำกัดความลึก 2 ชั้น
tree -L 2

# แสดงเฉพาะไดเรกทอรี (ไม่แสดงไฟล์)
tree -d

# แสดง hidden file ด้วย
tree -a

# รวมออปชันที่ใช้บ่อยสุด: ลึก 3 ชั้น + ขนาด human-readable
tree -L 3 -h /etc/nginx

# ตัวอย่าง output:
# .
# ├── app.py
# ├── requirements.txt
# └── tests
#     ├── test_api.py
#     └── test_db.py

3.2.4 Path แบบ Absolute vs Relative

สัญลักษณ์สำคัญ:

# ถ้าอยู่ที่ /home/moo/projects/ai-course
pwd                             # → /home/moo/projects/ai-course

cat ./lecture01.md              # = /home/moo/projects/ai-course/lecture01.md
cat ../ml-course/syllabus.md    # = /home/moo/projects/ml-course/syllabus.md
cat ~/notes.md                  # = /home/moo/notes.md
cat /etc/hostname               # absolute, ใช้ได้จากทุกที่

3.2.5 Wildcards/Globbing

Globbing คือการให้ Shell ขยาย (expand) สัญลักษณ์พิเศษให้เป็นรายชื่อไฟล์จริงก่อนส่งให้คำสั่ง

Pattern ความหมาย ตัวอย่าง
* ตัวอักษรใด ๆ กี่ตัวก็ได้ (รวมว่าง) *.txt → ไฟล์ .txt ทั้งหมด
? ตัวอักษรใด ๆ หนึ่งตัว file?.log → file1.log, fileA.log
[abc] ตัวใดตัวหนึ่งใน set [aeiou]*.md → ไฟล์ .md ที่ขึ้นต้นด้วยสระ
[a-z] ช่วงตัวอักษร img[0-9].png
[!abc] ไม่ใช่ตัวใน set (negate) [!._]* → ไม่ขึ้นต้นด้วย . หรือ _
{a,b,c} Brace Expansion file.{jpg,png,gif}
# ลบไฟล์ .log ทั้งหมด
rm *.log

# คัดลอกไฟล์ที่ขึ้นต้นด้วย "report" ตามด้วยเลข 3 หลัก
cp report???.pdf /backup/

# ย้ายไฟล์ภาพทุกประเภทไปโฟลเดอร์ images
mv *.{jpg,jpeg,png,gif,webp} ./images/

# เปิดใช้ globstar เพื่อให้ ** หมายถึง recursive (bash 4+)
shopt -s globstar
ls **/*.py          # ไฟล์ .py ทุกไฟล์ในทุกชั้นย่อย

3.2.6 Brace Expansion

Brace Expansion ไม่ใช่ glob แท้ (ไม่ต้องมีไฟล์จริงอยู่) แต่เป็นการสร้างสตริงหลายชุดพร้อมกัน:

# สร้างโฟลเดอร์หลายอันพร้อมกัน
mkdir -p project/{src,tests,docs,config}
# ได้: project/src, project/tests, project/docs, project/config

# สร้างโครงสร้างซ้อนกัน
mkdir -p course/{ai,ml,netsec}/{lectures,labs,quizzes}
# ได้ 9 โฟลเดอร์ย่อย

# ใช้ช่วงตัวเลข
echo {1..5}                 # → 1 2 3 4 5
echo {01..10}               # → 01 02 03 04 05 06 07 08 09 10 (zero-padded)
echo {a..e}                 # → a b c d e
echo {10..1..2}             # → 10 8 6 4 2 (step -2)

# สร้างไฟล์เปล่า 100 ไฟล์
touch log_{001..100}.txt

# ใช้คู่กับคำสั่งจริง
cp config.yml{,.bak}        # สำเนาเป็น config.yml.bak (trick ยอดฮิต)
mv document.{txt,md}        # เปลี่ยนชื่อนามสกุล

3.3 การจัดการไฟล์และไดเรกทอรี

3.3.1 touch, mkdir (-p), rmdir

# สร้างไฟล์เปล่า หรือปรับ timestamp ของไฟล์ที่มีอยู่แล้ว
touch newfile.txt
touch -t 202501011200 file.txt    # ตั้ง timestamp เอง (YYYYMMDDhhmm)
touch -r ref.txt target.txt       # ให้ timestamp เท่ากับ ref.txt

# สร้างไดเรกทอรี
mkdir logs

# -p (parents) สร้างโฟลเดอร์พ่อแม่ให้ด้วยถ้ายังไม่มี (ไม่ error หากมีอยู่แล้ว)
mkdir -p /var/www/app/public/assets/images

# รวมหลายโฟลเดอร์พร้อม brace expansion
mkdir -p lab-{01..10}/{code,data,report}

# ลบไดเรกทอรี (ต้องว่างเท่านั้น)
rmdir empty_folder
rmdir -p a/b/c     # ลบ c, b, a ถ้าทั้งหมดว่าง

3.3.2 cp, mv, rm

# ---------- cp (copy) ----------
cp source.txt dest.txt                       # คัดลอกไฟล์
cp file.txt /tmp/                            # คัดลอกไปโฟลเดอร์
cp -r src/ backup/                           # -r = recursive (สำหรับไดเรกทอรี)
cp -i file.txt dest.txt                      # -i = interactive ถามก่อนเขียนทับ
cp -p file.txt dest.txt                      # -p = preserve permissions/timestamps
cp -v *.md docs/                             # -v = verbose แสดงว่ากำลังทำอะไร
cp -rpv src/ /backup/$(date +%Y-%m-%d)/      # backup แบบครบทุก option

# ---------- mv (move / rename) ----------
mv old.txt new.txt                # เปลี่ยนชื่อ
mv file.txt ../                   # ย้ายขึ้นไปชั้นบน
mv -n source.txt dest.txt         # -n = no-clobber ไม่เขียนทับ
mv *.log archive/                 # ย้ายหลายไฟล์

# ---------- rm (remove) ----------
rm file.txt                       # ลบไฟล์
rm -r folder/                     # -r = recursive ลบโฟลเดอร์และเนื้อใน
rm -i *.bak                       # -i = ถามก่อนลบทุกไฟล์
rm -f file.txt                    # -f = force ไม่ถาม ไม่ error ถ้าไม่มีไฟล์
rm -rf node_modules/              # ลบทั้งต้น (ใช้ด้วยความระวังสูงสุด!)

# CAUTION: rm -rf / หรือ rm -rf $UNSET_VAR/* อาจลบทั้งระบบ!
# ป้องกันด้วย alias:
alias rm='rm -i'
# หรือใช้ trash-cli แทน:
sudo apt install trash-cli
trash-put file.txt                # ลบลงถังขยะ กู้คืนได้
trash-list
trash-restore
# Hard Link: ชี้ไปที่ inode เดียวกัน ลบไฟล์ต้นฉบับข้อมูลยังอยู่ตราบใดที่ยังมี link
ln original.txt hardlink.txt

# Symbolic Link (Symlink): เป็น "ทางลัด" ชี้ไปที่ path ลบต้นฉบับ link ก็พัง
ln -s /var/log/nginx/access.log nginx-log   # -s = symbolic

# ตรวจสอบ link
ls -l nginx-log
# lrwxrwxrwx 1 moo moo 23 Oct 15 nginx-log -> /var/log/nginx/access.log

# อ่านเป้าหมายของ symlink
readlink nginx-log
readlink -f nginx-log        # ตามไปจนถึงไฟล์จริง

# ลบ symlink (ไม่ใช่ไฟล์ต้นทาง!)
rm nginx-log                 # หรือ unlink nginx-log

ความแตกต่าง:

flowchart LR
    subgraph HL[Hard Link]
        HA[file.txt] --> I1[inode #1234
ข้อมูลจริง] HB[backup.txt] --> I1 end subgraph SL[Symbolic Link] SA[link.txt] -->|path string| SB[original.txt] SB --> I2[inode #5678
ข้อมูลจริง] end HL ~~~ SL style HA fill:#98971a,stroke:#b8bb26,color:#282828 style HB fill:#98971a,stroke:#b8bb26,color:#282828 style I1 fill:#d79921,stroke:#fabd2f,color:#282828 style SA fill:#458588,stroke:#83a598,color:#fbf1c7 style SB fill:#b16286,stroke:#d3869b,color:#fbf1c7 style I2 fill:#d79921,stroke:#fabd2f,color:#282828

3.3.4 stat, file, basename, dirname

# stat แสดงข้อมูล metadata ละเอียดของไฟล์
stat /etc/passwd
# แสดง inode, blocks, IO block, สิทธิ์, access/modify/change time, birth time

# file ตรวจสอบชนิดไฟล์จริง (ไม่ใช่จากนามสกุล)
file script.sh              # → Bourne-Again shell script, ASCII text executable
file image.jpg              # → JPEG image data, JFIF standard 1.01
file /usr/bin/ls            # → ELF 64-bit LSB executable, x86-64

# basename และ dirname ใช้ใน script บ่อยมาก
FILE="/home/moo/docs/report.pdf"
basename "$FILE"                # → report.pdf
basename "$FILE" .pdf           # → report (ตัดนามสกุล)
dirname  "$FILE"                # → /home/moo/docs

# ใช้ใน for loop
for f in /var/log/*.log; do
    name=$(basename "$f" .log)
    echo "Processing $name"
done

3.3.5 Hidden File

ไฟล์หรือโฟลเดอร์ที่ชื่อขึ้นต้นด้วย . จะไม่แสดงใน ls ปกติ (ต้องใช้ ls -a) ใช้เก็บไฟล์ค่าปรับแต่ง (dotfiles) เช่น .bashrc, .gitconfig, .ssh/, .config/

# ดูเฉพาะ hidden file
ls -d .*                    # หลีก ., .. ด้วย:
ls -A                       # -A คล้าย -a แต่ไม่แสดง . และ ..

# Dotfiles ที่สำคัญใน ~/
# .bashrc / .bash_profile     → bash configuration
# .zshrc                      → zsh configuration
# .profile                    → login shell env
# .gitconfig                  → git user settings
# .ssh/                       → ssh keys & config
# .config/                    → XDG-standard config directory
# .cache/                     → cached data (เคลียร์ได้)
# .local/share/               → application data

3.4 การดูและแก้ไขเนื้อหาไฟล์

3.4.1 cat, tac, nl

# cat = concatenate แสดงเนื้อไฟล์ (หรือรวมหลายไฟล์)
cat file.txt
cat file1.txt file2.txt > combined.txt          # รวมสองไฟล์

# -n แสดงเลขบรรทัด, -b แสดงเฉพาะบรรทัดที่ไม่ว่าง
cat -n script.sh
cat -b notes.md

# tac = cat กลับด้าน แสดงจากบรรทัดสุดท้าย
tac /var/log/syslog | head      # ดู log ล่าสุดก่อน

# nl เพิ่มเลขบรรทัดแบบยืดหยุ่น
nl -ba poem.txt                 # นับทุกบรรทัด
nl -bt report.md                # นับเฉพาะบรรทัดที่ไม่ว่าง (default)

ข้อควรระวัง: cat ไฟล์ binary อาจทำให้ terminal พัง แก้ด้วย reset หรือ stty sane

3.4.2 less, more

less คือ pager ที่ทรงพลัง สามารถเลื่อนขึ้นลงได้อิสระ (more ทำได้แค่เลื่อนลง)

less /var/log/syslog

# คีย์ที่ใช้ในหน้าต่าง less:
#   SPACE / f      → หน้าถัดไป
#   b              → หน้าก่อนหน้า
#   j / ↓          → บรรทัดลง
#   k / ↑          → บรรทัดขึ้น
#   g              → ไปต้นไฟล์
#   G              → ไปท้ายไฟล์
#   /pattern       → ค้นหาไปข้างหน้า
#   ?pattern       → ค้นหาย้อนหลัง
#   n / N          → ผลถัดไป / ย้อนกลับ
#   &pattern       → กรองเฉพาะบรรทัดที่ match
#   :n / :p        → ไฟล์ถัดไป / ก่อนหน้า (ถ้าเปิดหลายไฟล์)
#   F              → follow mode (เหมือน tail -f)
#   q              → ออก

# option ยอดนิยม
less -N file.txt        # แสดงเลขบรรทัด
less -R colored.log     # ตีความ ANSI color
less +F /var/log/auth.log   # เปิดใน follow mode ทันที

3.4.3 head, tail และ tail -f

head file.txt                   # แสดง 10 บรรทัดแรก (default)
head -n 20 file.txt             # 20 บรรทัดแรก
head -c 100 file.txt            # 100 byte แรก

tail file.txt                   # 10 บรรทัดสุดท้าย
tail -n 50 /var/log/syslog      # 50 บรรทัดสุดท้าย
tail -n +100 file.txt           # ตั้งแต่บรรทัดที่ 100 ถึงท้าย

# -f (follow) ดู log แบบ real-time - คำสั่งที่ sysadmin ใช้บ่อยที่สุด
tail -f /var/log/nginx/access.log

# -F เหมือน -f แต่ติดตามแม้ไฟล์ถูก rotate
tail -F /var/log/syslog

# follow หลายไฟล์พร้อมกัน
tail -f /var/log/nginx/{access,error}.log

# multitail (ติดตั้งเพิ่ม) สำหรับดู log หลายไฟล์แบบ split screen
sudo apt install multitail
multitail /var/log/syslog /var/log/auth.log

3.4.4 wc (นับ line, word, character)

wc file.txt
#  125   1823  10456 file.txt
#  ↑     ↑     ↑
#  lines words bytes

wc -l file.txt          # นับเฉพาะจำนวนบรรทัด
wc -w file.txt          # นับคำ
wc -c file.txt          # นับ byte
wc -m file.txt          # นับ character (สำคัญกับไฟล์ UTF-8 ที่มีภาษาไทย)

# ตัวอย่างการใช้จริง
ls /etc | wc -l                     # นับจำนวนไฟล์ใน /etc
cat *.py | wc -l                    # นับบรรทัดโค้ด Python ทั้งหมด
grep -c "ERROR" /var/log/syslog     # นับจำนวน ERROR (grep -c ทำงานคล้าย wc -l)

3.4.5 diff, cmp, md5sum, sha256sum

# diff เปรียบเทียบสองไฟล์ แสดงบรรทัดที่แตกต่าง
diff file1.txt file2.txt
diff -u file1.txt file2.txt             # unified format (ใช้กับ patch)
diff -r dir1/ dir2/                     # recursive เปรียบสองโฟลเดอร์

# สร้าง patch และนำไปใช้
diff -u old.c new.c > fix.patch
patch old.c < fix.patch

# cmp เปรียบเทียบ byte-by-byte (ใช้กับไฟล์ binary)
cmp file1.bin file2.bin
cmp -l file1 file2                      # แสดงทุก byte ที่ต่าง

# ตรวจสอบความสมบูรณ์ของไฟล์ด้วย hash
md5sum linux.iso
# a1b2c3...  linux.iso

sha256sum linux.iso                     # ปลอดภัยกว่า md5 ใช้บ่อยกว่าในปัจจุบัน
sha512sum linux.iso

# ตรวจสอบไฟล์ ISO กับ checksum ที่ผู้แจกจ่ายให้มา
sha256sum -c SHA256SUMS                 # -c = check
# linux.iso: OK

3.5 การประมวลผลข้อความ (Text Processing)

การประมวลผลข้อความเป็นจุดแข็งที่สุดของ Linux Shell เพราะตามปรัชญา Unix "Everything is a file" และส่วนใหญ่เป็นไฟล์ข้อความ การใช้เครื่องมือเหล่านี้ร่วมกันผ่าน pipe สามารถทำงานที่ซับซ้อนได้ในบรรทัดเดียว

3.5.1 grep, egrep, fgrep, rg (ripgrep)

grep (Global Regular Expression Print) ค้นหาบรรทัดที่ตรงกับ pattern

grep "ERROR" /var/log/syslog            # ค้นหาคำว่า ERROR
grep -i "error" file.log                # -i ไม่สนตัวพิมพ์เล็ก-ใหญ่
grep -v "DEBUG" app.log                 # -v เลือกบรรทัดที่ "ไม่" match
grep -n "TODO" *.py                     # -n แสดงเลขบรรทัด
grep -c "404" access.log                # -c นับจำนวนบรรทัดที่ match
grep -r "password" /etc/                # -r recursive ค้นหาในทุกไฟล์
grep -l "api_key" -r src/               # -l แสดงเฉพาะชื่อไฟล์
grep -A 3 "Exception" app.log           # -A แสดง 3 บรรทัดหลัง match
grep -B 2 "Exception" app.log           # -B แสดง 2 บรรทัดก่อน match
grep -C 5 "ERROR" app.log               # -C แสดง 5 บรรทัดรอบ ๆ (context)
grep -E "error|warning|fatal" app.log   # -E = extended regex (เหมือน egrep)
grep -F "a.b.c" file.txt                # -F = fixed string (ไม่ตีความ regex, เหมือน fgrep)

# ripgrep (rg) - รุ่นทันสมัย เร็วกว่า grep มาก เข้าใจ .gitignore
sudo apt install ripgrep
rg "TODO" .                     # ค้นทุกไฟล์ในโฟลเดอร์ปัจจุบัน
rg -i "warning" --type py       # เฉพาะไฟล์ Python
rg "func \w+" -o                # -o แสดงเฉพาะส่วนที่ match

3.5.2 Regular Expression (BRE, ERE, PCRE)

Regular Expression เป็นภาษาสำหรับอธิบาย pattern ข้อความ Linux รองรับ 3 รสชาติ:

Metacharacters หลัก:

Symbol ความหมาย ตัวอย่าง
. ตัวอักษรใด ๆ 1 ตัว c.t → cat, cut, c7t
* ซ้ำ 0 ครั้งขึ้นไป ab* → a, ab, abb
+ ซ้ำ 1 ครั้งขึ้นไป (ERE) ab+ → ab, abb
? มีหรือไม่มีก็ได้ (0 หรือ 1) colou?r
^ ต้นบรรทัด ^Error
$ ท้ายบรรทัด done$
[abc] a, b หรือ c [aeiou]
[^abc] ไม่ใช่ a, b, c [^0-9]
\d ตัวเลข (PCRE) \d{3}-\d{4}
\w ตัวอักษรคำ \w+@\w+
\s whitespace
` ` หรือ
() group (ab)+
{n,m} ซ้ำ n ถึง m ครั้ง a{2,4}

ตัวอย่าง:

# ค้นหา IP Address
grep -E '[0-9]{1,3}(\.[0-9]{1,3}){3}' access.log

# ค้นหา email (อย่างง่าย)
grep -E '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}' contacts.txt

# ค้นหา HTTP response code 4xx หรือ 5xx ใน access log
grep -E ' (4|5)[0-9]{2} ' access.log

# ค้นหาบรรทัดที่ขึ้นต้นด้วย # (comment)
grep '^#' config.txt

# ค้นหาบรรทัดว่าง
grep -n '^$' file.txt

3.5.3 sed (Stream Editor)

sed เป็น editor ที่ทำงานกับ stream ข้อความ ทีละบรรทัด เหมาะกับ find-replace อัตโนมัติ

# แทนที่ครั้งแรกในแต่ละบรรทัด (print ออกเฉย ๆ)
sed 's/foo/bar/' file.txt

# แทนที่ทั้งหมด (g = global)
sed 's/foo/bar/g' file.txt

# แก้ไขไฟล์จริง (-i = in-place)  ระวัง! ไม่มี undo
sed -i 's/foo/bar/g' file.txt

# สำรองไฟล์เดิมไว้ก่อนแก้
sed -i.bak 's/foo/bar/g' file.txt       # สร้าง file.txt.bak

# ใช้ตัวแยก (delimiter) อื่นเมื่อ pattern มี /
sed 's|/old/path|/new/path|g' config.txt

# ลบบรรทัด
sed '3d' file.txt                       # ลบบรรทัดที่ 3
sed '/^#/d' file.txt                    # ลบบรรทัดที่ขึ้นต้นด้วย #
sed '/^$/d' file.txt                    # ลบบรรทัดว่าง
sed '5,10d' file.txt                    # ลบบรรทัดที่ 5-10

# แทรกข้อความ
sed '1i\
# This is a header' file.txt            # i = insert before line 1
sed '$a\
# End of file' file.txt                 # a = append after last line

# แสดงเฉพาะบางบรรทัด (-n ปิด auto-print, p = print)
sed -n '10,20p' file.txt                # แสดงบรรทัด 10-20
sed -n '/Error/p' log.txt               # แสดงเฉพาะบรรทัดที่มี Error

# หลาย expression ใน sed เดียว
sed -e 's/foo/bar/g' -e 's/hello/hi/g' file.txt

# ตัวอย่างจริง: แปลงนามสกุลไฟล์ .jpg เป็น .png ในชื่อหลาย ๆ ไฟล์
ls *.jpg | sed 's/\.jpg$/.png/'

3.5.4 awk – pattern-action, field

awk เป็นภาษาสคริปต์ขนาดเล็กสำหรับประมวลผลข้อความแบบคอลัมน์ ทรงพลังมาก

แนวคิดหลัก: แบ่งบรรทัดเป็น field คั่นด้วย whitespace (default) เรียกเป็น $1, $2, ... และ $0 คือทั้งบรรทัด

ตัวแปรในตัว (built-in):

# พิมพ์ field ที่ 1 และ 3 ของแต่ละบรรทัด
awk '{print $1, $3}' data.txt

# พิมพ์เฉพาะบรรทัดที่มีมากกว่า 3 field
awk 'NF > 3' data.txt

# เปลี่ยน field separator เป็น : (เช่น /etc/passwd)
awk -F: '{print $1, $7}' /etc/passwd     # username กับ shell

# คำนวณผลรวม คอลัมน์ที่ 2
awk '{sum += $2} END {print "Total:", sum}' sales.txt

# เฉลี่ย
awk '{sum += $2; count++} END {print "Avg:", sum/count}' data.txt

# เงื่อนไข (pattern-action)
awk '$3 > 100 {print $1, $3}' data.txt   # แสดงเฉพาะบรรทัดที่ field 3 > 100

# BEGIN และ END block
awk 'BEGIN {print "Report"; print "------"} 
     {print NR, $0} 
     END {print "Total lines:", NR}' file.txt

# ตัวอย่างจริง: สรุป access.log โดยนับ IP ที่เข้ามา
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head

ตัวอย่าง awk script ที่ซับซ้อนขึ้น - สรุปยอดขายรายสินค้า:

# สมมุติไฟล์ sales.csv
# apple,5,25
# banana,3,15
# apple,2,10
# cherry,4,40

awk -F, '
{
    total[$1] += $3          # บันทึกยอดแต่ละสินค้าใน associative array
    qty[$1] += $2
}
END {
    printf "%-10s %-8s %s\n", "Product", "Qty", "Total"
    for (p in total)
        printf "%-10s %-8d %d\n", p, qty[p], total[p]
}' sales.csv

3.5.5 cut, paste, join

# cut ตัดเฉพาะบางคอลัมน์
cut -d: -f1 /etc/passwd                 # -d = delimiter, -f = field
cut -d: -f1,6,7 /etc/passwd             # หลาย field
cut -c1-10 file.txt                     # ตัดตามตำแหน่ง character
cut -c5- file.txt                       # ตั้งแต่ column 5 ถึงท้าย

# paste รวมไฟล์แบบเรียงข้าง (ทำเป็นคอลัมน์)
paste names.txt ages.txt                # เอาสองไฟล์มาต่อข้าง
paste -d, names.txt ages.txt            # คั่นด้วย comma
paste -s names.txt                      # -s = รวมเป็นบรรทัดเดียว

# join รวมสองไฟล์ตาม key (เหมือน SQL JOIN)
# users.txt:        orders.txt:
# 1 Alice           1 Book
# 2 Bob             2 Pen
# 3 Carol           3 Paper

join users.txt orders.txt
# 1 Alice Book
# 2 Bob Pen
# 3 Carol Paper

3.5.6 sort (-n, -r, -k, -u), uniq (-c, -d)

sort file.txt                       # เรียงตามตัวอักษร
sort -n numbers.txt                 # -n = numeric (เรียงเป็นตัวเลข)
sort -r file.txt                    # -r = reverse (มาก→น้อย)
sort -u file.txt                    # -u = unique (ลบที่ซ้ำ)
sort -k 2 data.txt                  # -k = field ที่ใช้เรียง (field 2)
sort -k 2,2n -k 1,1 data.txt        # เรียง field 2 เป็นเลข, แล้วด้วย field 1
sort -t: -k3 -n /etc/passwd         # -t = delimiter, เรียงตาม UID
sort -h sizes.txt                   # -h = human-readable (1K, 2M, 3G)
sort -R file.txt                    # -R = random shuffle

# uniq ลบบรรทัด "ซ้ำที่ติดกัน" เท่านั้น (ต้อง sort ก่อน!)
sort file.txt | uniq                # ลบที่ซ้ำ
sort file.txt | uniq -c             # -c = นับจำนวนครั้งที่เจอ
sort file.txt | uniq -d             # -d = แสดงเฉพาะที่ซ้ำ
sort file.txt | uniq -u             # -u = แสดงเฉพาะที่ไม่ซ้ำ

# สูตรยอดนิยม: หา top-10 IP ที่เข้าเว็บบ่อยสุด
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -10

3.5.7 tr, rev, fold, column

# tr แปลง (translate) ตัวอักษร - ใช้ผ่าน pipe เท่านั้น
echo "Hello World" | tr 'a-z' 'A-Z'         # → HELLO WORLD
echo "Hello World" | tr -d ' '              # -d = delete → HelloWorld
cat file.txt | tr -s ' '                    # -s = squeeze ลดช่องว่างซ้ำ
echo "2024-10-15" | tr '-' '/'              # → 2024/10/15
tr -cd 'a-zA-Z0-9\n' < input.txt            # -c = complement (เก็บเฉพาะ)

# rev กลับตัวอักษรในบรรทัด
echo "ABCDE" | rev                          # → EDCBA

# fold ตัดบรรทัดยาวตามความกว้าง
fold -w 80 long_line.txt                    # ตัดที่คอลัมน์ 80
fold -s -w 80 text.txt                      # -s ไม่แยกคำกลางคำ

# column จัดเรียงเป็นคอลัมน์สวยงาม
cat /etc/passwd | column -t -s:             # -t = table, -s = delimiter
ps aux | head | column -t

3.5.8 tee

tee ส่ง input ไปทั้งหน้าจอ (stdout) และไฟล์พร้อมกัน - มีประโยชน์เมื่อต้องทั้งดูผลลัพธ์และบันทึก

# เขียนไฟล์ด้วย sudo (ไม่ได้ผลกับ > เพราะ redirect ทำโดย user shell ปกติ)
echo "127.0.0.1 myserver" | sudo tee -a /etc/hosts

# -a = append (ไม่เขียนทับ)
dmesg | tee -a boot.log

# ส่งไปหลายไฟล์พร้อมกัน
ls -l | tee file1.txt file2.txt file3.txt

# เข้าคู่กับ pipeline
cat data.txt | sort | tee sorted.txt | uniq -c
# sorted.txt ได้ข้อมูลเรียง, หน้าจอเห็นผลรวมจำนวนซ้ำ

3.6 Pipe, Redirect และ Process Substitution

แนวคิดนี้คือหัวใจของปรัชญา Unix: "โปรแกรมเล็ก ๆ ที่ทำงานอย่างเดียวให้ดี แล้วต่อกันเป็นสายท่อ"

3.6.1 Pipe (|) และ Named Pipe (mkfifo)

Pipe (|) ส่ง stdout ของคำสั่งซ้ายไปเป็น stdin ของคำสั่งขวา

# ใครคือผู้ใช้ที่ login อยู่มากสุด
who | awk '{print $1}' | sort | uniq -c | sort -rn

# จำนวนไฟล์ .py ในโปรเจกต์
find . -name '*.py' | wc -l

# 5 โปรเซสที่กิน RAM มากสุด
ps aux --sort=-%mem | head -6

Named Pipe (FIFO) เป็นไฟล์ในระบบไฟล์จริง ให้โปรเซสสองตัวสื่อสารกันแบบ stream ได้

# สร้าง named pipe
mkfifo mypipe

# Terminal 1: เขียนข้อมูลเข้า pipe (จะค้างรอจนมีคนอ่าน)
echo "Hello via FIFO" > mypipe

# Terminal 2: อ่านข้อมูลจาก pipe
cat mypipe
# → Hello via FIFO

# ใช้ประโยชน์: streaming log ข้ามโปรเซส
mkfifo /tmp/logpipe
(tail -f /var/log/syslog > /tmp/logpipe) &
grep ERROR /tmp/logpipe

3.6.2 Redirect: <, >, >>, 2>, &>, 2>&1

ทุกโปรเซสใน Unix มี file descriptor 3 ตัวหลัก:

flowchart LR
    IN[stdin fd=0] -->|<| P((Process))
    P -->|>| OUT[stdout fd=1]
    P -->|2>| ERR[stderr fd=2]
    OUT --> F1[file หรือ terminal]
    ERR --> F2[error log หรือ terminal]

    style IN fill:#98971a,stroke:#b8bb26,color:#282828
    style P fill:#d79921,stroke:#fabd2f,color:#282828
    style OUT fill:#458588,stroke:#83a598,color:#fbf1c7
    style ERR fill:#cc241d,stroke:#fb4934,color:#fbf1c7
# >  เขียนทับ (overwrite)  ระวังข้อมูลเดิมหาย!
echo "Hello" > greeting.txt

# >> ต่อท้าย (append)
echo "World" >> greeting.txt

# <  อ่าน input จากไฟล์
wc -l < access.log

# 2> เฉพาะ stderr
grep pattern /etc/ 2> errors.txt

# 1> หรือ > คือ stdout (1 ย่อได้)
command 1> output.log

# &> หรือ >& ทั้ง stdout และ stderr (bash shorthand)
command &> all.log

# 2>&1 รวม stderr เข้า stdout (อ่านว่า "2 follow 1")
command > all.log 2>&1

# ทิ้ง stderr (เงียบ error)
command 2> /dev/null

# ทิ้งทั้งหมด
command &> /dev/null

# เปิดไฟล์เป็น input และ output ของ file descriptor 3
exec 3<> somefile.txt
echo "write" >&3
exec 3<&-           # ปิด fd 3

ลำดับการเขียน redirect สำคัญมาก:

command > file 2>&1     # ถูก: stdout → file, stderr → stdout (ซึ่งไป file)
command 2>&1 > file     # ผิด: stderr → terminal, stdout → file

3.6.3 /dev/null, /dev/zero, /dev/urandom

อุปกรณ์พิเศษใน Linux:

# ทิ้ง output
command > /dev/null 2>&1

# สร้างไฟล์ขนาด 100MB ทดสอบ
dd if=/dev/zero of=testfile bs=1M count=100

# สร้างรหัสผ่านสุ่ม 32 ตัวอักษร base64
head -c 24 /dev/urandom | base64

# สร้าง UUID
cat /proc/sys/kernel/random/uuid

3.6.4 xargs (-n, -I, -P)

xargs แปลง stdin ให้เป็น argument ของคำสั่ง (ไม่ใช่ stdin) มีประโยชน์มากเมื่อคำสั่งไม่อ่าน stdin เอง

# ส่งรายชื่อไฟล์จาก find ไปให้ rm
find . -name "*.tmp" | xargs rm

# -I {} ระบุตำแหน่งของ placeholder (จำเป็นเมื่อไม่ได้อยู่ท้าย)
ls *.jpg | xargs -I {} cp {} /backup/{}.bak

# -n จำกัดจำนวน argument ต่อการเรียก 1 ครั้ง
echo "1 2 3 4 5 6" | xargs -n 2 echo
# 1 2
# 3 4
# 5 6

# -P รันแบบขนาน (parallel) - เร่งความเร็วมาก
cat urls.txt | xargs -n 1 -P 10 wget -q

# -0 ใช้คู่กับ find -print0 เพื่อรองรับชื่อไฟล์ที่มีช่องว่าง
find . -name "*.log" -print0 | xargs -0 rm

# ดูคำสั่งที่จะถูกรันก่อน (-t = trace)
ls | xargs -t -I {} echo "Processing {}"

3.6.5 Command Substitution: $(...) และ backtick

แทนที่ output ของคำสั่งให้กลายเป็นส่วนหนึ่งของคำสั่งอื่น

# แบบ modern (แนะนำ - nestable)
echo "Today is $(date +%Y-%m-%d)"
echo "You have $(ls | wc -l) files"

# สร้างโฟลเดอร์ชื่อมี timestamp
mkdir "backup_$(date +%Y%m%d_%H%M%S)"

# ซ้อน substitution ได้
echo "Latest file: $(ls -t | head -1)"

# แบบเก่า (backtick) - ไม่แนะนำ ซ้อนยาก
echo "Today is `date`"

# เก็บลงตัวแปร
current_user=$(whoami)
uptime_days=$(uptime | awk '{print $3}')

3.6.6 Process Substitution: <(...), >(...)

แปลง output ของคำสั่งให้กลายเป็น ไฟล์ชั่วคราว (จริง ๆ เป็น /dev/fd/...) เพื่อให้คำสั่งที่ต้องการ "ไฟล์" เป็น argument ใช้ได้

# เปรียบเทียบ output ของสองคำสั่งโดยไม่ต้องสร้างไฟล์จริง
diff <(ls /dir1) <(ls /dir2)

# เปรียบเทียบไฟล์ที่ sort แล้ว โดยไม่แก้ไขต้นฉบับ
diff <(sort file1.txt) <(sort file2.txt)

# ดู config ที่ตัด comment ออกแล้วเทียบกัน
diff <(grep -v '^#' /etc/nginx/nginx.conf) <(grep -v '^#' /etc/nginx/nginx.conf.bak)

# >() ส่งไปเป็น "ไฟล์ output"
cat file.txt | tee >(grep ERROR > errors.log) >(grep WARN > warns.log) > /dev/null
# แยก stream เดียวเข้าหลาย grep พร้อมกัน

3.7 การค้นหาไฟล์

3.7.1 find: option เยอะ มีประโยชน์มหาศาล

find เป็นคำสั่งค้นหาไฟล์ที่ทรงพลังที่สุด สามารถค้นโดยเงื่อนไขใด ๆ แล้วทำ action ต่อได้

# โครงสร้าง: find [path] [tests] [actions]

# ค้นหาตามชื่อ (case-sensitive)
find /home -name "*.pdf"

# ไม่สนตัวพิมพ์เล็ก-ใหญ่
find . -iname "*.jpg"

# ตามประเภท: f=file, d=directory, l=symlink, b=block, c=char, s=socket, p=fifo
find /etc -type f -name "*.conf"
find . -type d -name "node_modules"

# ตามขนาด: k=KB, M=MB, G=GB (+มากกว่า, -น้อยกว่า)
find /var -size +100M              # ใหญ่กว่า 100 MB
find . -size -10k                  # เล็กกว่า 10 KB
find . -size 0                     # ไฟล์ขนาด 0

# ตามเวลา (mtime=modify, atime=access, ctime=change metadata)
find . -mtime -7                   # ถูกแก้ไขใน 7 วันที่ผ่านมา
find . -mtime +30                  # ไม่ได้แก้ไขมากกว่า 30 วัน
find . -mmin -60                   # ใน 60 นาทีที่แล้ว

# ตามสิทธิ์
find . -perm 644                   # สิทธิ์ตรงกัน 644
find . -perm -u+x                  # มีสิทธิ์ execute ของเจ้าของ
find / -perm -4000 -type f         # SUID files (สำคัญสำหรับ security audit)

# ตามเจ้าของ
find /home -user moo
find /var -group www-data
find . -nouser                     # ไฟล์ที่ไม่มีเจ้าของ (orphan)

# รวมหลายเงื่อนไข (AND default, ใช้ -o สำหรับ OR, ! หรือ -not สำหรับ NOT)
find . -type f -name "*.log" -size +10M
find . \( -name "*.tmp" -o -name "*.bak" \) -delete

# -exec ทำ action กับผลลัพธ์  {} = ไฟล์ที่พบ, \; = จบคำสั่ง
find . -name "*.log" -exec gzip {} \;
find . -name "*.old" -exec rm -v {} \;

# \; รันคำสั่งต่อไฟล์, + รวมไฟล์ทั้งหมดเป็นครั้งเดียว (เร็วกว่า)
find . -name "*.txt" -exec grep "TODO" {} +

# -delete ลบเลย (ระวังใช้ เมื่อแน่ใจแล้วเท่านั้น)
find /tmp -name "*.cache" -mtime +7 -delete

# ตัวอย่างใช้งานจริง:
# หาไฟล์ที่ใหญ่ที่สุด 10 อันใน /var
find /var -type f -exec du -h {} + | sort -rh | head

# หาไฟล์ที่มีข้อความ "password" โดยไม่รวม .git
find . -type f ! -path "*/.git/*" -exec grep -l "password" {} +

# ลบ __pycache__ ทั้งหมดในโปรเจกต์ Python
find . -type d -name "__pycache__" -exec rm -rf {} +

3.7.2 locate และ updatedb

locate เร็วมากเพราะค้นจากฐานข้อมูลที่สร้างไว้ล่วงหน้า (แต่ข้อมูลอาจไม่ล่าสุด)

# ติดตั้ง (ถ้ายังไม่มี)
sudo apt install plocate             # หรือ mlocate
sudo updatedb                         # สร้าง/อัปเดตฐานข้อมูล (ต้องเป็น root)

# ค้นหา
locate nginx.conf
locate -i readme                      # case-insensitive
locate -c "*.pdf"                     # นับจำนวน
locate -r "^/etc/.*\.conf$"           # regex mode

# locate อัตโนมัติจะ updatedb ผ่าน systemd timer หรือ cron รายวัน

3.7.3 which, whereis, type, command -v

ทั้งสี่ใช้หาตำแหน่งของคำสั่ง แต่มีความต่าง:

# which: บอก path ของ executable ใน $PATH
which python3         # → /usr/bin/python3
which ls              # → /usr/bin/ls

# whereis: หาทั้ง binary, source, manual
whereis gcc           # → gcc: /usr/bin/gcc /usr/share/man/man1/gcc.1.gz

# type: บอกว่าเป็น builtin, alias, function, หรือ external (แม่นสุด)
type cd               # → cd is a shell builtin
type ll               # → ll is aliased to 'ls -lah'
type python3          # → python3 is /usr/bin/python3

# command -v: เหมือน which แต่เป็น POSIX มาตรฐาน ใช้ใน script ได้ปลอดภัย
if command -v docker &>/dev/null; then
    echo "Docker is installed"
fi

3.7.4 fd (modern alternative)

fd คือ find รุ่นใหม่ที่ syntax ง่ายและเร็วกว่า เข้าใจ .gitignore

sudo apt install fd-find             # Debian/Ubuntu (อาจเรียก fdfind)
# หรือ Arch: sudo pacman -S fd

fd pattern                            # เหมือน find -iname "*pattern*"
fd -e py                              # หาไฟล์ .py
fd -H pattern                         # รวม hidden files
fd -t d node_modules                  # -t d = type directory
fd pattern -x wc -l                   # -x = execute (เหมือน -exec ของ find)

3.8 การจัดการสิทธิ์และเจ้าของไฟล์

ระบบสิทธิ์ของ Unix/Linux เป็นรากฐานของความปลอดภัย ทุกไฟล์มี เจ้าของ (owner/user), กลุ่ม (group), และ อื่น ๆ (others) และสำหรับแต่ละกลุ่มมีสิทธิ์ 3 อย่าง: r (read), w (write), x (execute)

3.8.1 chmod Symbolic และ Octal

รูปแบบ Symbolic: [who][op][perm]

chmod u+x script.sh                 # เจ้าของได้สิทธิ์ execute เพิ่ม
chmod g-w file.txt                  # group ลบสิทธิ์ write
chmod o=r document.pdf              # others อ่านได้อย่างเดียว
chmod a+r report.pdf                # ทุกคนอ่านได้
chmod u=rwx,g=rx,o=r script.sh      # กำหนดทุกชุดพร้อมกัน
chmod -R g+w project/               # -R = recursive

รูปแบบ Octal: ผลรวมของ r=4, w=2, x=1 ในแต่ละตำแหน่ง (u, g, o)

แสดงเป็นสมการทางคณิตศาสตร์:

Poctal = 100×pu + 10×pg + po

เมื่อ px ของแต่ละกลุ่ม (u, g, o) คำนวณจาก 4r+2w+1x โดย r, w, x มีค่า 0 หรือ 1

Octal Binary Perm
7 111 rwx
6 110 rw-
5 101 r-x
4 100 r--
3 011 -wx
2 010 -w-
1 001 --x
0 000 ---
chmod 755 script.sh         # rwxr-xr-x (exec สำหรับทุกคน, write เฉพาะเจ้าของ)
chmod 644 notes.txt         # rw-r--r-- (ไฟล์ปกติ)
chmod 600 ~/.ssh/id_rsa     # rw------- (ไฟล์ลับ เฉพาะเจ้าของ)
chmod 700 ~/.ssh            # rwx------ (โฟลเดอร์ลับ)
chmod 777 /tmp              # rwxrwxrwx (ระวัง! เปิดทั้งหมด)

3.8.2 chown user:group, chgrp

# เปลี่ยนเจ้าของ
sudo chown alice file.txt
sudo chown alice:developers file.txt         # พร้อมเปลี่ยน group
sudo chown -R www-data:www-data /var/www/app # recursive (เว็บไซต์ทั้งหมด)
sudo chown --reference=ref.txt file.txt      # ใช้เจ้าของเหมือน ref.txt

# เปลี่ยนแค่ group
sudo chgrp developers file.txt
sudo chgrp -R www-data /srv/site/

3.8.3 umask และค่า default

umask คือ "หน้ากาก" ที่ใช้กันสิทธิ์ออกเมื่อสร้างไฟล์/โฟลเดอร์ใหม่ คำนวณจาก:

umask                       # ดูค่าปัจจุบัน (มักเป็น 0022 หรือ 0002)
umask 0022                  # ไฟล์จะได้ 644, โฟลเดอร์ได้ 755 (default)
umask 0077                  # ไฟล์จะได้ 600, โฟลเดอร์ได้ 700 (paranoid mode)
umask -S                    # แสดงแบบ symbolic: u=rwx,g=rx,o=rx

# ตั้งถาวรใน ~/.bashrc หรือ /etc/profile
echo "umask 0027" >> ~/.bashrc

3.8.4 SUID, SGID, Sticky Bit ในการใช้งานจริง

ทั้งสามเป็น "special permission" ที่มีฟังก์ชันพิเศษ:

SUID (Set User ID) = 4xxx: โปรแกรมที่รันจะมีสิทธิ์ของเจ้าของไฟล์แทน user ผู้เรียก ตัวอย่างคลาสสิก: /usr/bin/passwd เป็นของ root มี SUID เพื่อให้ user ทั่วไปแก้รหัสผ่านตัวเองได้

ls -l /usr/bin/passwd
# -rwsr-xr-x 1 root root 68208 ... passwd    ← s ในตำแหน่ง x ของ user = SUID

SGID (Set Group ID) = 2xxx:

Sticky Bit = 1xxx: ในไดเรกทอรี แม้คนอื่นมีสิทธิ์ write ก็ลบได้เฉพาะไฟล์ของตัวเอง ตัวอย่างคลาสสิก: /tmp มี sticky bit

ls -ld /tmp
# drwxrwxrwt 20 root root ... /tmp    ← t ในตำแหน่ง x ของ others = sticky

# การตั้งค่า special permission (prefix ตัวแรกใน octal 4 หลัก)
chmod 4755 myapp             # SUID + 755
chmod 2775 shared_dir        # SGID + 775
chmod 1777 shared_tmp        # Sticky + 777
chmod 7755 power_app         # SUID + SGID + Sticky + 755

# รูปแบบ symbolic
chmod u+s myapp              # SUID
chmod g+s shared_dir         # SGID
chmod +t shared_tmp          # Sticky

# ค้นหา SUID ทั้งระบบ (security audit)
find / -perm -4000 -type f 2>/dev/null

3.9 การจัดการโพรเซส

ทุกโปรแกรมที่รันอยู่เป็น Process แต่ละตัวมี PID (Process ID), PPID (Parent Process ID), สถานะ, เจ้าของ, และทรัพยากรที่ใช้อยู่ การจัดการโพรเซสเป็นทักษะสำคัญของ sysadmin

stateDiagram-v2
    [*] --> NEW: fork()
    NEW --> READY: admitted
    READY --> RUNNING: scheduler dispatch

RUNNING --> READY: timer / preempt RUNNING --> WAITING: I/O หรือ event WAITING --> READY: I/O เสร็จ RUNNING --> STOPPED: SIGSTOP / SIGTSTP STOPPED --> READY: SIGCONT RUNNING --> TERMINATED: exit() / SIGKILL TERMINATED --> [*]

3.9.1 ps (aux, -ef), pgrep

# BSD style (ยอดนิยม)
ps aux
# USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND

# System V style
ps -ef
# UID  PID PPID C STIME TTY TIME CMD

# ดูเฉพาะโพรเซสของตัวเอง
ps -u $USER

# ดูแบบ tree
ps -ef --forest
ps axjf
pstree -p          # pstree สวยกว่า (ติดตั้ง psmisc)

# กรองด้วย grep (ระวัง grep ก็เป็น process ด้วย)
ps aux | grep nginx
ps aux | grep [n]ginx       # trick: ใส่ [] กัน grep ตัวเอง

# pgrep - หา PID ตามชื่อ
pgrep nginx
pgrep -u moo firefox
pgrep -l ssh                # -l แสดงชื่อด้วย
pgrep -a python            # -a แสดง command line เต็ม

3.9.2 top, htop, btop, glances

เครื่องมือ monitor แบบ interactive:

top             # มาพร้อมทุก distro
# คีย์ใน top:
#   M = เรียงตาม memory
#   P = เรียงตาม CPU
#   k = kill process (ใส่ PID)
#   r = renice
#   q = quit

htop            # สวยกว่า - color, scroll, tree view
sudo apt install htop

btop            # สวยที่สุด (เขียนด้วย C++)
sudo apt install btop

glances         # python-based, แสดงทุกอย่างรวมทั้ง disk, network
sudo apt install glances

3.9.3 kill, killall, pkill และ Signal

Signal เป็นวิธีสื่อสารกับ process ที่กำลังรันอยู่

Signal เลข ความหมาย
SIGHUP 1 Hang up - มักใช้ให้ daemon reload config
SIGINT 2 Interrupt จากคีย์บอร์ด (Ctrl+C)
SIGQUIT 3 Quit + dump core (Ctrl+)
SIGKILL 9 บังคับฆ่าทันที - ดักไม่ได้ ignore ไม่ได้
SIGTERM 15 Terminate อย่างสุภาพ (ตั้งค่า default ของ kill)
SIGSTOP 19 หยุดโพรเซส (ดักไม่ได้)
SIGTSTP 20 Suspend จากคีย์บอร์ด (Ctrl+Z)
SIGCONT 18 Continue ให้โพรเซสที่หยุดอยู่ทำงานต่อ
SIGUSR1/2 10/12 ใช้งานโดยแอปพลิเคชัน
# kill - ตาม PID
kill 1234                # ส่ง SIGTERM (15)
kill -9 1234             # ส่ง SIGKILL - ใช้เมื่อ TERM ไม่ได้ผล
kill -HUP 1234           # reload config
kill -l                  # list signal ทั้งหมด

# killall - ตามชื่อ (ฆ่าทุกตัว)
killall firefox
killall -9 stuck-app

# pkill - ตามชื่อด้วย pattern
pkill nginx
pkill -u moo             # ฆ่า process ของ user moo ทั้งหมด
pkill -f "python.*train.py"    # -f = match full command line

# ตัวอย่างจริง: reload nginx configuration
sudo nginx -t && sudo kill -HUP $(cat /var/run/nginx.pid)
# หรือแบบสมัยใหม่:
sudo systemctl reload nginx

3.9.4 jobs, bg, fg, &, nohup, disown

การควบคุม job ใน shell:

# รันในพื้นหลัง (background) ใส่ & ท้ายคำสั่ง
long_task.sh &
# [1] 12345  ← job number, PID

# ดู job ใน shell นี้
jobs
jobs -l                 # -l แสดง PID ด้วย

# นำกลับมา foreground
fg %1                   # job number 1
fg                      # job ล่าสุด

# ส่งไป background (หลังจาก Ctrl+Z suspend แล้ว)
bg %1

# nohup: ให้ process รันต่อแม้ shell ปิด (ปกติ shell จะส่ง SIGHUP ให้ลูก ๆ)
nohup python3 long_script.py &
# output จะถูกเขียนไปที่ nohup.out

# disown: ปลด job ออกจาก shell
long_running_command &
disown %1

# สมัยใหม่: ใช้ systemd-run แทน nohup
systemd-run --user --scope python3 script.py
# หรือใช้ tmux/screen (ดีที่สุดสำหรับ SSH)
tmux new -s work
# Ctrl+b d เพื่อ detach
tmux attach -t work

3.9.5 nice, renice, ionice

Nice value (−20 ถึง 19): ยิ่งเลขต่ำ priority ยิ่งสูง (user ทั่วไปตั้งค่าลบไม่ได้)

# รันด้วย priority ต่ำลง (nice value สูง) - ไม่รบกวนงานอื่น
nice -n 10 ./backup.sh

# รันด้วย priority สูง (ต้อง root)
sudo nice -n -5 ./critical.sh

# เปลี่ยน priority ของ process ที่กำลังรัน
renice -n 15 -p 1234
renice -n 10 -u moo         # ทุก process ของ user

# ionice - ควบคุม I/O priority (disk)
# class: 1=realtime, 2=best-effort (default), 3=idle
ionice -c 3 tar czf backup.tar.gz /data/     # IO idle - ไม่แย่ง IO งานอื่น
ionice -c 2 -n 0 important.sh                # best-effort level 0 (สูงสุด)

3.9.6 lsof, fuser

# lsof = list open files
sudo lsof                       # ทั้งหมด (เยอะมาก)
sudo lsof -i                    # network connection
sudo lsof -i :80                # port 80
sudo lsof -i :22 -u moo         # port 22 ของ user moo
sudo lsof -p 1234               # ตาม PID
sudo lsof +D /var/log           # ทุกไฟล์ที่เปิดอยู่ในโฟลเดอร์นี้ (recursive)
sudo lsof /var/log/syslog       # ใครเปิดไฟล์นี้อยู่

# fuser - หา process ที่ใช้ไฟล์/port
sudo fuser /var/log/syslog      # แสดง PID
sudo fuser -v /var/log/syslog   # verbose
sudo fuser -k /mnt/usb          # -k = kill (ใช้ก่อน umount)
sudo fuser 8080/tcp             # ใครใช้ port 8080

3.10 การจัดการไฟล์บีบอัดและแพ็กเกจ

3.10.1 tar กับ option c, x, t, z, j, J, v, f

tar = Tape ARchive รวมหลายไฟล์เป็นไฟล์เดียว โดย default ไม่บีบอัด แต่รวมกับ gzip/bzip2/xz/zstd ได้

Option ที่ต้องจำ:

# สร้าง archive
tar cf archive.tar file1 file2 dir/          # ไม่บีบอัด (.tar)
tar czf archive.tar.gz dir/                  # gzip (.tar.gz หรือ .tgz)
tar cjf archive.tar.bz2 dir/                 # bzip2 (ช้า แต่บีบแน่นกว่า)
tar cJf archive.tar.xz dir/                  # xz (บีบแน่นสุด)
tar --zstd -cf archive.tar.zst dir/          # zstd (สมดุลสุด)

# ดูเนื้อหาโดยไม่แตก
tar tf archive.tar.gz
tar tzvf archive.tar.gz | head               # + verbose

# แตก archive
tar xf archive.tar                           # auto-detect การบีบอัด (tar ใหม่)
tar xzf archive.tar.gz -C /tmp/              # -C = extract ไปที่อื่น

# แตกเฉพาะบางไฟล์
tar xzf backup.tar.gz path/to/specific/file

# exclude ไฟล์บางอย่าง
tar czf backup.tar.gz --exclude='*.log' --exclude='node_modules' project/

# มี verbose + ดู progress ไฟล์ใหญ่
tar czvf huge.tar.gz big_folder/

# incremental backup (ครั้งแรกทำ full, ครั้งต่อไปเฉพาะที่เปลี่ยน)
tar czf backup_full.tar.gz -g snapshot.snar /data/
tar czf backup_incr1.tar.gz -g snapshot.snar /data/

3.10.2 gzip, bzip2, xz, zstd

บีบอัดไฟล์เดียว (ไม่รวมหลายไฟล์เหมือน zip/tar):

# gzip (เร็ว, กลาง)
gzip file.txt              # ได้ file.txt.gz ไฟล์ต้นหายไป
gzip -k file.txt           # -k = keep ต้นฉบับ
gzip -9 file.txt           # -9 = อัดแน่นสุด (ช้า)
gunzip file.txt.gz         # หรือ gzip -d
zcat file.txt.gz           # อ่านโดยไม่แตก

# bzip2 (บีบแน่นกว่า แต่ช้า)
bzip2 file.txt
bunzip2 file.txt.bz2
bzcat file.txt.bz2

# xz (บีบแน่นสุดในสาม)
xz file.txt
unxz file.txt.xz
xzcat file.txt.xz

# zstd (รุ่นใหม่ เร็วมาก บีบดี)
sudo apt install zstd
zstd file.txt              # ได้ file.txt.zst
unzstd file.txt.zst
zstdcat file.txt.zst

# เปรียบเทียบ (อ้างอิงทั่วไป):
# gzip:  เร็ว, ratio ~2-3x
# bzip2: ช้า, ratio ~3x  
# xz:    ช้ามาก, ratio ~4x
# zstd:  เร็วมาก, ratio ~2.5-3x (ปรับ level ได้ -1 ถึง -22)

3.10.3 zip/unzip, 7z

เข้ากันได้กับ Windows:

# zip
zip -r archive.zip folder/              # -r = recursive
zip -e secret.zip file.txt              # -e = encrypt (ใส่รหัส)
zip -9 tight.zip file.txt               # max compression

unzip archive.zip                       # แตกที่นี่
unzip archive.zip -d /tmp               # -d = destination
unzip -l archive.zip                    # -l = list
unzip -p archive.zip file.txt           # -p = pipe to stdout

# 7z (อัดแน่นดีมาก รองรับหลายฟอร์แมต)
sudo apt install p7zip-full
7z a archive.7z folder/                 # a = add
7z x archive.7z                         # x = extract (เก็บโครงสร้าง)
7z l archive.7z                         # l = list
7z a -p -mhe=on secret.7z data/         # encrypt headers ด้วย

3.10.4 การรวมกับ find + tar สำหรับ backup

# backup เฉพาะไฟล์ที่แก้ไขใน 7 วัน
find /home/moo -type f -mtime -7 -print0 | tar czf backup.tar.gz --null -T -

# backup เฉพาะ .md และ .txt
find ~/docs -type f \( -name "*.md" -o -name "*.txt" \) | \
    tar czf docs_backup.tar.gz -T -

# backup โปรเจกต์ โดย exclude ของที่ไม่จำเป็น
tar czf project_$(date +%Y%m%d).tar.gz \
    --exclude='.git' \
    --exclude='node_modules' \
    --exclude='*.pyc' \
    --exclude='__pycache__' \
    ~/projects/ai-course/

# backup ไป remote ผ่าน SSH
tar czf - /data | ssh user@backup-server "cat > /backup/data_$(date +%F).tar.gz"

3.11 คำสั่งเกี่ยวกับเครือข่าย

3.11.1 ping, traceroute/tracepath, mtr

# ping ทดสอบ reachability และ latency
ping google.com                          # หยุดด้วย Ctrl+C (Linux ping ต่อเนื่อง)
ping -c 4 8.8.8.8                        # -c = count 4 แพ็กเก็ตแล้วหยุด
ping -i 0.2 target                       # -i = interval 0.2 วินาที
ping -s 1472 -M do target                # -s ขนาด, -M do = don't fragment (หา MTU)

# traceroute เห็นทุก hop ตลอดเส้นทาง
traceroute google.com
traceroute -n google.com                 # -n = ไม่ resolve DNS (เร็วขึ้น)
traceroute -I target                     # ใช้ ICMP (default บาง distro ใช้ UDP)

# tracepath - ไม่ต้อง root
tracepath google.com

# mtr (My TraceRoute) = ping + traceroute แบบ real-time (แนะนำสุด)
sudo apt install mtr
mtr google.com
mtr -n -c 100 -r target                  # -r = report mode

คำสั่ง ifconfig และ route ถูกแทนที่ด้วย ip ที่ทรงพลังกว่า (จากชุด iproute2)

# ---------- interface / address ----------
ip addr                         # หรือ ip a
ip -4 addr                      # เฉพาะ IPv4
ip -6 addr                      # เฉพาะ IPv6
ip addr show eth0               # เฉพาะ interface หนึ่ง

# เพิ่ม/ลบ IP address
sudo ip addr add 192.168.1.10/24 dev eth0
sudo ip addr del 192.168.1.10/24 dev eth0

# ---------- link (interface up/down) ----------
ip link                         # หรือ ip l
sudo ip link set eth0 up
sudo ip link set eth0 down
sudo ip link set eth0 mtu 1500

# ---------- route (routing table) ----------
ip route                        # หรือ ip r
sudo ip route add 10.0.0.0/24 via 192.168.1.1
sudo ip route del 10.0.0.0/24
ip route get 8.8.8.8            # ดูว่าจะไป 8.8.8.8 ทางไหน

# ---------- ARP table / neighbor ----------
ip neigh                        # ARP cache
sudo ip neigh flush all         # ล้าง cache

3.11.3 ss แทน netstat

ss -t                           # TCP connections ที่ established
ss -u                           # UDP
ss -l                           # listening
ss -tlnp                        # ใช้บ่อย: TCP listening, no resolve, + process
# -t=TCP, -l=listen, -n=numeric, -p=process

# ใครฟัง port ไหน
sudo ss -tlnp
# LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=789,fd=3))

# connection ที่เชื่อมต่ออยู่กับ port 443
ss -t state established '( dport = :443 or sport = :443 )'

# นับ connection ต่อ state
ss -ta | awk '{print $1}' | sort | uniq -c

3.11.4 curl, wget, aria2c

# ---------- curl - Swiss Army knife ของ HTTP ----------
curl https://example.com                     # GET + print to stdout
curl -o page.html https://example.com        # -o = output file
curl -O https://example.com/file.zip         # -O = ใช้ชื่อไฟล์จาก URL
curl -L https://bit.ly/xxx                   # -L = ตาม redirect
curl -I https://example.com                  # -I = HEAD request (ดูแค่ header)
curl -v https://example.com                  # -v = verbose
curl -s https://api.example.com/data         # -s = silent (ไม่มี progress bar)

# ---- Method, Header, Body ----
curl -X POST https://api.example.com/users \
     -H "Content-Type: application/json" \
     -H "Authorization: Bearer TOKEN123" \
     -d '{"name":"Moo","role":"lecturer"}'

# ใช้ไฟล์เป็น body
curl -X POST https://api.example.com/upload -d @data.json

# Basic Auth
curl -u username:password https://api.example.com/protected

# Download ต่อจากที่ค้าง
curl -C - -O https://example.com/bigfile.iso

# ---------- wget - เน้นดาวน์โหลดไฟล์ ----------
wget https://example.com/file.zip
wget -c url                     # -c = continue
wget -b url                     # -b = background (log ไป wget-log)
wget -r -np -k -E url           # mirror เว็บทั้งเว็บ (-r recursive, -np ไม่ขึ้นไปโฟลเดอร์แม่)

# ---------- aria2c - รุ่นใหม่ รองรับ multi-connection, torrent ----------
aria2c -x 16 -s 16 url          # 16 connections พร้อมกัน เร็วมาก
aria2c -i urls.txt              # รายการ URL

3.11.5 nslookup, dig, host

# nslookup - เก่าแต่ยังใช้
nslookup google.com
nslookup google.com 8.8.8.8              # ใช้ DNS server เฉพาะ

# dig - ละเอียดที่สุด แนะนำ
dig google.com                            # default A record
dig google.com MX                         # mail record
dig google.com NS                         # name server
dig google.com AAAA                       # IPv6
dig google.com ANY
dig +short google.com                     # output สั้น
dig +trace google.com                     # ตามทุก resolver (DNS root → TLD → authoritative)
dig @8.8.8.8 google.com                   # ใช้ server 8.8.8.8
dig -x 8.8.8.8                            # reverse lookup (IP → name)

# host - เรียบง่าย
host google.com
host -t MX google.com
host google.com 1.1.1.1

3.11.6 nc (netcat), socat

netcat = "Swiss Army knife ของเครือข่าย" ใช้เชื่อมต่อ/ฟัง TCP/UDP ได้ทุกรูปแบบ

# ทดสอบว่า port เปิดอยู่ไหม
nc -zv example.com 443           # -z = scan (no I/O), -v = verbose
nc -zv example.com 20-30         # range of ports

# ส่งข้อมูลหา server
echo "GET / HTTP/1.0" | nc example.com 80

# เปิด listener (server แบบง่ายสุด)
nc -l 9000                       # ฟัง port 9000
# ในอีก terminal:
echo "hello" | nc localhost 9000

# ส่งไฟล์ระหว่างเครื่อง
# รับ: nc -l 9000 > received.tar.gz
# ส่ง: nc receiver-ip 9000 < file.tar.gz

# chat ง่าย ๆ
# server: nc -l 9000
# client: nc server-ip 9000

# socat - ทรงพลังกว่า nc รองรับ SSL, UNIX socket, etc.
socat - TCP:example.com:80                       # เหมือน nc
socat TCP-LISTEN:8080,fork TCP:localhost:80      # forward port
socat OPENSSL:example.com:443,verify=0 -         # เชื่อมต่อ TLS

3.11.7 nmap เบื้องต้น

nmap คือเครื่องมือ scan เครือข่ายและ port ที่นิยมที่สุด (หมายเหตุ: ใช้สแกนเฉพาะเครือข่ายของตัวเองเท่านั้น)

sudo apt install nmap

# สแกน host เดียว (port ยอดนิยม 1000 port)
nmap 192.168.1.10

# สแกนทั้ง subnet (host discovery)
nmap -sn 192.168.1.0/24          # -sn = ping scan ไม่สแกน port

# สแกน port ทั้งหมด
nmap -p- 192.168.1.10

# สแกนเฉพาะ port
nmap -p 22,80,443 target
nmap -p 1-1000 target

# ตรวจสอบ version ของ service
nmap -sV target

# ตรวจสอบ OS
sudo nmap -O target

# สแกนแบบเร็ว (top 100 ports)
nmap -F target

# aggressive - รวมทุก feature (-A = -O + -sV + -sC + --traceroute)
sudo nmap -A -T4 target

3.12 คำสั่งเกี่ยวกับระบบ

3.12.1 uname, hostname, hostnamectl

uname                    # ชื่อ kernel → Linux
uname -r                 # kernel version → 6.11.5-arch1-1
uname -m                 # architecture → x86_64
uname -a                 # ทั้งหมด

# hostname
hostname                 # แสดงชื่อเครื่อง
sudo hostname newname    # ตั้งแบบชั่วคราว (รีบูตหาย)

# hostnamectl (systemd) - ตั้งถาวร
hostnamectl                           # แสดงข้อมูลครบ (static/pretty/transient, chassis, OS)
sudo hostnamectl set-hostname myserver
sudo hostnamectl set-chassis laptop   # desktop, laptop, server, vm, container

3.12.2 uptime, date, timedatectl, cal

uptime
# 14:32:08 up 5 days, 3:47, 2 users, load average: 0.45, 0.32, 0.28
# ปัจจุบัน, uptime, user logged in, load avg 1/5/15 นาที

# date - แสดง/ตั้งวันที่
date
date "+%Y-%m-%d %H:%M:%S"                       # format เอง
date +%s                                         # Unix timestamp
date -d "2 days ago"                             # คำนวณวันที่
date -d "@1700000000"                            # แปลง timestamp → date
date -u                                          # UTC

# timedatectl (systemd)
timedatectl                                      # ข้อมูลเวลาทั้งหมด
sudo timedatectl set-timezone Asia/Bangkok
sudo timedatectl set-ntp true                    # เปิด NTP sync
timedatectl list-timezones | grep Asia

# cal - ปฏิทิน
cal                                              # เดือนปัจจุบัน
cal 2026
cal 11 2026
cal -3                                           # 3 เดือน (ก่อน-ปัจจุบัน-หลัง)

3.12.3 df (-h), du (-sh), free (-h)

# df = disk free (ระบบไฟล์)
df                          # byte แบบ block
df -h                       # human-readable (K, M, G)
df -h /                     # เฉพาะพาร์ทิชัน root
df -hT                      # -T = แสดง type ของ filesystem
df -i                       # inode usage (อาจหมดแม้ที่เหลือเยอะ!)

# du = disk usage (โฟลเดอร์/ไฟล์)
du /var/log                 # recursive byte
du -h /var/log              # human-readable
du -sh /var/log             # -s = summary (ไม่แสดงรายละเอียดย่อย)
du -sh */                   # ขนาดของแต่ละโฟลเดอร์ย่อย
du -h --max-depth=1 /var    # ควบคุมความลึก
du -sh /* 2>/dev/null | sort -rh | head  # top 10 ของ root

# ทางเลือกใหม่: ncdu (ncurses disk usage) - ใช้คีย์เลื่อนดูได้
sudo apt install ncdu
ncdu /                      # สแกนทั้งระบบแล้ว browse ได้

# free = RAM / Swap
free                        # byte
free -h                     # human-readable
free -m                     # MB
free -s 2                   # -s = update ทุก 2 วินาที

3.12.4 lsblk, blkid, mount, umount, fstab

# lsblk = list block devices (disks, partitions)
lsblk                       # เห็น tree ของ disk
lsblk -f                    # -f = แสดง filesystem type + UUID + label
lsblk -p                    # -p = full path /dev/sda แทน sda

# blkid = แสดง UUID / filesystem ของแต่ละ block
sudo blkid
# /dev/sda1: UUID="abcd-1234" TYPE="ext4" PARTUUID="..."

# mount = เม้าต์ระบบไฟล์
sudo mkdir /mnt/usb
sudo mount /dev/sdb1 /mnt/usb                   # mount
sudo mount -o ro /dev/sdb1 /mnt/usb             # read-only
sudo mount -t nfs server:/share /mnt/nfs        # NFS
sudo mount -t ext4 -o rw,noatime /dev/sda2 /data

mount                       # ดู mount ทั้งหมด (ยาวมาก)
mount | grep sdb
findmnt                     # สวยกว่า tree view

# umount
sudo umount /mnt/usb
sudo umount -l /mnt/usb     # -l = lazy (ถ้ามี file ที่เปิดอยู่)

# /etc/fstab - mount อัตโนมัติตอน boot
# UUID=xxx  /data  ext4  defaults,noatime  0  2
# ฟิลด์: device  mountpoint  type  options  dump  fsck-pass

sudo mount -a               # mount ทุกอย่างใน fstab
sudo systemctl daemon-reload

3.12.5 lscpu, lsusb, lspci, lsmod, dmesg

# lscpu = CPU info
lscpu
# Architecture, CPU(s), Model name, CPU MHz, L1/L2/L3 cache, Virtualization
# ดูว่ารองรับ virtualization (VT-x/AMD-V) ไหม
lscpu | grep -i virtualization

# lsusb = USB devices
lsusb
lsusb -t                    # tree
lsusb -v                    # verbose (เยอะมาก)

# lspci = PCI devices (VGA, network card, sound card)
lspci
lspci -k                    # -k = แสดง kernel driver ที่ใช้
lspci -nnk | grep -iA 3 vga

# lsmod = kernel modules ที่โหลดอยู่
lsmod
lsmod | grep nvidia
modinfo <module>            # ดูรายละเอียด module
sudo modprobe <module>      # โหลด module
sudo modprobe -r <module>   # unload

# dmesg = kernel ring buffer (log ของ kernel)
sudo dmesg                  # ทั้งหมด (ยาวมาก)
sudo dmesg -T               # -T = แปลงเวลาเป็น human-readable
sudo dmesg -w               # -w = follow แบบ real-time
sudo dmesg | grep -i error
sudo dmesg | grep -i usb    # ดูว่า USB ตัวใหม่เสียบเจออะไร

# journalctl (systemd) - log แบบสมัยใหม่
journalctl -xe              # log ล่าสุด + explanation
journalctl -u nginx         # เฉพาะ service
journalctl --since "1 hour ago"
journalctl -k               # kernel log (เหมือน dmesg)
journalctl -f               # follow

3.12.6 man, info, --help, tldr, cheat

# man = manual page (มาตรฐาน Unix)
man ls
man 5 passwd                # ระบุ section
man -k keyword              # ค้นหา (เหมือน apropos)
man -f command              # สั้น (เหมือน whatis)

# Section ของ man:
# 1 = user command
# 2 = system call
# 3 = library function
# 4 = device file
# 5 = config file format
# 7 = misc (protocol, convention)
# 8 = admin command

# คีย์ใน man (เหมือน less):
#   / ค้นหา, n ถัดไป, q ออก

# info = manual แบบ hypertext ของ GNU (ละเอียดกว่า man)
info ls

# --help = ช่วยเหลือในตัว (เร็ว เน้น)
ls --help
rsync --help | less

# tldr - "too long; didn't read" ให้ตัวอย่างสั้นที่ใช้บ่อย
sudo apt install tldr       # หรือ npm install -g tldr
tldr tar
tldr ffmpeg
tldr curl

# cheat - สร้าง cheatsheet ส่วนตัวได้
pip install cheat
cheat tar

ตัวอย่าง Lab: ฝึกใช้คำสั่งจริงแบบครบวงจร

ตัวอย่างการใช้คำสั่งในบทนี้ร่วมกันเพื่อแก้ปัญหาจริง เตรียมข้อมูลและคัดลอกบล็อกโค้ดไปทดสอบในเครื่องของผู้เรียนได้ทันที:

# ============================================================
# Lab 1: เตรียมสภาพแวดล้อม
# ============================================================
mkdir -p ~/linux-lab/{logs,data,backup,scripts}
cd ~/linux-lab

# สร้างข้อมูลตัวอย่าง
cat > data/sales.csv << 'EOF'
date,product,quantity,price
2025-10-01,apple,5,25
2025-10-01,banana,3,15
2025-10-02,apple,2,25
2025-10-02,cherry,4,40
2025-10-03,banana,6,15
2025-10-03,apple,3,25
EOF

# สร้าง log ตัวอย่าง
for i in {1..100}; do
    level=$(shuf -e INFO WARN ERROR DEBUG -n 1)
    echo "$(date -d "-$i minutes" '+%Y-%m-%d %H:%M:%S') [$level] Event number $i" \
         >> logs/app.log
done

# ============================================================
# Lab 2: การวิเคราะห์ข้อความ
# ============================================================
# นับ log ตาม level
awk '{print $3}' logs/app.log | sort | uniq -c | sort -rn

# หายอดรวมและเฉลี่ยของ apple
awk -F, '$2=="apple" {total += $3*$4; count += $3} 
         END {print "Total sold:", count, "Revenue:", total}' data/sales.csv

# สรุปยอดทุกสินค้า
awk -F, 'NR>1 {rev[$2] += $3*$4; qty[$2] += $3} 
         END {for (p in rev) printf "%-10s qty=%d rev=%d\n", p, qty[p], rev[p]}' \
    data/sales.csv

# ============================================================
# Lab 3: การจัดการไฟล์ขั้นสูง
# ============================================================
# หาไฟล์ที่ใหญ่กว่า 1KB แล้ว backup
find ~/linux-lab -type f -size +1k -exec cp {} backup/ \;

# สร้าง archive พร้อม timestamp
tar czf backup_$(date +%Y%m%d_%H%M%S).tar.gz logs/ data/

# ============================================================
# Lab 4: ติดตาม log แบบ real-time + filter
# ============================================================
# เปิด Terminal 1
tail -f logs/app.log | grep --line-buffered ERROR

# Terminal 2: เพิ่ม log เข้าไป
echo "$(date '+%Y-%m-%d %H:%M:%S') [ERROR] Manual test error" >> logs/app.log

# ============================================================
# Lab 5: One-liner วิเคราะห์ระบบ
# ============================================================
# Top 5 processes ใช้ RAM
ps aux --sort=-%mem | awk 'NR<=6 {print $2, $4"%", $11}'

# นับจำนวน connection ตาม state
ss -tan | awk 'NR>1 {print $1}' | sort | uniq -c

# หาไฟล์ที่ใหญ่สุด 10 อันใน home
du -ah ~/ 2>/dev/null | sort -rh | head -10

# หาไฟล์ที่แก้ไขภายใน 1 ชั่วโมง
find ~/ -type f -mmin -60 2>/dev/null

# รายงานพื้นที่ดิสก์แบบสั้น
df -h | awk 'NR==1 || $5+0 > 50'        # แสดงบรรทัดที่ใช้เกิน 50%

การฝึกทำ lab เหล่านี้จะช่วยให้ผู้เรียนเห็นว่าคำสั่งแต่ละตัว ไม่ได้มีประโยชน์โดดเดี่ยว แต่ พลังที่แท้จริงเกิดจากการต่อกันเป็น pipeline ตามปรัชญา Unix อย่างแท้จริง