รหัสข้อผิดพลาดของ ShellCheck ที่พบบ่อย มักเกิดจากพฤติกรรมเฉพาะของ Shell Script เรื่อง Word Splitting, การดักจับ Exit Status, ขอบเขตตัวแปร และไวยากรณ์เฉพาะระบบ (Bashisms)
1. SC2086: Double quote to prevent globbing and word splitting
สาเหตุ
ไม่ใส่เครื่องหมายคำพูด (Double quotes) ครอบตัวแปร ทำให้ Shell ทำการตัดคำตามช่องว่าง (Word Splitting) และขยาย Wildcard เช่น * (Globbing) หากตัวแปรมีเว้นวรรคหรือเป็นค่าว่าง สคริปต์จะทำงานผิดพลาดทันที
- โค้ดที่ผิด
filename="my report.txt" rm $filename # ผลลัพธ์: Shell จะมองเป็นสองอาร์กิวเมนต์คือ `rm my` และ `report.txt` - วิธีแก้
rm "$filename"
ข้อยกเว้น: หากตั้งใจให้เกิด Word Splitting เพื่อแยกข้อความเป็นหลาย Argument ให้ใส่ Directive ปิดเฉพาะบรรทัดนั้น
# shellcheck disable=SC2086 ./app $CLI_ARGS
2. SC2181: Check exit code directly with e.g. ‘if mycmd;’, not indirectly with $?
สาเหตุ
ตรวจสอบความสำเร็จของคำสั่งผ่านตัวแปร $? ในบรรทัดถัดไป การทำแบบนี้เสี่ยงต่อการถูกแทรกแซง เพราะหากมีคำสั่งอื่นหลุดมาระหว่างกลาง ค่า $? จะเปลี่ยนไปทันที และทำให้อ่านโค้ดเข้าใจยากขึ้น
- โค้ดที่ผิด
grep "ERROR" /var/log/syslog if [ $? -eq 0 ]; then echo "Found error" fi - วิธีแก้
นำคำสั่งไปใส่ไว้หลังifโดยตรงif grep -q "ERROR" /var/log/syslog; then echo "Found error" fi
3. SC2154: Variable is referenced but not assigned
สาเหตุ: มีการเรียกใช้ตัวแปรที่ ShellCheck ตรวจไม่พบการประกาศค่าภายในไฟล์ มักเกิดจากการสะกดชื่อตัวแปรผิด หรือเป็นตัวแปรที่รับมาจาก Environment ภายนอก
- โค้ดที่ผิด
target_dir="/tmp" rm -rf "${tagret_dir}"/* # พิมพ์ชื่อตัวแปรผิด กลายเป็นค่าว่าง นำไปสู่ rm -rf /* - วิธีแก้
- แก้ไขการสะกดชื่อตัวแปรให้ตรงกันหากเป็นตัวแปร Environment ภายนอก ให้กำหนดค่า Default Fallback หรือใส่คอมเมนต์บอก ShellCheck
# แบบที่ 1: กำหนดค่าปลอดภัยหากไม่มีตัวแปร target_dir="${TARGET_DIR:?Target directory must be set}"# แบบที่ 2: คอมเมนต์ปิดการเตือนเฉพาะตัวแปร # shellcheck disable=SC2154 printf "Deploying to: %s\n" "$DEPLOY_ENV"
4. SC2164: Use ‘cd … || exit’ or ‘cd … || return’ in case cd fails
สาเหตุ
ใช้คำสั่ง cd โดด ๆ โดยไม่มีเงื่อนไขรองรับกรณีที่ไดเรกทอรีนั้นไม่มีอยู่จริง ทำให้คำสั่งถัดไปถูกรันบนโฟลเดอร์เดิมที่ไม่ได้ตั้งใจ
- โค้ดที่ผิด
cd /var/www/build rm -rf ./* # หากเข้าโฟลเดอร์ไม่ได้ จะทำการลบไฟล์ทั้งหมดในโฟลเดอร์ปัจจุบันแทน - วิธีแก้
cd /var/www/build || exit 1 rm -rf ./*
5. SC2034: Variable appears unused. Verify use (or export if used externally)
สาเหตุ
มีการประกาศตัวแปรและกำหนดค่า แต่ไม่มีการเรียกใช้ที่ใดเลยในสคริปต์ มักเกิดจากการลืมใช้งาน สะกดชื่อตัวแปรตอนเรียกใช้ไม่ตรงกับตอนประกาศ หรือเป็นตัวแปรในไฟล์คอนฟิก
- โค้ดที่ผิด
port=8080 echo "Server starting on port $PORT" # ประกาศตัวพิมพ์เล็ก แต่เรียกตัวพิมพ์ใหญ่ - วิธีแก้
- แก้ไขชื่อตัวแปรให้ตรงกัน หรือลบทิ้งหากไม่จำเป็น
- หากเป็นตัวแปรที่ตั้งใจส่งต่อไปยัง Subprocess ให้ใช้คำสั่ง
export
export APP_PORT=8080- หากเป็นไฟล์รวมตัวแปรคอนฟิก (ไม่ได้ถูกเรียกใช้ในไฟล์นี้โดยตรง)
# shellcheck disable=SC2034 DATABASE_HOST="127.0.0.1"
6. SC3010 / SC3014: In POSIX sh, [[ ]] / == is not supported (Bashisms)
สาเหตุ
ไฟล์ใช้ Shebang เป็น #!/bin/sh หรือระบุว่ารันบน POSIX Shell แต่มีการใช้ฟีเจอร์เฉพาะของ Bash เช่น วงเล็บเหลี่ยมคู่ [[ หรือเครื่องหมาย ==
- โค้ดที่ผิด
#!/bin/sh if [[ "$mode" == "debug" ]]; then echo "Debug active" fi - วิธีแก้
- ปรับให้เป็น POSIX Standard (แนะนำสำหรับพกพาข้ามระบบ)
#!/bin/sh if [ "$mode" = "debug" ]; then echo "Debug active" fi- หรือเปลี่ยน Shebang ไปใช้ Bash หากตั้งใจพึ่งพาฟีเจอร์ของ Bash จริง ๆ
#!/bin/bash
7. SC2002: Useless cat. Consider ‘cmd < file | ..’ or ‘cmd file’ instead
สาเหตุ
การใช้คำสั่ง cat เพื่ออ่านไฟล์แล้วส่งต่อไปยัง Pipe โดยไม่จำเป็น ทำให้สิ้นเปลืองทรัพยากรสร้าง Process ใหม่ขึ้นมาฟรี ๆ
- โค้ดที่ผิด
cat users.txt | grep "admin" cat data.json | jq . - วิธีแก้
grep "admin" users.txt jq . data.json
สรุป Quick Reference การแก้ไข
| รหัสข้อผิดพลาด | คำอธิบายสั้น | วิธีแก้ไขที่ถูกต้อง |
| SC2086 | ลืม Quote ตัวแปร | ครอบตัวแปรด้วย Double Quotes "$var" |
| SC2181 | เช็ค $? หลังคำสั่ง | ยกคำสั่งไปไว้หลัง if หรือ && โดยตรง |
| SC2154 | ตัวแปรไม่ได้ประกาศค่า | เช็คตัวสะกด หรือใช้ ${VAR:-default} |
| SC2164 | cd ลอยๆ เสี่ยงรันผิดที่ | ต่อท้ายด้วย cd path || exit 1 |
| SC2034 | ตัวแปรไม่ได้ถูกใช้ | เช็คตัวพิมพ์เล็ก/ใหญ่ หรือใช้ export |
| SC3010/3014 | ติด Bashism บน sh | เปลี่ยนมาใช้ [ และ = หรือเปลี่ยนเป็น #!/bin/bash |
| SC2002 | Useless cat | ส่งชื่อไฟล์เข้าคำสั่งปลายทางตรงๆ |