Trong bài này của series debug shell script, chúng ta sẽ giải thích chế độ debug thứ ba: shell tracing, với ví dụ minh họa cách hoạt động và cách sử dụng.
Phần trước đã làm rõ hai chế độ debug khác: verbose mode và syntax checking mode với ví dụ dễ hiểu cách bật debug shell script ở các chế độ đó.
- Cách bật Shell Script Debugging Mode trên Linux – Phần 1
- Cách thực hiện Syntax Checking Debugging Mode trong Shell Scripts – Phần 2
Shell tracing đơn giản là theo dõi thực thi các lệnh trong shell script. Để bật shell tracing, dùng tùy chọn debug -x.
Điều này chỉ thị shell hiển thị tất cả lệnh và tham số trên terminal khi chúng được thực thi.
Sử dụng script sys_info.sh dưới đây, in tóm tắt ngày giờ hệ thống, số user đăng nhập và uptime. Tuy nhiên chứa lỗi cú pháp cần tìm và sửa.
#!/bin/bash
#script in tóm tắt thông tin hệ thống
ROOT_ID="0"
DATE=`date`
NO_USERS=`who | wc -l`
UPTIME=`uptime`
check_root(){
if [ "$UID" -ne "$ROOT_ID" ]; then
echo "Bạn không được phép chạy chương trình này!"
exit 1;
}
print_sys_info(){
echo "System Time : $DATE"
echo "Number of users: $NO_USERS"
echo "System Uptime : $UPTIME }
check_root
print_sys_info
exit 0
Lưu file và cấp quyền thực thi. Script chỉ chạy được bằng root, dùng sudo:
$ chmod +x sys_info.sh $ sudo bash -x sys_info.sh

Từ đầu ra, quan sát lệnh được thực thi trước khi đầu ra thay thế làm giá trị biến.
Ví dụ, date chạy trước và đầu ra thay thế làm giá trị biến DATE.
Có thể kiểm tra cú pháp chỉ hiển thị lỗi cú pháp:
$ sudo bash -n sys_info.sh

Nếu nhìn kỹ script, nhận ra câu lệnh if thiếu từ khóa đóng fi. Thêm nó và script mới như sau:
#!/bin/bash
#script in tóm tắt thông tin hệ thống
ROOT_ID="0"
DATE=`date`
NO_USERS=`who | wc -l`
UPTIME=`uptime`
check_root(){
if [ "$UID" -ne "$ROOT_ID" ]; then
echo "Bạn không được phép chạy chương trình này!"
exit 1;
fi }
print_sys_info(){
echo "System Time : $DATE"
echo "Number of users: $NO_USERS"
echo "System Uptime : $UPTIME }
check_root
print_sys_info
exit 0
Lưu lại và chạy với root, kiểm tra cú pháp:
$ sudo bash -n sys_info.sh

Kết quả kiểm tra vẫn báo lỗi ở dòng 21. Vẫn còn lỗi cú pháp.
Phân tích kỹ lần nữa, lỗi dòng 21 do thiếu dấu ngoặc kép đóng (") trong lệnh echo cuối cùng trong hàm print_sys_info.
Thêm dấu ngoặc kép đóng trong lệnh echo và lưu. Script sửa đổi:
#!/bin/bash
#script in tóm tắt thông tin hệ thống
ROOT_ID="0"
DATE=`date`
NO_USERS=`who | wc -l`
UPTIME=`uptime`
check_root(){
if [ "$UID" -ne "$ROOT_ID" ]; then
echo "Bạn không được phép chạy chương trình này!"
exit 1;
fi }
print_sys_info(){
echo "System Time : $DATE"
echo "Number of users: $NO_USERS"
echo "System Uptime : $UPTIME" }
check_root
print_sys_info
exit 0
Kiểm tra cú pháp lần nữa.
$ sudo bash -n sys_info.sh
Lệnh trên không xuất ra gì vì script đã đúng cú pháp. Có thể trace thực thi lần 2 và nó chạy tốt:
$ sudo bash -x sys_info.sh


Bây giờ chạy script.
$ sudo ./sys_info.sh


Tầm quan trọng của Shell Script Execution Tracing
Shell script tracing giúp xác định lỗi cú pháp và quan trọng hơn, lỗi logic. Ví dụ hàm check_root trong sys_info.sh xác định user có phải root không, vì script chỉ cho superuser chạy.
check_root(){
if [ "$UID" -ne "$ROOT_ID" ]; then
echo "Bạn không được phép chạy chương trình này!"
exit 1;
fi }
Phép toán điều khiển bởi biểu thức if statement [ "$UID" -ne "$ROOT_ID" ], nếu không dùng toán tử số phù hợp (-ne nghĩa là không bằng), sẽ gây lỗi logic.
Giả sử dùng -eq (bằng), sẽ cho phép mọi user và root chạy script, do đó lỗi logic.
check_root(){
if [ "$UID" -eq "$ROOT_ID" ]; then
echo "Bạn không được phép chạy chương trình này!"
exit 1;
fi }
Lưu ý: Như xem ở đầu series, lệnh built-in set có thể bật debug cho đoạn cụ thể của shell script.
Dòng dưới giúp tìm lỗi logic trong hàm bằng trace thực thi:
Script có lỗi logic:
#!/bin/bash
#script in tóm tắt thông tin hệ thống
ROOT_ID="0"
DATE=`date`
NO_USERS=`who | wc -l`
UPTIME=`uptime`
check_root(){
if [ "$UID" -eq "$ROOT_ID" ]; then
echo "Bạn không được phép chạy chương trình này!"
exit 1;
fi }
print_sys_info(){
echo "System Time : $DATE"
echo "Number of users: $NO_USERS"
echo "System Uptime : $UPTIME" }
# bật/tắt debug cho hàm check_root
set -x ; check_root; set +x ; print_sys_info
exit 0
Lưu file và chạy script, thấy user thường có thể chạy script không sudo như đầu ra dưới. Vì USER_ID là 100 không bằng ROOT_ID = 0.
$ ./sys_info.sh

Đó là tất cả, kết thúc series debug shell script. Form phản hồi dưới dùng để gửi câu hỏi hoặc góp ý về hướng dẫn hoặc toàn bộ series 3 phần.