จนถึงตอนนี้คุณพิมพ์คำสั่งทีละบรรทัด — บทนี้จะสอนวิธี “รวมหลายคำสั่งไว้ในไฟล์เดียว” แล้วสั่งทำงานทีเดียวจบ ไม่ต้องพิมพ์ซ้ำ ไม่ต้องจำ ทำซ้ำได้ทุกวัน
🌱 บทนี้เขียนเพื่อคนที่ไม่เคยเขียนโปรแกรมมาก่อนเลยสมมติทุกเช้าคุณต้องทำงานเดิมๆ 5 คำสั่ง: เช็กพื้นที่ดิสก์ → สำรองไฟล์ตั้งค่า → สร้าง user ใหม่ → เคลียร์ log → รีสตาร์ตบริการ ถ้าพิมพ์ทีละบรรทัดทุกวันก็เสียเวลาและพลาดง่าย
shell script คือการเอาคำสั่งทั้งหมดนั้น เขียนเรียงไว้ในไฟล์เดียว แล้วสั่งให้ทำงานทีเดียว เครื่องจะไล่ทำทุกบรรทัดตามลำดับให้เอง
script ก็เหมือน สูตรอาหารที่จดไว้ — แทนที่จะต้องนึกเองทุกครั้งว่า “ตอกไข่ → ตีให้เข้ากัน → ตั้งกระทะ → เทลงไป” คุณเขียนขั้นตอนไว้ครั้งเดียว แล้วใครหยิบสูตรไปทำตามก็ได้ผลเหมือนกันทุกครั้ง ไม่ต้องจำ ไม่ตกหล่นขั้นตอน
เครื่องก็คือ “พ่อครัว” ที่อ่านสูตร (script) แล้วทำตามทีละบรรทัดจากบนลงล่าง
ข้อสอบมักให้เขียน script สั้นๆ ที่ รับ argument และ มี if เช็กเงื่อนไข เช่น “เขียน script ที่รับชื่อมา 1 ตัว ถ้าเป็น start ให้ทำอย่างหนึ่ง ถ้าเป็น stop ให้ทำอีกอย่าง” — ไม่ต้องเก่งเขียนโปรแกรม แค่ครบ 5 อย่างในบทนี้ก็ทำข้อสอบได้
ทุก script ต้องเริ่มด้วยบรรทัดพิเศษที่เรียกว่า shebang หน้าตาแบบนี้:
#!/bin/bash
เครื่องหมาย #! (อ่านว่า “แช-แบง”) ตามด้วย path ของโปรแกรมที่จะใช้รันไฟล์นี้ — ในที่นี้คือ /bin/bash แปลว่า “ขอให้ใช้ bash อ่านและรันไฟล์นี้นะ”
shebang เหมือน ป้ายบอกภาษาบนหน้าปกหนังสือ — บอกล่วงหน้าว่า “เนื้อในเล่มนี้เป็นภาษา bash นะ” เครื่องจะได้เรียกล่ามที่ถูกตัว (bash) มาแปลให้
เซฟไฟล์เป็นนามสกุล .sh เช่น backup.sh เพื่อให้คนอื่นรู้ว่าเป็น script (จริงๆ Linux ไม่บังคับนามสกุล แต่ทำไว้ให้อ่านง่าย)
ถ้ามีบรรทัดว่างหรือมีช่องว่างนำหน้า #! จะใช้งานไม่ได้ ต้องเป็น อักขระแรกสุดของไฟล์ เป๊ะๆ
เขียนไฟล์เสร็จยังรันไม่ได้ทันที เพราะไฟล์ใหม่ ยังไม่มีสิทธิ์ “รันได้” (execute) — จำเรื่องสิทธิ์ r w x จาก M5 ได้ไหม? เราต้องเปิดสิทธิ์ x ให้ก่อน
[student@server1 ~]$ chmod +x backup.sh [student@server1 ~]$ ./backup.sh เริ่มสำรองข้อมูล... เสร็จเรียบร้อย!
chmod +x backup.shเพิ่มสิทธิ์ “รันได้” (x) ให้กับไฟล์ — ทำครั้งเดียวพอ./backup.shสั่งรัน script ที่อยู่ในโฟลเดอร์ปัจจุบันคุณอาจสงสัยว่าทำไมพิมพ์ backup.sh เฉยๆ ไม่ได้ ต้องมี ./ นำหน้า คำตอบอยู่ที่ . = “โฟลเดอร์ที่ฉันอยู่ตอนนี้” (จาก M1)
เวลาคุณพิมพ์ ls เฉยๆ เครื่องจะไปค้นหาคำสั่งจาก “รายชื่อร้านค้าที่รู้จัก” (ตัวแปรชื่อ PATH — รวมที่อยู่ของคำสั่งระบบ) แต่ script ของคุณ ไม่ได้อยู่ในรายชื่อนั้น เครื่องเลยหาไม่เจอ
การใส่ ./ ก็เหมือนชี้นิ้วบอกตรงๆ ว่า “ไฟล์อยู่ตรงนี้ ในห้องที่ฉันยืนอยู่นี่แหละ” เครื่องจะได้ไม่ต้องไปหาที่อื่น
เขียน script เสร็จทุกครั้งให้ทำ 2 อย่าง: (1) chmod +x ชื่อไฟล์ เปิดสิทธิ์รัน แล้ว (2) ./ชื่อไฟล์ เพื่อสั่งรัน — ลืมข้อใดข้อหนึ่ง script ก็ไม่ทำงาน
ข้อความที่ขึ้นต้นด้วย # เครื่องจะ ข้ามไปเลย ไม่ทำงาน — มีไว้ให้ “คน” อ่านเข้าใจว่าบรรทัดถัดไปทำอะไร (ยกเว้น #! บรรทัดแรกที่เป็น shebang พิเศษ)
คำสั่ง echo ก็คือ “พูดออกมา” — พิมพ์ข้อความที่เราใส่ออกมาบนจอ ใช้บอกความคืบหน้าให้ผู้ใช้รู้ว่า script ทำถึงไหนแล้ว
#!/bin/bash # script แรกของฉัน — ทักทายโลก echo "สวัสดีชาว Linux!" echo "นี่คือ script แรกของฉัน"
เมื่อรัน ./hello.sh จะได้ผลว่า:
สวัสดีชาว Linux! นี่คือ script แรกของฉัน
ตัวแปร คือ “กล่องที่ตั้งชื่อไว้” สำหรับเก็บค่าเอาไว้ใช้ซ้ำ — เก็บครั้งเดียว เรียกใช้ได้หลายที่ ถ้าจะแก้ค่าก็แก้ที่เดียว
#!/bin/bash name="สมชาย" echo "สวัสดีคุณ $name" echo "ยินดีต้อนรับคุณ ${name} อีกครั้ง"
name="สมชาย"ตั้งค่า เก็บคำว่า “สมชาย” ไว้ในกล่องชื่อ name$nameเรียกใช้ ค่าในกล่อง — ใส่ $ นำหน้าชื่อ${name}แบบมีปีกกา ความหมายเหมือนกัน แต่ชัดเจนกว่าเมื่อต้องเขียนติดกับตัวอักษรอื่น เช่น ${name}_backupตัวแปรเหมือน กล่องที่แปะป้ายชื่อ ในตู้เก็บของ — ตอนตั้งค่า (name="สมชาย") คือเอาของใส่กล่อง ตอนเรียกใช้ ($name) คือเปิดกล่องเอาของออกมาดู เครื่องหมาย $ ก็คือคำสั่ง “เปิดกล่องนี้ให้ดูหน่อย”
นี่คือ error อันดับหนึ่งของมือใหม่ ต้องเขียนติดกันเป๊ะ:
✅ ถูก: name="สมชาย"
❌ ผิด: name = "สมชาย" (มีเว้นวรรค → bash จะนึกว่า name เป็นคำสั่ง แล้ว error)
นอกจากตั้งค่าตัวแปรเองในไฟล์ เรายัง ส่งค่าเข้าไปตอนสั่งรัน ได้ด้วย ค่าพวกนี้เรียกว่า argument — script จะหยิบมาใช้ผ่านตัวแปรพิเศษ $1 $2 $3 ...
#!/bin/bash echo "ชื่อ script: $0" echo "argument ตัวแรก: $1" echo "argument ตัวที่สอง: $2" echo "ส่งมาทั้งหมด $# ตัว: $@"
รันแบบนี้ (เว้นวรรคคั่นแต่ละค่า):
[student@server1 ~]$ ./greet.sh สมชาย สมหญิง ชื่อ script: ./greet.sh argument ตัวแรก: สมชาย argument ตัวที่สอง: สมหญิง ส่งมาทั้งหมด 2 ตัว: สมชาย สมหญิง
| ตัวแปรพิเศษ | หมายถึง |
|---|---|
$0 | ชื่อของ script เอง (เช่น ./greet.sh) |
$1 $2 $3 | argument ตัวที่ 1, 2, 3 ตามลำดับ |
$# | จำนวน argument ที่ส่งเข้ามาทั้งหมด |
$@ | argument ทุกตัวรวมกัน |
argument เหมือน วัตถุดิบที่ยื่นให้พ่อครัวตอนสั่งอาหาร — สูตร (script) เขียนไว้แล้วว่า “เอาของชิ้นที่ 1 มาทอด” แต่ของชิ้นที่ 1 จะเป็นไก่หรือหมูก็แล้วแต่คุณยื่นให้ตอนนั้น $1 ก็คือ “ของชิ้นที่ 1 ที่เพิ่งยื่นให้”
อีกวิธีรับค่าคือ ถามตอนรันแบบโต้ตอบ ด้วยคำสั่ง read — script จะหยุดรอให้พิมพ์ แล้วเก็บสิ่งที่พิมพ์ลงตัวแปร
#!/bin/bash read -p "พิมพ์ชื่อของคุณ: " name echo "สวัสดีคุณ $name !"
[student@server1 ~]$ ./ask.sh พิมพ์ชื่อของคุณ: สมชาย สวัสดีคุณ สมชาย !
read -p "..."แสดงข้อความถาม (prompt) แล้วรอรับคำตอบnameชื่อตัวแปรที่จะเก็บคำตอบ (ไม่ต้องใส่ $ ตอนรับค่า ใส่ตอนเรียกใช้)บางครั้งเราอยากเอา ผลลัพธ์ของคำสั่ง มาเก็บไว้ในตัวแปร เช่นเก็บวันที่วันนี้ ทำได้ด้วย $( คำสั่ง ) เรียกเทคนิคนี้ว่า command substitution
#!/bin/bash today=$(date +%F) echo "วันนี้คือ $today" echo "กำลังสร้างไฟล์ backup-$today.tar.gz"
วันนี้คือ 2026-06-16 กำลังสร้างไฟล์ backup-2026-06-16.tar.gz
$(date +%F)รันคำสั่ง date +%F (ได้วันที่รูปแบบ ปี-เดือน-วัน) แล้วเอาผลลัพธ์ยัดลงตัวแปร today$(...) เหมือน ใช้คนอื่นไปถามมาก่อน — แทนที่คุณจะเขียนวันที่ลงไปเองตายตัว คุณส่งคนไปถามนาฬิกาว่า “วันนี้ที่เท่าไหร่” แล้วเอาคำตอบกลับมาเก็บ ทุกครั้งที่รันก็จะได้วันที่ปัจจุบันเสมอ
หัวใจของ script ที่ฉลาดขึ้นคือการ ตัดสินใจ — “ถ้าเงื่อนไขเป็นจริง ทำอย่างนี้ ไม่งั้นทำอีกอย่าง” ใช้โครงสร้าง if
if [ เงื่อนไข ]; then # ทำเมื่อเงื่อนไขจริง elif [ เงื่อนไขอื่น ]; then # ทำเมื่อเงื่อนไขที่สองจริง else # ทำเมื่อไม่เข้าเงื่อนไขไหนเลย fi
if ... thenเริ่มเช็กเงื่อนไขelif“ไม่งั้นถ้า...” เช็กเงื่อนไขเพิ่ม (มีหรือไม่มีก็ได้)else“ไม่งั้น...” ทำเมื่อไม่เข้าเงื่อนไขข้างบนเลย (มีหรือไม่มีก็ได้)fiปิดบล็อก if (คือ if สะกดกลับหลัง) — ลืมไม่ได้!วงเล็บเหลี่ยม [ ] จริงๆ คือคำสั่งทดสอบ ต้องมีช่องว่างคั่น:
✅ ถูก: if [ "$x" = "yes" ]; then
❌ ผิด: if ["$x"="yes"]; then (ไม่เว้นวรรค → error)
การเขียนเงื่อนไขต่างกันตามชนิดของสิ่งที่เทียบ:
| ใช้กับ | ตัวเทียบ | ความหมาย |
|---|---|---|
| ตัวเลข | -eq | เท่ากัน (equal) |
-ne | ไม่เท่ากัน (not equal) | |
-lt | น้อยกว่า (less than) | |
-gt | มากกว่า (greater than) | |
-le | น้อยกว่าหรือเท่ากับ | |
-ge | มากกว่าหรือเท่ากับ | |
| สตริง (ข้อความ) | = | ข้อความเท่ากัน |
!= | ข้อความไม่เท่ากัน | |
| ไฟล์ | -f ไฟล์ | มีไฟล์นี้อยู่จริงไหม |
-d โฟลเดอร์ | มีโฟลเดอร์นี้อยู่จริงไหม | |
-z สตริง | สตริงว่างเปล่าหรือเปล่า |
#!/bin/bash age=$1 if [ "$age" -ge 18 ]; then echo "คุณบรรลุนิติภาวะแล้ว" else echo "คุณยังเป็นเยาวชน" fi
รัน ./check-age.sh 20 → ได้ “คุณบรรลุนิติภาวะแล้ว” เพราะ 20 มากกว่าหรือเท่ากับ 18
#!/bin/bash if [ -f /etc/passwd ]; then echo "เจอไฟล์ /etc/passwd" else echo "ไม่เจอไฟล์" fi
เวลาต้องทำงานเดิมกับหลายๆ ค่า เราไม่ต้องเขียนซ้ำ — ใช้ loop วนทำให้
เหมาะเวลามี “รายการ” ชัดเจนว่าจะวนกี่รอบ
#!/bin/bash for i in 1 2 3; do echo "รอบที่ $i" done
รอบที่ 1 รอบที่ 2 รอบที่ 3
for i in ...วนโดยให้ i เปลี่ยนค่าไปทีละตัวในรายการdo ... doneคลุมคำสั่งที่จะทำซ้ำ — done ปิดบล็อก (ลืมไม่ได้!)#!/bin/bash for f in *.txt; do echo "กำลังประมวลผลไฟล์: $f" done
*.txt จะถูกแทนที่ด้วยรายชื่อไฟล์ .txt ทุกไฟล์ในโฟลเดอร์ปัจจุบัน แล้ววนทำทีละไฟล์
#!/bin/bash for user in alice bob charlie; do useradd $user echo "สร้าง user $user เรียบร้อย" done
แทนที่จะพิมพ์ useradd สามรอบ ก็เขียนชื่อทั้งหมดในรายการ แล้วให้ loop วนสร้างให้ทีละคน — ถ้ามี 50 คนก็แค่เพิ่มชื่อเข้าไป
เหมาะเวลายังไม่รู้แน่ว่าจะวนกี่รอบ แต่รู้ว่า “วนไปเรื่อยๆ จนกว่าเงื่อนไขจะเลิกเป็นจริง”
#!/bin/bash count=1 while [ "$count" -le 3 ]; do echo "นับเลข $count" count=$((count + 1)) done
นับเลข 1 นับเลข 2 นับเลข 3
while [ ... ]วนต่อไปตราบที่เงื่อนไขยังจริง (ในที่นี้คือ count ยัง ≤ 3)$((count + 1))คำนวณเลข — เพิ่มค่า count ทีละ 1 ในแต่ละรอบใน while ถ้าลืมเพิ่มค่าตัวนับ (เช่นลืมบรรทัด count=$((count + 1))) เงื่อนไขจะจริงตลอด → วนไม่หยุด เครื่องค้าง! ถ้าเจอแบบนี้กด Ctrl + C เพื่อหยุด
ทุกคำสั่งที่รันเสร็จจะ คืนรหัสบอกผล เรียกว่า exit code เก็บอยู่ในตัวแปรพิเศษ $? — เช็กได้ว่าคำสั่งที่เพิ่งรันสำเร็จหรือไม่
| ค่า $? | หมายถึง |
|---|---|
0 | สำเร็จ — ทุกอย่างเรียบร้อย |
| ไม่ใช่ 0 (เช่น 1, 2, 127) | ผิดพลาด — มีบางอย่างไม่สำเร็จ |
[student@server1 ~]$ ls /etc/passwd /etc/passwd [student@server1 ~]$ echo $? 0 [student@server1 ~]$ ls /ไม่มีไฟล์นี้ ls: cannot access '/ไม่มีไฟล์นี้': No such file or directory [student@server1 ~]$ echo $? 2
คำสั่งแรกสำเร็จ → $? เป็น 0 ส่วนคำสั่งที่หาไฟล์ไม่เจอ → $? ไม่ใช่ 0
exit code เหมือน คำตอบสั้นๆ ของลูกน้องหลังทำงานเสร็จ — ตอบ “เรียบร้อยครับ” (0) หรือ “มีปัญหาครับ” (ไม่ใช่ 0) จำง่ายๆ ว่า 0 = ดี (ผิดจากชีวิตประจำวันที่ 0 มักแปลว่าแย่)
ใน script เราใช้ exit 0 เพื่อจบงานแบบ “สำเร็จ” หรือ exit 1 เพื่อจบแบบ “มีปัญหา” ให้คนหรือ script อื่นที่เรียกเราเอาไปเช็กต่อได้
#!/bin/bash if [ -f /etc/passwd ]; then echo "เจอไฟล์ — สำเร็จ" exit 0 else echo "ไม่เจอไฟล์ — ล้มเหลว" exit 1 fi
รวมทุกอย่างในบทนี้: รับชื่อ user เข้ามา 1 ตัว แล้วเช็กว่ามี user นั้นอยู่ในระบบหรือไม่
#!/bin/bash # เช็กว่ามี user ตามชื่อที่ส่งมาในระบบหรือไม่ # ขั้นที่ 1: เช็กว่าส่งชื่อมาหรือเปล่า if [ "$#" -ne 1 ]; then echo "วิธีใช้: $0 <ชื่อ-user>" exit 1 fi username=$1 # ขั้นที่ 2: ค้นชื่อในไฟล์ /etc/passwd if grep -q "^$username:" /etc/passwd; then echo "✅ มี user '$username' อยู่ในระบบ" exit 0 else echo "❌ ไม่พบ user '$username'" exit 1 fi
ลองรันสองแบบ:
[student@server1 ~]$ chmod +x check-user.sh [student@server1 ~]$ ./check-user.sh root ✅ มี user 'root' อยู่ในระบบ [student@server1 ~]$ ./check-user.sh ผีไม่มีจริง ❌ ไม่พบ user 'ผีไม่มีจริง'
"$#" -ne 1ถ้าจำนวน argument ไม่เท่ากับ 1 แสดงวิธีใช้แล้วออกด้วย exit 1grep -q "^$username:"ค้นบรรทัดที่ขึ้นต้นด้วยชื่อ user ในไฟล์ /etc/passwd (-q = เงียบ ไม่ต้องแสดงผล แค่บอกเจอ/ไม่เจอผ่าน exit code)script เดียวนี้รวม: shebang, comment, ตัวแปร, argument ($1 $#), if/else, การค้นด้วย grep, และ exit code — นี่คือทรงที่ข้อสอบ RHCSA ชอบออก
name="ค่า" ติดกัน — ถ้าเขียน name = "ค่า" (มีเว้นวรรค) bash จะนึกว่า name เป็นคำสั่งแล้ว error ทันที[ "$x" = "yes" ] ไม่ใช่ ["$x"="yes"] เพราะ [ จริงๆ คือคำสั่ง ต้องมีช่องว่างคั่นเสมอPermission denied — ต้อง chmod +x ชื่อไฟล์ ก่อนทุกครั้งbackup.sh เฉยๆ จะขึ้น command not found เพราะเครื่องหาไม่เจอ — ต้องใส่ ./backup.sh ชี้ว่าไฟล์อยู่ในโฟลเดอร์นี้if ต้องปิดด้วย fi เปิด for/while ต้องปิดด้วย done — ลืมแล้วจะขึ้น syntax error: unexpected end of filename=... (ไม่มี $) แต่เรียกใช้ต้อง $name (มี $) — สลับกันบ่อย| สิ่งที่ต้องรู้ | เขียนอย่างไร |
|---|---|
| บรรทัดแรก (shebang) | #!/bin/bash |
| comment (เครื่องข้าม) | # ข้อความ |
| แสดงข้อความ | echo "ข้อความ" |
| ตั้งตัวแปร | name="ค่า" (ห้ามเว้นวรรครอบ =) |
| เรียกใช้ตัวแปร | $name หรือ ${name} |
| argument / ชื่อ script | $1 $2 / $0 |
| จำนวน / ทุก argument | $# / $@ |
| ถามผู้ใช้ | read -p "ถาม: " ตัวแปร |
| เก็บผลคำสั่ง | today=$(date +%F) |
| เงื่อนไข | if [ เงื่อนไข ]; then ... else ... fi |
| เทียบตัวเลข | -eq -ne -lt -gt -le -ge |
| เทียบสตริง | = != |
| เทียบไฟล์ | -f มีไฟล์ -d มีโฟลเดอร์ -z สตริงว่าง |
| วนตามรายการ | for i in 1 2 3; do ... done |
| วนตามเงื่อนไข | while [ เงื่อนไข ]; do ... done |
| ผลคำสั่งล่าสุด | $? (0 = สำเร็จ) |
| จบ script | exit 0 สำเร็จ / exit 1 ผิดพลาด |
| ทำให้รันได้ + รัน | chmod +x ไฟล์.sh แล้ว ./ไฟล์.sh |
เขียนไฟล์ .sh ที่มี shebang → ใช้ตัวแปรและรับ argument เป็น → เขียน if เช็กเงื่อนไขและ for/while วนซ้ำได้ → chmod +x แล้วรันด้วย ./ เท่านี้คุณก็เขียน script อัตโนมัติงานซ้ำๆ และทำข้อ scripting ในห้องสอบได้แล้ว!