ShellCheck คือเครื่องมือ Static Analysis (Linter) แบบโอเพนซอร์สสำหรับ Shell Script พัฒนาด้วยภาษา Haskell โดย Vidar Holen จุดประสงค์หลักคือช่วยค้นหาข้อผิดพลาดทางไวยากรณ์ (Syntax Errors), จุดเสี่ยงด้านความปลอดภัย (Security Vulnerabilities), ปัญหาการพกพาข้ามระบบ (Portability / Bashisms), และพฤติกรรมที่ไม่คาดคิดของสคริปต์ก่อนนำไปรันจริงบน Production
ทำไม Shell Script จึงต้องการ Linter อย่าง ShellCheck?
Shell Script (ไม่ว่าจะเป็น sh, bash, หรือ dash) เป็นภาษาที่ยืดหยุ่นสูงและไม่มีกระบวนการ Compilation ทำให้ข้อผิดพลาดหลายอย่างไม่แสดงตัวออกมาจนกว่าเงื่อนไขใน Runtime จะทำงานจริง
- ไม่มี Type Safety และจัดการช่องว่าง (Whitespace) ซับซ้อน
ข้อผิดพลาดเล็กน้อย เช่น การลืมครอบเครื่องหมายคำพูดรอบตัวแปร ($filevs"$file") อาจทำให้คำสั่งธรรมดากลายเป็นช่องโหว่ร้ายแรง - พฤติกรรมที่แตกต่างกันตามระบบ
สคริปต์ที่รันผ่านบนเครื่องพัฒนาที่เป็น macOS หรือ Ubuntu อาจพังทันทีเมื่อนำไปรันบน Alpine Linux ใน Docker เพราะเผลอใช้ฟีเจอร์เฉพาะของ Bash - ดักจับคำสั่งอันตราย
ป้องกันอุบัติเหตุร้ายแรง เช่น การเขียนคำสั่งลบไฟล์ที่ขยายค่าผิดพลาดกลายเป็นrm -rf /
ปัญหาคลาสสิกที่ ShellCheck ช่วยตรวจจับ
1. การไม่ครอบ Double Quotes รอบตัวแปร (Quoting issues)
# โค้ดที่ผิด:
rm -rf $target_dir/*
# ShellCheck แจ้งเตือน: SC2086: Double quote to prevent globbing and word splitting.
# หาก $target_dir ว่างเปล่า คำสั่งจะกลายเป็น `rm -rf /*` ทันที
# โค้ดที่ถูกต้อง:
rm -rf "${target_dir:?}"/*
2. การเขียนเงื่อนไขเปรียบเทียบผิดพลาด (Incorrect Comparison)
# โค้ดที่ผิด:
if [ $count = 0 ]; then ...
# ShellCheck แจ้งเตือน: SC2070: -eq should be used for numeric comparisons.
# โค้ดที่ถูกต้อง:
if [ "$count" -eq 0 ]; then ...
3. การตรวจจับคำสั่งเฉพาะระบบ (Bashisms Detection)
หากไฟล์สคริปต์ระบุ Shebang เป็น #!/bin/sh แต่เผลอใช้ฟังก์ชันของ Bash
#!/bin/sh
if [[ $name == "Pitt" ]]; then
echo "Hello"
fi
# ShellCheck แจ้งเตือน:
# SC3010: In POSIX sh, [[ ]] is not supported.
# SC3014: In POSIX sh, == in place of = is not supported.
ระดับความรุนแรงของการแจ้งเตือน (Severity Levels)
ShellCheck แบ่งระดับการตรวจจับออกเป็น 4 ระดับ
| ระดับ (Severity) | คำอธิบาย | ตัวอย่าง |
| Error | ไวยากรณ์ผิดพลาดอย่างร้ายแรง สคริปต์จะทำงานล้มเหลวแน่นอน | ลืมปิด quote, วงเล็บไม่ตรงคู่, ปีกกาผิด |
| Warning | สคริปต์อาจรันผ่าน แต่พฤติกรรมมีโอกาสผิดพลาดสูงใน Runtime | ลืมครอบ quote, การเปรียบเทียบผิดประเภท |
| Info | แนะนำแนวทางปฏิบัติที่ดี หรือลดความกำกวมของคำสั่ง | การใช้ $() แทน backticks (`...`) |
| Style | ข้อเสนอแนะเชิงรูปแบบและความกระชับของโค้ด | ตัวแปรไม่ได้ถูกเรียกใช้ (Unused variable) |
วิธีการติดตั้งและการใช้งาน
1. ติดตั้งผ่าน Package Manager
- macOS (Homebrew)
brew install shellcheck - Debian / Ubuntu
sudo apt-get install shellcheck - Alpine Linux
apk add shellcheck
2. การรันตรวจสอบผ่าน CLI
- ตรวจสอบสคริปต์แบบระบุเชลล์เป้าหมาย:Bash
# บังคับตรวจตามมาตรฐาน POSIX shellcheck -s sh deploy.sh # ตรวจสอบตามมาตรฐาน Bash shellcheck -s bash setup.sh - กำหนดระดับความเข้มงวดในการแจ้งเตือน (เช่น แสดงเฉพาะ Warning ขึ้นไป):Bash
shellcheck -S warning deploy.sh
การผสานรวมเข้ากับกระบวนการทำงาน (Integration)
1. ใช้งานใน VS Code
ติดตั้ง Extension ชื่อ ShellCheck ของ Timon Wong ซึ่งจะไฮไลต์เส้นใต้สีแดง/เหลืองในโค้ดแบบ Real-time พร้อมแสดงรหัสโค้ด (เช่น SC2086) และปุ่ม Quick Fix
2. การควบคุมพฤติกรรมเฉพาะจุด (Inline Directives)
หากมีบรรทัดที่ตั้งใจให้เกิด Word Splitting หรือจำเป็นต้องละเว้นการตรวจ สามารถใส่คอมเมนต์กำกับได้
# shellcheck disable=SC2086
echo $list_of_args
3. การนำเข้า CI/CD Pipeline (ตัวอย่าง GitHub Actions)
ช่วยให้มั่นใจว่าโค้ดทุกชุดที่ Merge เข้าสู่ Repository มีมาตรฐานความปลอดภัย
name: Lint Shell Scripts
on: [push, pull_request]
jobs:
shellcheck:
runs-edge: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run ShellCheck
run: |
shellcheck $(find . -type f -name "*.sh")
ShellCheck เปลี่ยนการเขียนสคริปต์จากการพึ่งพาการลองผิดลองถูก มาเป็นการพัฒนาระบบที่มีการทดสอบเชิงคุณภาพตั้งแต่ต้นทาง ช่วยลดความเสี่ยงต่อเซิร์ฟเวอร์ และประหยัดเวลาในการ Debug ปัญหาที่หาสาเหตุได้ยากในภายหลัง