Linux
Fundamental

ทบทวนก่อนสอบปลายภาค

01476113 ภาคเรียนที่ 1/2569
เนื้อหาสัปดาห์ 6 ถึง 11 และเรื่องสิทธิ์ไฟล์จากสัปดาห์ 5
ผลในแล็บจำลองจาก Ubuntu

$ ./recap --help
← →เปลี่ยนสไลด์ หรือปัดบนมือถือ Fเต็มจอ Cสารบัญ Kแฟลชการ์ด Aเปิดแนวตอบในหน้าข้อสอบ Rโหมดอ่านแบบเลื่อน Pบันทึกเป็น PDF
สีไฮไลต์มาจากชีตคำถามของอาจารย์
ฟ้าอาจเอาไปออกข้อสอบ เขียวคำถามน่าสนใจ
ภาพรวม

ข้อสอบน่าจะออกตรงไหน

ข้อเขียนราว 8 ข้อ แต่ละข้อเป็นโจทย์สถานการณ์ ให้อธิบายพร้อมคำสั่ง

  • ขอบเขตหลักคือสัปดาห์ 6 ถึง 11
  • เรื่อง permission จากสัปดาห์ 5 อาจถูกผสมเข้ามาในโจทย์อื่น เช่น cron ที่รันสคริปต์ไม่มีสิทธิ์ x
  • หัวข้อ 6 กลุ่มในชีตคำถามของอาจารย์ตรงกับบทที่สอนพอดี จึงน่าจะเป็นโครงของข้อสอบ
  • โจทย์ที่อาจารย์ไฮไลต์ส่วนใหญ่เป็นแบบ “เกิดปัญหา แล้วให้หาสาเหตุและวิธีแก้”

รูปแบบโจทย์ที่น่าจะเจอ

โจทย์มักเป็นสถานการณ์บริษัทหรือเซิร์ฟเวอร์ ถามหลายขั้นในข้อเดียว และตรวจด้วยเกณฑ์ว่าครบทั้งสาเหตุ คำสั่ง วิธีตรวจ และมุมความปลอดภัยหรือไม่

จำนวนคำถามที่ถูกไฮไลต์ แยกตามหัวข้อ

นับจาก Sheet1 และ Sheet1 (8) รวม 34 ข้อ

Pipe, redirection, sed/awk
4 / 3 Permission, link
4 / 2 Shell script
1 / 5 User, sudo, cron, log
4 / 2 Shell, PATH, process
1 / 4 Disk, mount, LVM
2 / 2
ฟ้า อาจออกสอบเขียว น่าสนใจ

ข้อที่ไฮไลต์ฟ้ามากคือ pipe, permission และ cron ควรเตรียมให้เขียนได้คล่องที่สุด

วิธีเขียนตอบ

โครงคำตอบข้อเขียน

  1. ตีโจทย์ให้ชัด

    เขียนหนึ่งบรรทัดว่าโจทย์ถามกี่อย่าง เช่น สาเหตุ วิธีแก้ และวิธีป้องกัน แล้วตอบให้ครบทุกข้อย่อย

  2. อธิบายกลไก

    บอกว่าระบบทำงานอย่างไรจึงเกิดผลนั้น เช่น “uniq ยุบเฉพาะบรรทัดซ้ำที่อยู่ติดกัน จึงต้อง sort ก่อน”

  3. คำสั่งจริงพร้อม option

    ใส่คำสั่งที่รันได้จริง อธิบาย option สำคัญทีละตัว อย่าเขียนแค่ชื่อคำสั่ง

  4. วิธีตรวจผล

    ปิดท้ายด้วยคำสั่งตรวจ เช่น ls -l id df -h systemctl status crontab -l

  5. มุมความปลอดภัย

    Least Privilege, ไม่ใช้ 777, quote ตัวแปร, ใช้ full path, เก็บ log ไว้ตรวจย้อนหลัง

แม่แบบคำตอบ

ปัญหานี้เกิดจาก ...
เพราะ ... (กลไก)
แก้ได้ด้วยคำสั่ง
  $ ...
ตรวจผลด้วย
  $ ...
เพื่อป้องกันไม่ให้เกิดซ้ำ ควร ...
ข้อเขียนที่ผู้ตรวจใช้ rubric มักให้คะแนนแยกส่วน การเขียนครบ 5 ส่วนแม้สั้นจะได้มากกว่าการอธิบายยาวแค่ส่วนเดียว
W5 Permission

r w x บนไฟล์และไดเรกทอรี

สิทธิ์บนไฟล์บนไดเรกทอรี
r (4)อ่านเนื้อหา catดูรายชื่อไฟล์ ls
w (2)แก้ไขเนื้อหาสร้าง ลบ เปลี่ยนชื่อไฟล์ข้างใน
x (1)รันเป็นโปรแกรมหรือสคริปต์เข้าไปได้ cd และเข้าถึงไฟล์ข้างใน
-rwxr-x---1 admin devops deploy.sh
ชนิดownergroupothers- ไฟล์ d ไดเรกทอรี l symlink
การลบไฟล์ไม่ได้ดูสิทธิ์ของไฟล์ แต่ดูสิทธิ์ w และ x ของไดเรกทอรีที่เก็บไฟล์นั้น

แก้ไฟล์ projects/report.txt ต้องมีอะไรบ้าง

ไดเรกทอรี projects/ ต้องมี x เพื่อผ่านเข้าไป และไฟล์ต้องมี w (กับ r ถ้าเปิดด้วย editor) ไม่จำเป็นต้องให้ w กับไดเรกทอรี

ระบบตรวจสิทธิ์ทีละชั้น ถ้าเป็น owner ใช้ชุด u ทันที ไม่ไปดู g หรือ o ต่อ

W5 Permission

chmod แบบตัวเลขและแบบสัญลักษณ์

เลขสิทธิ์ใช้บ่อยกับ
755rwxr-xr-xสคริปต์ที่ทุกคนรันได้, ไดเรกทอรีทั่วไป
750rwxr-x---สคริปต์ของทีม คนนอกห้ามแตะ
700rwx------สคริปต์ส่วนตัว
644rw-r--r--ไฟล์ทั่วไป
640rw-r-----ไฟล์ลับ เช่น /etc/shadow
# สัญลักษณ์ who(u g o a) op(+ - =) perm(r w x)
chmod u+x,go-w file
chmod o= secret.txt        # ล้างสิทธิ์ others
chown admin:devops deploy.sh
# X ตัวใหญ่ ใส่ x ให้ไดเรกทอรีเท่านั้น
chmod -R u=rwX,g=rX,o= /srv/project
W5 Link

Hard link กับ Soft link

D11
Soft link ln -sHard link ln
ชี้ไปที่path ของไฟล์inode เดียวกับต้นฉบับ
ลบต้นฉบับลิงก์เสียยังเปิดได้
ข้ามพาร์ทิชันได้ไม่ได้
ลิงก์ไดเรกทอรีได้ไม่ได้
ใน ls -ll และ -> targetlink count เพิ่ม

ข้ามพาร์ทิชันไม่ได้ เพราะเลข inode นับแยกในแต่ละพาร์ทิชัน
ลิงก์ไดเรกทอรีไม่ได้ เพราะจะเกิดลูปไม่รู้จบตอน find หรือ du ไล่ต้นไม้

W6 Stream

stdin, stdout, stderr และการเปลี่ยนทิศ

fdชื่อปกติไปที่
0stdinคีย์บอร์ด
1stdoutหน้าจอ
2stderrหน้าจอ

stdout กับ stderr ขึ้นจอเหมือนกัน จึงดูไม่ออกว่ามาจากคนละช่อง จนกว่าจะ redirect

รูปแบบผล
cmd > fstdout ลงไฟล์ เขียนทับ
cmd >> fstdout ต่อท้ายไฟล์
cmd < fอ่าน stdin จากไฟล์
cmd 2> fเฉพาะ stderr ลงไฟล์
cmd > f 2>&1ทั้งสองช่องลงไฟล์เดียว
cmd &> fแบบย่อของบรรทัดบน (bash)
cmd 2>/dev/nullทิ้ง error
2>&1 แปลว่า “ให้ fd 2 ไปที่เดียวกับ fd 1 ณ ตอนนี้” ลำดับจึงสำคัญ ลองสลับลำดับในแล็บหน้าถัดไป
W6 Stream

ข้อมูลไหนไปลงไฟล์ไหน

E35

มี a.txt อยู่จริง แต่ไม่มี nofile.txt

$ ls a.txt nofile.txt > output.txt 2> error.log
  • output.txt ได้บรรทัด a.txt เพราะเป็น stdout
  • error.log ได้ข้อความ cannot access 'nofile.txt' เพราะเป็น stderr
  • หน้าจอว่าง และ exit status เป็น 2 เพราะมีไฟล์หนึ่งหาไม่เจอ
2>&1 > out ไม่เหมือน > out 2>&1 แบบแรก stderr ถูกผูกกับจอก่อน stdout จะย้ายไปไฟล์ error จึงยังขึ้นจอ
W6 Pipe

Pipe ทำงานอย่างไร

E18
cmd1stdoutpipe buffer ใน kernelstdincmd2 stderr ของทั้งสองคำสั่งยังไปที่หน้าจอ ไม่ผ่าน pipe
  1. shell สร้าง pipe ซึ่งเป็น buffer ใน kernel มีปลายเขียนและปลายอ่าน
  2. fork สองโปรเซส ต่อ stdout ของ cmd1 เข้าปลายเขียน และ stdin ของ cmd2 เข้าปลายอ่าน
  3. ทั้งสองคำสั่งรันพร้อมกัน cmd2 อ่านทันทีที่มีข้อมูล ถ้า buffer เต็ม cmd1 จะรอ
  4. exit status ของทั้ง pipeline คือของคำสั่งสุดท้าย เว้นแต่ใช้ set -o pipefail
คำสั่งหน้าที่option ที่ควรรู้
grepกรองบรรทัดตาม pattern-i ไม่สนตัวพิมพ์ -c นับ -v กลับด้าน
cutตัดคอลัมน์-d: ตัวคั่น -f1 ฟิลด์
sortเรียงบรรทัด-r กลับ -n ตัวเลข -h ขนาด
uniqยุบบรรทัดซ้ำที่ติดกัน-c นับจำนวน
wcนับ-l บรรทัด
headเอา n บรรทัดแรก-n 5

Pipe ส่งเฉพาะ stdout ถ้าอยากให้ error ผ่าน pipe ด้วยใช้ cmd 2>&1 | grep ...

W6 Pipe

หา IP ที่ login ล้มเหลวบ่อยที่สุด

E7 E80
grep 'Failed password' /var/log/auth.log \
  | awk '{print $11}' \
  | sort | uniq -c \
  | sort -rn | head -n 5
grepเก็บเฉพาะบรรทัดที่ล็อกอินพลาด
awk $11ดึงฟิลด์ที่ 11 ซึ่งเป็น IP
sortจัด IP เดียวกันให้อยู่ติดกัน
uniq -cนับจำนวนครั้งต่อ IP
sort -rnเรียงตัวเลขมากไปน้อย
head -n 5เอา 5 อันดับแรก

nginx access.log ใช้สูตรเดียวกัน แค่เปลี่ยนเป็น awk '{print $1}'

$11 ใช้กับ log รูปแบบ syslog ดั้งเดิมตามสไลด์ Ubuntu 24.04 ใช้ timestamp แบบ ISO ทำให้ IP ไปอยู่ที่ $9 และบรรทัด invalid user ฟิลด์ก็เลื่อน ดึงด้วย grep -oE 'from [0-9.]+' | awk '{print $2}' จะไม่ขึ้นกับตำแหน่ง

W6 Text tools

sed กับ awk

E73 E69
sedawk
มองข้อมูลเป็นข้อความทีละบรรทัดตาราง แยกฟิลด์ $1 $2
เหมาะกับค้นหาแทนที่ ลบ แทรกบรรทัดกรองตามเงื่อนไข คำนวณ ทำรายงาน
คำสั่งหลักs d p ipattern {action}, BEGIN, END, NR, NF
ตัวอย่างงานแก้ค่าใน config ทั้งไฟล์รวมยอดขาย, ดึงคอลัมน์ IP
# แทนที่ทุกตัว และลบบรรทัด comment
sed 's/error/ERROR/g' app.log
sed '/^#/d' app.conf
# กรองตามเงื่อนไข และรวมยอด
awk '$3 > 20' sales.txt
awk '{s+=$2*$3} END {print s}' sales.txt
W6 Editor

vim และ nano เท่าที่ต้องใช้

vim มีหลายโหมด

โหมดเข้าด้วยใช้ทำ
NormalEscเลื่อน ลบ คัดลอก
Inserti a oพิมพ์ข้อความ
Visualv Vเลือกช่วงข้อความ
Command: /บันทึก ออก ค้นหา

:w บันทึก :q ออก :wq บันทึกแล้วออก :q! ออกโดยไม่บันทึก
dd ลบบรรทัด yy คัดลอก p วาง u undo /คำ ค้นหา

nano ใช้ปุ่ม Ctrl

Ctrl+Oบันทึก (Write Out)
Ctrl+Xออก
Ctrl+Wค้นหา
Ctrl+K / Uตัดบรรทัด / วาง

โจทย์ E29

เปิดไฟล์ lease ของ DHCP เพื่อแก้ IP ใช้ sudo find / -name "*.leases" 2>/dev/null จะพบ /var/lib/dhcp/dhcpd.leases แล้วเปิดด้วย sudo nano ต้องใช้ sudo เพราะ owner คือ root
W7 Environment

PATH คือรายการที่ shell ใช้หาคำสั่ง

F40 F59
  1. ไล่จากซ้ายไปขวาตามลำดับใน $PATH
  2. เจอไฟล์ที่รันได้ตัวแรกแล้วหยุด
  3. ไม่เจอเลยได้ command not found และ exit status 127
ตัวแปรค่าตัวอย่าง
HOME/home/student
USERstudent
SHELL/bin/bash
PWDไดเรกทอรีปัจจุบัน

ดูค่า echo $PATH ดูว่าคำสั่งไหนถูกเลือก which -a myscript หรือ type myscript

W7 Config

export หายเมื่อปิด shell ต้องเขียนลงไฟล์

F28
shell แบบไหนอ่านไฟล์
Login shell (SSH, login ครั้งแรก)/etc/profile แล้ว ~/.bash_profile หรือ ~/.profile ซึ่งมัก source ~/.bashrc ต่อ
Interactive non-login (เปิดแท็บ terminal ใหม่)/etc/bash.bashrc แล้ว ~/.bashrc
Non-interactive (สคริปต์, cron)ไม่อ่าน .bashrc สคริปต์ที่รันจาก terminal ยังได้ตัวแปรที่ export จาก shell แม่ แต่ไม่ได้ alias ส่วน cron ไม่ได้ทั้งคู่

export ทำให้ตัวแปรส่งต่อไปยังโปรเซสลูก แต่มีผลแค่ session นั้น

ทำให้เรียก ~/bin ได้จากทุกที่ และมี alias ll

~/.bashrc เพิ่มท้ายไฟล์

export PATH="$PATH:$HOME/bin"
alias ll='ls -alh'

terminal

$ source ~/.bashrc
$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/home/student/bin
$ type ll
ll is aliased to `ls -alh'
อย่าเขียน PATH=$HOME/bin เฉยๆ เพราะจะทับ PATH เดิม ทำให้ ls และคำสั่งพื้นฐานหาไม่เจอ
W7 Process

สถานะโปรเซส สัญญาณ และ job control

สถานะใน ps / top

RRunning
SSleeping รอเหตุการณ์ ปลุกด้วย signal ได้
DSleep ที่ขัดจังหวะไม่ได้ มักรอ I/O ของดิสก์
TStopped
ZZombie จบแล้วแต่พ่อยังไม่เก็บ exit status

Signal ที่ต้องจำ

1SIGHUPterminal ปิด
2SIGINTCtrl+C
9SIGKILLฆ่าทันที
15SIGTERMค่าเริ่มต้นของ kill
20SIGTSTPCtrl+Z

ใช้ kill PID ก่อนเสมอ ให้โปรแกรมได้ปิดไฟล์และเก็บกวาด kill -9 ใช้เมื่อไม่ยอมจบเท่านั้น

คำสั่ง

ps aux | grep sleep
top                  # เรียงตาม CPU
pgrep -a python
cmd &                # รันเบื้องหลัง
jobs                 # ดู job
fg %1                # ดึงมาหน้า
bg %1                # ให้รันต่อข้างหลัง
kill %1
kill 4821
kill -9 4821
W7 Process

รัน & แล้วปิด terminal งานจะรอดไหม

F41

ไม่รอด เมื่อ terminal ปิดหรือ SSH หลุด kernel ส่ง SIGHUP ให้ shell แล้ว bash ส่ง SIGHUP ต่อให้ทุก job ของตัวเอง ค่าเริ่มต้นของ SIGHUP คือจบโปรเซส

วิธีใช้เมื่อ
nohup cmd > out.log 2>&1 &รู้ล่วงหน้าว่าจะออกจากระบบ
disown -h %1รันไปแล้ว เพิ่งนึกได้
setsid cmdแยก session ใหม่ทั้งหมด
tmux / screenอยากกลับมาดูหน้าจอเดิม
systemd serviceงานถาวรบนเซิร์ฟเวอร์

สไลด์อาจารย์ไม่มี nohup และ disown แต่โจทย์ F41 และ F6 ต้องใช้

W8 Script

สคริปต์แรก ตัวแปร และ argument

F78
#!/bin/bash
# greet.sh ทักทายผู้ใช้
name="${1:-$USER}"          # ไม่มี arg ใช้ $USER
today=$(date +%A)           # command substitution
read -p "อายุ: " age
echo "Hello $name, today is $today"
$ chmod +x greet.sh
$ ./greet.sh alice
  • Shebang บรรทัดแรก บอก kernel ว่าใช้ interpreter ตัวไหน ถ้าไม่มี จะใช้ shell ที่เรียกอยู่ ซึ่งอาจไม่ใช่ bash
  • กำหนดค่า x=5 ห้ามมีช่องว่างรอบ = และไม่ใส่ $
  • ./script รันใน bash โปรเซสใหม่ ตัวแปรที่ตั้งจะไม่กลับมา ส่วน source script รันใน shell ปัจจุบัน

รัน ./my.sh apple "grape juice" kiwi

ตัวแปรค่า
$0./my.sh
$1apple
$2grape juice (quote จึงเป็นค่าเดียว)
$#3 ไม่นับ $0
"$@"ทุกตัว แยกเป็นคำละตัว
"$*"ทุกตัว รวมเป็นสตริงเดียว
$?exit status ของคำสั่งล่าสุด
$$PID ของสคริปต์

read -p ข้อความนำ -s ซ่อนตัวอักษร -t หมดเวลา -r ไม่แปล backslash

W8 Test

ตัวดำเนินการทดสอบ และ [ ] กับ [[ ]]

G36

ตัวเลข

-eq -ne -gt -lt -ge -le

สตริง

= != -z ว่าง -n ไม่ว่าง

ไฟล์

-eมีอยู่
-fเป็นไฟล์ปกติ
-dเป็นไดเรกทอรี
-r -w -xอ่าน เขียน รันได้
-sขนาดมากกว่า 0
[ ] หรือ test[[ ]]
ที่มาPOSIX ใช้ได้กับ sh ทุกตัวkeyword ของ bash, zsh
ตัวแปรไม่ quoteเกิด word splitting และ glob ค่าว่างหรือมีช่องว่างทำให้ errorไม่ split ไม่ glob ปลอดภัยกว่า
AND / OR-a -o หรือแยก [ ] && [ ]&& || ! ในวงเล็บได้เลย
Pattern / Regexไม่มี== *.txt และ =~ ^[0-9]+$
< >ต้อง escape ไม่งั้นกลายเป็น redirectเทียบสตริงได้ตรงๆ
name="my file"
[ $name = "my file" ]     # bash: [: too many arguments
[ "$name" = "my file" ]   # ถูก ต้อง quote
[[ $name == my* ]]        # ถูก และใช้ pattern ได้
W8 Exit status

exit status บอกผลให้ระบบอื่นรู้

G72 G74
ค่าความหมาย
0สำเร็จ
1error ทั่วไป
2ใช้ผิด หรือ ls หาไฟล์ไม่เจอ
126เจอไฟล์ แต่ไม่มีสิทธิ์รัน
127command not found
#!/bin/bash
if [ -f "$1" ]; then
  echo "Config found"
else
  echo "Config not found: $1" >&2
  exit 1
fi

$? ต้องอ่านทันที เพราะคำสั่งถัดไป รวมถึง echo จะเขียนทับ ใช้คู่กับ && และ || ได้ เช่น ./check.sh app.conf && ./run.sh

W9 Script

ลูป ฟังก์ชัน และอาร์เรย์

ลูป

for f in *.txt; do
  echo "$f"
done

for i in {1..5}; do ...; done

i=1
while [ $i -le 3 ]; do
  i=$((i+1))
done

while read -r line; do
  echo "$line"
done < list.txt

while วนขณะเงื่อนไขจริง until วนจนกว่าเงื่อนไขจะจริง

ฟังก์ชัน

is_exec() {
  local f="$1"
  [ -f "$f" ] && [ -x "$f" ]
}

for f in "${1:-.}"/*; do
  is_exec "$f" && echo "$f"
done
  • arg ในฟังก์ชันคือ $1 $2 ของฟังก์ชันเอง
  • local กันชนกับตัวแปร global
  • return ส่ง status 0 ถึง 255 ส่วนค่าข้อมูลให้ echo แล้วรับด้วย $( )

อาร์เรย์

fruits=(apple banana cherry)
echo "${fruits[0]}"    # apple
echo "${fruits[@]}"    # ทั้งหมด
echo "${#fruits[@]}"   # 3
echo "${!fruits[@]}"   # 0 1 2
fruits+=(mango)

คำนวณ

echo $(( 7 / 2 ))           # 3
echo "scale=2; 7/2" | bc    # 3.50
W9 Script

ลองรันสคริปต์จากใบงานด้วย argument ต่างกัน

G85 G41
#!/bin/bash

ทุกสคริปต์มาจากใบงานในคลาส

W9 Safety

เขียนสคริปต์แบบป้องกัน

จากโจทย์ G6 และ G27
#!/bin/bash
set -euo pipefail

DIR="${1:?usage: $0 <dir>}"
[ -d "$DIR" ] || { echo "no dir" >&2; exit 1; }

rm -rf -- "${DIR:?}"/*
-eคำสั่งไหนล้มเหลว หยุดสคริปต์ทันที
-uอ้างตัวแปรที่ไม่ได้กำหนดค่า ให้ error
-o pipefailpipeline ล้มเหลวถ้ามีคำสั่งใดใน pipe ล้มเหลว
${VAR:?msg}ว่างหรือไม่มีค่า หยุดพร้อมข้อความ

ทำไม rm -rf "$DIR"/* อันตราย

ถ้า DIR ว่าง บรรทัดนี้กลายเป็น rm -rf /* ลบทั้งระบบ ถ้ารันด้วย root ป้องกันด้วย set -u และ ${DIR:?}
อย่าทำทำแทน
chmod -R 777755 กับไดเรกทอรี 644 กับไฟล์
curl ... | sudo bashโหลดมาอ่านก่อน ตรวจ checksum
eval $inputตรวจและกรอง input
echo $VARecho "$VAR"
รหัสผ่านในสคริปต์ตัวแปรสภาพแวดล้อม หรือไฟล์สิทธิ์ 600

trap 'rm -f "$TMP"' EXIT ลบไฟล์ชั่วคราวเสมอแม้สคริปต์จบด้วย error

W9 Backup

สคริปต์สำรองข้อมูล .tar.gz พร้อม log

จากโจทย์ G4
#!/bin/bash
set -euo pipefail
SRC="${1:?usage: $0 <dir>}"
DEST=/backup
LOG=/var/log/backup.log
TS=$(date +%Y%m%d_%H%M)

[ -d "$SRC" ] || { echo "$TS no source $SRC" >> "$LOG"; exit 1; }

if tar -czf "$DEST/web_$TS.tar.gz" -C "$SRC" .; then
  echo "$TS OK web_$TS.tar.gz" >> "$LOG"
else
  echo "$TS FAIL tar exit $?" >> "$LOG"
  exit 1
fi
optionความหมาย
-ccreate สร้าง archive
-xextract แตกไฟล์
-tlist ดูรายการข้างใน
-zผ่าน gzip
-vแสดงชื่อไฟล์ขณะทำ
-fชื่อไฟล์ archive ต้องตามหลังทันที
-C dirเปลี่ยนไดเรกทอรีก่อนทำ
tar -tzf web_20261104_0230.tar.gz
tar -xzvf web_20261104_0230.tar.gz \
  -C /tmp/restore

tar รวมไฟล์เป็นก้อนเดียวและเก็บ permission ส่วน gzip บีบอัด

W10 Disk

ดิสก์ พาร์ทิชัน และ filesystem

ชื่ออุปกรณ์

/dev/sdaSATA, SCSI, USB ลูกแรก
/dev/sdb1ลูกที่สอง พาร์ทิชัน 1
/dev/nvme0n1p2NVMe controller 0, namespace 1, พาร์ทิชัน 2
lsblk
sudo fdisk -l /dev/sdb
sudo blkid /dev/sdb1

MBR กับ GPT

MBRGPT
มักคู่กับBIOSUEFI
ดิสก์สูงสุด2.2 TBราว 9.4 ZB
primary4128
สำรองตารางไม่มีมีที่ท้ายดิสก์

Filesystem

ext4มาตรฐาน มี journaling เสถียร ไม่มี snapshot
xfsไฟล์ใหญ่ งานขนานดี ย่อขนาดไม่ได้
btrfsCopy-on-Write, snapshot, checksum มี overhead

Journaling บันทึกสิ่งที่จะเขียนก่อนเขียนจริง ไฟดับกลางทางจึงกู้กลับได้เร็ว

W10 Mount

เพิ่มดิสก์ใหม่จนใช้งานได้ถาวร

  1. ดูดิสก์ใหม่

    lsblk เห็น sdb ที่ยังไม่มีพาร์ทิชัน
  2. แบ่งพาร์ทิชัน

    sudo fdisk /dev/sdb แล้วกด n p 1 Enter Enter w
  3. ฟอร์แมต

    sudo mkfs.ext4 /dev/sdb1 ต้องเป็น sdb1 ไม่ใช่ sdb
  4. สร้าง mount point และ mount

    sudo mkdir -p /mnt/backup
    sudo mount /dev/sdb1 /mnt/backup
  5. ทำให้ถาวร

    sudo blkid /dev/sdb1 คัด UUID ไปใส่ /etc/fstab
  6. ทดสอบก่อนรีบูต

    sudo mount -a ไม่มี error แล้วดู df -h

6 ฟิลด์ของ /etc/fstab

UUID=b06b...c0b1  /mnt/backup  ext4  defaults  0  2
1อุปกรณ์ ใช้ UUID เพราะชื่อ sdX เปลี่ยนได้เมื่อเพิ่มดิสก์
2mount point
3ชนิด filesystem
4options เช่น defaults noexec nofail
5dump ใช้ 0
6ลำดับ fsck ราก / เป็น 1 ที่เหลือ 2 ไม่ตรวจ 0
fstab ผิดอาจทำให้บูตไม่ขึ้น จึงต้อง mount -a ทดสอบก่อนรีบูตเสมอ
W10 Mount

รีบูตแล้ว root เต็ม ทั้งที่เขียนลง /mnt/backup

H72

mount ด้วยมือมีผลถึงรีบูตเท่านั้น หลังรีบูต /mnt/backup เป็นแค่ไดเรกทอรีว่างบน root สคริปต์จึงเขียนลงดิสก์หลักจนเต็ม

  1. หยุดสคริปต์ backup หรือ cron ก่อน
  2. df -h /mnt/backup เห็นว่าเป็น /dev/sda2 ไม่ใช่ sdb1 และ du -sh /mnt/backup เห็นขนาดที่กินไป
  3. ย้ายไฟล์ออกไปที่อื่นชั่วคราว ถ้า mount ทับไปเลย ไฟล์เดิมจะถูกซ่อนใต้ mount point และยังกินพื้นที่ root ต่อ
  4. ใส่ UUID ใน /etc/fstab แล้ว mount -a ย้ายไฟล์กลับเข้าดิสก์ใหม่ ตรวจด้วย df -h
  5. ให้สคริปต์ตรวจก่อนเขียน mountpoint -q /mnt/backup || exit 1
W10 df du

df, du และ “No space left” ทั้งที่ยังว่าง

H28 H42
dfdu
ดูระดับทั้ง filesystemไฟล์และไดเรกทอรี
วิธีได้ค่าอ่าน superblock เร็วไล่รวมขนาดไฟล์ ช้า
ตอบคำถามดิสก์เต็มไหมอะไรกินที่
df -h /var
sudo du -sh /var/* 2>/dev/null | sort -rh | head -n 3
df -i /var                  # inode
sudo lsof +L1               # ไฟล์ที่ลบแล้วแต่ยังเปิดอยู่

ค่าของ du กับ df ไม่เท่ากันได้ เช่น ไฟล์ที่ลบแล้วแต่โปรเซสยังเปิดอยู่ ไฟล์ที่ซ่อนใต้ mount point และ hard link

df -h ว่าง 50% แต่สร้างไฟล์ไม่ได้

สาเหตุตรวจด้วย
inode หมด ไฟล์เล็กจำนวนมาก เช่น session หรือ cachedf -i IUse% 100%
ติด quota ของ user หรือ groupquota -u user
เขียนผิดที่ path นั้นอยู่คนละ filesystem เช่น /tmp เป็น tmpfsdf -h /path
reserved blocks ext4 กันไว้ 5% ให้ root user ปกติจึงเต็มก่อนsudo tune2fs -l /dev/sda2 | grep -i reserved
ก่อนลบไฟล์ ตรวจว่าใครเป็นเจ้าของ ยังใช้งานอยู่ไหม (lsof) และควร backup หรือบีบอัดแทนลบ log ที่ยังต้องใช้
W10 LVM

LVM ทำให้ขยายพื้นที่ได้โดยไม่ต้องแบ่งดิสก์ใหม่

H35
mount
//home/var/logว่าง
LV
lv_rootlv_datalv_log
VG
vg_main พื้นที่รวมของทุกดิสก์
PV
/dev/sdb/dev/sdc/dev/sdd
sudo pvcreate /dev/sdb /dev/sdc /dev/sdd
sudo vgcreate vg_main /dev/sdb /dev/sdc /dev/sdd
sudo lvcreate -n lv_data -L 100G vg_main
sudo mkfs.ext4 /dev/vg_main/lv_data
# เพิ่มดิสก์ภายหลัง
sudo pvcreate /dev/sde
sudo vgextend vg_main /dev/sde
sudo lvextend -r -L +50G /dev/vg_main/lv_data

สไลด์อาจารย์ไม่มี vgextend และ lvextend แต่ต้องใช้ตอบเรื่องขยายพื้นที่ -r สั่ง resize filesystem ให้ด้วย

W11 User

/etc/passwd, /etc/shadow, /etc/group

I44
somchai:x:1001:1001:Somchai P.:/home/somchai:/bin/bash
1username
2x แปลว่า hash อยู่ใน /etc/shadow
3UID
4GID ของ primary group
5GECOS ชื่อจริง ห้อง เบอร์
6home directory
7login shell /usr/sbin/nologin คือห้าม login

0 root, 1 ถึง 999 บัญชีระบบและ service, 1000+ ผู้ใช้ทั่วไป

ไฟล์เก็บใครอ่านได้
/etc/passwdข้อมูลบัญชีทุกคน (644)
/etc/shadowhash รหัสผ่าน อายุรหัสผ่านroot และกลุ่ม shadow (640)
/etc/groupกลุ่มและสมาชิกทุกคน

UID ถูกแก้เป็น 0

ระบบตรวจสิทธิ์ด้วยตัวเลข UID ไม่ใช่ชื่อ บัญชีนั้นจึงเท่ากับ root ทันทีโดยไม่ต้องใช้ sudo เป็นช่องโหว่ แก้ฟิลด์ที่ 3 ด้วย sudo vipw เพราะ usermod จะปฏิเสธเมื่อ UID นั้นมีโปรเซสรันอยู่ ซึ่ง UID 0 มีเสมอ แล้วตรวจ awk -F: '$3==0' /etc/passwd ต้องเหลือแค่ root

เพิ่มกลุ่ม sudo แล้วยังใช้ไม่ได้ ส่วนใหญ่เพราะยังไม่ logout แล้ว login ใหม่ กลุ่มใหม่มีผลกับ session ถัดไป

W11 sudo

-G กับ -aG และการให้ sudo แบบจำกัด

I35
sudo groupadd dev
sudo useradd -m -s /bin/bash -G dev alice
sudo passwd alice
sudo usermod -aG sudo alice     # Ubuntu
sudo usermod -aG wheel alice    # RHEL
id alice
usermod -G testing alice แทนที่ กลุ่มรองทั้งหมดด้วย testing กลุ่มเดิมจึงหาย ต้องมี -a (append) คู่กับ -G เสมอ

sudo แบบ Least Privilege

$ sudo visudo -f /etc/sudoers.d/web
# user host=(runas) command
%webops ALL=(root) \
  /usr/bin/systemctl restart nginx

visudo ตรวจ syntax ก่อนบันทึก ถ้าแก้ /etc/sudoers ตรงๆ แล้วพิมพ์ผิด อาจไม่มีใครใช้ sudo ได้อีก

W11 Service

ติดตั้งแพ็กเกจ และจัดการ service

aptdpkg
ระดับhigh levellow level
ดึงจาก repositoryได้ไม่ได้ ติดตั้งจากไฟล์ .deb
แก้ dependencyอัตโนมัติไม่ทำ
sudo apt update
sudo apt install -y nginx
sudo apt upgrade
apt list --installed | grep nginx
sudo dpkg -i app.deb
dpkg -l | grep nginx

apt update แค่ดึงรายการ ไม่ได้อัปเกรดอะไร apt upgrade คือตัวที่อัปเกรดจริง

startenable
ทำงานตอนนี้ใช่ไม่
เปิดเองหลังรีบูตไม่ใช่ สร้าง symlink
sudo systemctl enable --now nginx   # ทั้งสองอย่าง
systemctl status nginx
sudo systemctl restart nginx
sudo systemctl reload nginx         # อ่าน config ใหม่
systemctl is-enabled nginx
journalctl -u nginx --since today

สถานะ active (running) inactive (dead) failed ถ้า failed ให้ดูสาเหตุที่ journalctl -u

W11 cron

crontab มี 5 ฟิลด์เวลา ตามด้วยคำสั่ง

I30 I74
30นาที0-59
2ชั่วโมง0-23
*วันที่1-31
*เดือน1-12
1-5วันในสัปดาห์0-7
/path/to/commandคำสั่ง ใช้ full path

วันในสัปดาห์ 0 และ 7 คืออาทิตย์ 1-5 คือจันทร์ถึงศุกร์

*ทุกค่า,หลายค่า 1,15
-ช่วง 1-5/ทุกๆ */3
crontab -e        crontab -l
crontab -r        # ลบทั้งหมด ระวัง
sudo crontab -u alice -e

@reboot @daily @hourly @weekly ใช้แทน 5 ฟิลด์ได้

W11 cron log

รันเองได้ แต่ cron ไม่ทำงาน

I42
สาเหตุแก้
PATH ของ cron มีแค่ /usr/bin:/binใช้ full path เช่น /usr/bin/python3
working directory คือ home ไม่ใช่ไดเรกทอรีโปรเจกต์cd /home/student/project && ก่อน
ไม่โหลด .bashrc ตัวแปรที่ export ไว้หายหมดประกาศในสคริปต์หรือบนหัว crontab
สคริปต์ไม่มีสิทธิ์ xchmod u+x หรือเรียก /bin/bash script.sh
ไฟล์ใน /etc/cron.d/ ไม่มีช่อง user หรือชื่อไฟล์มีจุดเพิ่มช่อง user ที่ 6 ชื่อไฟล์ใช้แค่ A-Z a-z 0-9 _ -
output หายไป ไม่รู้ว่าพังตรงไหน>> job.log 2>&1

อ่าน log

journalctl -u cron --since today
grep CRON /var/log/syslog
journalctl -u nginx -p err -b
journalctl -f                   # ตามดูสด
tail -f /var/log/auth.log
sudo grep 'Failed password' /var/log/auth.log
/var/log/syslogข้อความทั่วไป รวมถึง cron
/var/log/auth.loglogin, sudo, ssh
/var/log/journal/journal ของ systemd แบบ binary อ่านด้วย journalctl
เก็งข้อสอบ

8 ข้อที่น่าจะออก

หัวข้อฐานจากคำถามที่ไฮไลต์

ลองเขียนเองก่อนเปิดแนวตอบ

ข้อ 5 มีคำถามไฮไลต์ฟ้ามากที่สุด รองลงมาคือข้อ 1, 2 และ 6 ถ้าเวลาน้อยให้ซ้อมสี่ข้อนี้ก่อน

ตัวอักษรและเลขคือเซลล์ในชีต เช่น E7 คือคอลัมน์ Pipe แถว 7 ของ Sheet1 ส่วน E18 ขึ้นไปบางตัวมาจาก Sheet1 (8)

ข้อ 1

ไดเรกทอรีงานร่วมของทีม

permission link

บริษัทมี /srv/project ให้ alice และ bob ในกลุ่ม devops ใช้ร่วมกัน คนนอกกลุ่มต้องเข้าไม่ได้ ไฟล์ deploy.sh ให้เจ้าของทำได้ทุกอย่าง กลุ่มอ่านและรันได้ จงเขียนคำสั่ง อธิบายว่า bob ลบไฟล์ของ alice ได้หรือไม่ และถ้าต้องการสำรองไฟล์ที่ยังใช้ได้แม้ต้นฉบับถูกลบ ควรใช้ลิงก์แบบใด

ประกอบจาก D6, D11, D72, D18

sudo chown -R admin:devops /srv/project
sudo chmod 770 /srv/project
sudo chmod 750 /srv/project/deploy.sh
sudo ln /srv/project/deploy.sh /srv/project/deploy_backup.sh
ls -l /srv/project
ไดเรกทอรี
770 กลุ่มเข้าได้ x สร้างไฟล์ได้ w คนนอก 0
bob ลบได้ไหม
ได้ เพราะการลบดู w+x ของไดเรกทอรี ไม่ดูสิทธิ์ไฟล์ แม้ไฟล์เป็น rw-r----- bob อ่านได้ แก้ไม่ได้ แต่ลบได้
ลิงก์สำรอง
hard link ชี้ inode เดียวกัน ลบต้นฉบับแล้วข้อมูลยังอยู่ แต่ถ้าย้ายไปคนละพาร์ทิชันทำไม่ได้ ต้อง cp -p แทน hard link กันได้แค่การลบ แก้ผ่านชื่อใดก็เปลี่ยนทั้งคู่ soft link ไม่ช่วยเพราะจะเสีย
ความปลอดภัย
Least Privilege ให้สิทธิ์ผ่านกลุ่ม ไม่ใช้ 777 ถ้าไม่ให้ลบไฟล์ของกันใช้ chmod 3770 sticky bit ห้ามลบไฟล์คนอื่น setgid ให้ไฟล์ใหม่อยู่กลุ่ม devops
ข้อ 2

วิเคราะห์ log หาผู้โจมตี

pipe redirection

จากไฟล์ /var/log/auth.log ให้หา IP ที่ล็อกอินล้มเหลวมากที่สุด 5 อันดับ เขียนคำสั่งบรรทัดเดียว อธิบายแต่ละขั้นของ pipeline บันทึกผลลง top5.txt และทิ้งข้อความ error ทั้งหมด อธิบายด้วยว่าถ้าตัด sort ตัวแรกออกจะเกิดอะไร

ประกอบจาก E7, E80, E6, E35, E18

{ sudo grep 'Failed password' /var/log/auth.log \
 | awk '{print $11}' | sort | uniq -c \
 | sort -rn | head -n 5; } > top5.txt 2>/dev/null
แต่ละขั้น
กรองบรรทัด ดึงฟิลด์ IP จัดให้ IP เดียวกันติดกัน นับ เรียงจำนวนมากไปน้อย เอา 5 แถว
ตัด sort ออก
uniq -c นับเฉพาะบรรทัดซ้ำที่อยู่ติดกัน IP เดียวกันที่กระจายอยู่จะถูกนับแยกหลายแถว ผลผิด
กลไก pipe
ส่งเฉพาะ stdout ผ่าน buffer ใน kernel ทุกคำสั่งรันพร้อมกัน stderr ไม่ผ่าน pipe จึงต้องครอบทั้ง pipeline ก่อนใส่ 2>/dev/null
ความปลอดภัย
auth.log อ่านได้เฉพาะ root และกลุ่ม adm จึงต้อง sudo นำ IP ที่ได้ไปบล็อกต่อ เช่น ufw deny from IP

ถ้าไม่ครอบด้วย { ... ; } แล้วใส่ 2>/dev/null ท้ายบรรทัด จะทิ้งได้แค่ error ของ head

ข้อ 3

เรียกสคริปต์ไม่เจอ และโปรเซสกิน CPU

environment process

นักศึกษาวาง monitor.sh ไว้ใน ~/scripts เรียกด้วย path เต็มได้ แต่พิมพ์ชื่ออย่างเดียวได้ command not found ต่อมาพบโปรแกรมทำงานเบื้องหลังกิน CPU สูง อธิบายสาเหตุ วิธีตั้งค่าให้เรียกได้ทุกครั้งที่เปิด Bash วิธีหยุดเฉพาะโปรเซสที่มีปัญหา และถ้าต้องรันงานยาวผ่าน SSH ควรทำอย่างไร

ประกอบจาก F59, F40, F28, F41

echo 'export PATH="$PATH:$HOME/scripts"' >> ~/.bashrc
source ~/.bashrc && type monitor.sh
top                         # หา PID ที่ %CPU สูง
ps -o pid,user,%cpu,cmd -p 4821
kill 4821                   # SIGTERM ก่อน
kill -9 4821                # ถ้ายังไม่จบ
nohup ./job.sh > job.log 2>&1 &
สาเหตุ
shell หาคำสั่งจาก PATH ซ้ายไปขวา ~/scripts ไม่อยู่ใน PATH ถ้าชื่อซ้ำกันใน PATH ตัวที่อยู่ซ้ายกว่าจะถูกเลือก
ถาวร
export ใน terminal หายเมื่อปิด ต้องเขียนใน ~/.bashrc และเก็บ PATH เดิม
หยุดเฉพาะตัว
อ้าง PID ที่ตรวจแล้ว ไม่ใช้ killall เพราะกระทบตัวอื่นชื่อเดียวกัน
งานยาวผ่าน SSH
ปิดหน้าต่างแล้วโปรเซสได้ SIGHUP ต้องใช้ nohup, tmux หรือ systemd
ข้อ 4

สคริปต์ตรวจความพร้อมก่อนรันโปรแกรม

shell script

เขียนสคริปต์รับชื่อไฟล์ config ทาง $1 ตรวจว่ามีอยู่จริงและเป็นไฟล์ปกติ ถ้ามีให้แสดง Config found ถ้าไม่มีให้หยุดด้วย exit status 1 อธิบายว่าเหตุใดควรใช้ [[ ]] หรือ quote ตัวแปร และระบบอื่นนำ exit status ไปใช้อย่างไร

ประกอบจาก G72, G74, G36

#!/bin/bash
if [ $# -ne 1 ]; then
  echo "usage: $0 <config>" >&2; exit 2
fi
if [[ -f $1 ]]; then
  echo "Config found"
  exit 0
else
  echo "Config not found: $1" >&2
  exit 1
fi
-f ไม่ใช่ -e
-e จริงแม้เป็นไดเรกทอรี โจทย์ต้องการไฟล์ปกติ
quote
ชื่อไฟล์มีช่องว่างหรือว่าง [ -f $1 ] จะแตกเป็นหลายคำ [[ ]] ไม่ทำ word splitting
exit status
0 สำเร็จ ไม่ใช่ 0 ล้มเหลว ใช้ต่อด้วย ./check.sh a.conf && ./app, cron หรือ CI ตัดสินจากค่านี้
ข้อ 5

Backup อัตโนมัติด้วย cron ที่ไม่ยอมทำงาน

script cron permission

ผู้ใช้ student ตั้ง 2 30 * * 1-5 python3 report.py ใน crontab เพื่อให้รันวันจันทร์ถึงศุกร์ 02:30 แต่ไม่ทำงาน ทั้งที่รันเองได้ จงหาข้อผิดพลาดทั้งหมด เขียนบรรทัดที่ถูกต้องพร้อมเก็บ output และ error ลง log และบอกคำสั่งตรวจ log ของ cron วันนี้

ประกอบจาก I74, I30, I42, G4

30 2 * * 1-5 cd /home/student/project && \
  /usr/bin/python3 report.py \
  >> /home/student/report.log 2>&1

ใน crontab จริงต้องเขียนเป็นบรรทัดเดียว ตัดบรรทัดไว้ให้อ่านง่ายเท่านั้น

ลำดับฟิลด์
นาทีมาก่อนชั่วโมง 2 30 คือนาที 2 ชั่วโมง 30 ซึ่งไม่มีอยู่จริง
PATH
PATH ของ cron มีแค่ /usr/bin:/bin python3 อยู่ใน /usr/bin จึงหาเจอ แต่ควรใช้ full path จาก which python3 เพราะคำสั่งใน /usr/local/bin หรือ ~/bin จะหาไม่เจอ
ไดเรกทอรี
cron เริ่มที่ home report.py แบบ relative หาไม่เจอ ต้อง cd ก่อน ไฟล์ที่สคริปต์เขียนแบบ relative ก็จะไปอยู่ใน home
log
>> ต่อท้าย 2>&1 รวม error user ทั่วไปเขียน /var/log ไม่ได้ ถ้าโจทย์บังคับต้องให้ root สร้างไฟล์และ chown ให้
ตรวจ
crontab -l และ journalctl -u cron --since today

ถ้าสคริปต์ไม่มีสิทธิ์ x และห้ามแก้สิทธิ์ ให้เรียกผ่าน interpreter เช่น /bin/bash /home/student/backup.sh

ข้อ 6

เพิ่มดิสก์ใหม่ แล้ว root กลับเต็ม

disk mount df du

เพิ่มดิสก์ใหม่ สร้างพาร์ทิชัน แล้ว mount /dev/sdb1 /mnt/backup หลังรีบูต root เต็ม ขณะที่สคริปต์ยังเขียนลง /mnt/backup วิเคราะห์สาเหตุ กู้พื้นที่คืน ตั้งค่าให้ถาวรด้วย blkid fstab df du และอธิบายความต่างของ df กับ du

ประกอบจาก H72, H28, H42, H4

df -h /mnt/backup             # เห็น /dev/sda2 แปลว่ายังไม่ได้ mount
sudo du -sh /mnt/backup
sudo mkdir /root/hold && sudo mv /mnt/backup/* /root/hold/
sudo blkid /dev/sdb1
sudo nano /etc/fstab
# UUID=xxxx /mnt/backup ext4 defaults,nofail 0 2
sudo mount -a && df -h /mnt/backup
sudo mv /root/hold/* /mnt/backup/
สาเหตุ
mount ด้วยมือไม่อยู่ข้ามรีบูต ไม่มีบรรทัดใน fstab
ต้องย้ายก่อน mount
ไฟล์ที่ค้างในไดเรกทอรีจะถูกซ่อนใต้ mount point แล้วยังกินพื้นที่ root
UUID
ชื่อ sdb อาจเปลี่ยนเมื่อเพิ่มดิสก์ UUID ไม่เปลี่ยน
df กับ du
df ดูทั้ง filesystem จาก superblock du ไล่รวมขนาดไฟล์
ป้องกัน
สคริปต์ตรวจ mountpoint -q ก่อนเขียน
ข้อ 7

ออกแบบพื้นที่ด้วย LVM

LVM quota

บริษัทมีดิสก์ 3 ลูก ต้องเก็บระบบปฏิบัติการ ข้อมูลพนักงาน และ log ซึ่งโตไม่เท่ากัน เสนอการใช้ PV, VG, LV ให้ขยายได้ในอนาคต พร้อมคำสั่ง และวิธีกันไม่ให้ผู้ใช้คนเดียวใช้พื้นที่ข้อมูลจนหมด

ประกอบจาก H35, H4, H6

sudo pvcreate /dev/sdb /dev/sdc /dev/sdd
sudo vgcreate vg_main /dev/sdb /dev/sdc /dev/sdd
sudo lvcreate -n lv_data -L 200G vg_main
sudo lvcreate -n lv_log  -L 50G  vg_main
sudo mkfs.ext4 /dev/vg_main/lv_data
sudo mkfs.ext4 /dev/vg_main/lv_log
sudo lvextend -r -L +30G /dev/vg_main/lv_log
sudo vgs; sudo lvs
PV
ดิสก์จริงทั้ง 3 ลูก
VG
รวมเป็นพูลเดียว พื้นที่ไม่ผูกกับดิสก์ลูกใด
LV
แยก data กับ log คนละ LV log บวมจะไม่ทำให้ข้อมูลเขียนไม่ได้ เหลือพื้นที่ว่างใน VG ไว้ สำหรับขยาย
ขยาย
เพิ่มดิสก์ pvcreate vgextend แล้ว lvextend -r ทำขณะ mount อยู่ได้
Quota
ใส่ usrquota ใน fstab ของ lv_data แล้ว quotacheck -cum /data quotaon /data edquota -u alice ตั้ง soft และ hard limit เต็มแล้วเขียนไม่ได้ ไม่กระทบคนอื่น
ข้อ 8

ตั้ง web server ให้ปลอดภัยและตรวจย้อนหลังได้

user sudo apt systemd cron log

บริษัทจะติดตั้ง nginx มี admin1 เป็นผู้ดูแล dev1 และ dev2 เป็นนักพัฒนาที่ต้องแก้ไฟล์เว็บได้แต่ไม่มีสิทธิ์ผู้ดูแลเกินจำเป็น เว็บต้องเริ่มเองตอนบูต มี backup ทุกวัน 01:00 อธิบายพร้อมคำสั่ง ตั้งแต่สร้างผู้ใช้ กลุ่ม sudo ติดตั้ง จัดการ service ตั้ง cron จนถึงตรวจ log เมื่อเว็บล่ม

ประกอบจาก I59, I4, I35, I44

sudo groupadd webdev
sudo useradd -m -s /bin/bash -G sudo admin1
sudo useradd -m -s /bin/bash -G webdev dev1
sudo useradd -m -s /bin/bash -G webdev dev2
sudo apt update && sudo apt install -y nginx
sudo systemctl enable --now nginx
sudo chown -R root:webdev /var/www/html
sudo find /var/www/html -type d -exec chmod 2775 {} +
sudo find /var/www/html -type f -exec chmod 664 {} +
sudo visudo -f /etc/sudoers.d/webdev
# %webdev ALL=(root) /usr/bin/systemctl reload nginx
sudo crontab -e
# 0 1 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
ผู้ใช้
dev เข้ากลุ่ม webdev ไม่เข้ากลุ่ม sudo ถ้าเพิ่มทีหลังใช้ -aG
sudo
ให้ dev แค่ reload nginx ผ่าน visudo -f ซึ่งตรวจ syntax ก่อนบันทึก
service
enable คือเปิดตอนบูต --now คือเปิดทันที
ตรวจ
systemctl status nginx, journalctl -u nginx, /var/log/nginx/error.log, /var/log/backup.log
ใบงาน

ใบงานที่ทำมาแล้ว ตรงกับข้อสอบข้อไหน

ใบงานทักษะที่ใช้ตอบข้อ
ค้นหา filefind -perm 640 -size +10M -mtime -31, 6
softlink / hardlinkinode, ลบต้นฉบับ, ข้ามพาร์ทิชัน1
Pipe และ sed / awkgrep sort uniq และ awk รวมยอด2
PATH, alias, .bashrcexport ใน .bashrc3
Process list / killps kill &3
Argument + Condition, Exit Status-f, $?, exit4
วนลูปสร้างไฟล์, ฟังก์ชันfor printf -x4
ใบงานทักษะที่ใช้ตอบข้อ
Backup / Restoretar -czf -xzvf log5
Crontab & Log*/3 * * * *, journalctl5, 8
เพิ่ม disk, mountfdisk mkfs blkid fstab6
สร้าง user, sudo groupuseradd -m usermod -aG id8
install sshapt enable --now status8
ท้ายเล่ม

เช็กลิสต์คืนก่อนสอบ

ต้องเขียนได้โดยไม่ดูโน้ต

ติ๊กเมื่อเขียนได้เอง เบราว์เซอร์จำไว้ให้

ประโยคสั้นที่ควรจำ

ลบไฟล์ได้ไหมดู w+x ของไดเรกทอรี
hard linkชี้ inode ข้ามพาร์ทิชันไม่ได้
PATHซ้ายไปขวา ตัวแรกชนะ
ปิด terminalSIGHUP ใช้ nohup
[[ ]]ไม่ split, มี pattern และ regex
cronไม่มี environment ใช้ full path
ว่างแต่เขียนไม่ได้inode, quota, คนละ filesystem
UID 0เท่ากับ root

กด K เพื่อซ้อมด้วยแฟลชการ์ด