ค้นหาเว็บไซต์

วิธีติดตามการดำเนินการคำสั่งในเชลล์สคริปต์ด้วยการติดตามเชลล์


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

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

  1. วิธีเปิดใช้งานโหมดดีบักสคริปต์เชลล์ใน Linux - ตอนที่ 1
  2. วิธีดำเนินการตรวจสอบไวยากรณ์โหมดดีบักในเชลล์สคริปต์ - ตอนที่ 2

การติดตามเชลล์หมายถึงการติดตามการดำเนินการคำสั่งในเชลล์สคริปต์ หากต้องการเปิดการติดตามเชลล์ ให้ใช้ตัวเลือกการดีบัก -x

นี่เป็นการสั่งให้เชลล์แสดงคำสั่งทั้งหมดและอาร์กิวเมนต์บนเทอร์มินัลในขณะที่ถูกดำเนินการ

เราจะใช้เชลล์สคริปต์ sys_info.sh ด้านล่าง ซึ่งจะพิมพ์วันที่และเวลาของระบบของคุณ จำนวนผู้ใช้ที่เข้าสู่ระบบ และเวลาทำงานของระบบโดยย่อ อย่างไรก็ตาม มีข้อผิดพลาดทางไวยากรณ์ที่เราจำเป็นต้องค้นหาและแก้ไข

#!/bin/bash
#script to print brief system info

ROOT_ID="0"

DATE=`date`
NO_USERS=`who | wc -l`
UPTIME=`uptime`

check_root(){
    if [ "$UID" -ne "$ROOT_ID" ]; then
        echo "You are not allowed to execute this program!"
        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

บันทึกไฟล์และทำให้สคริปต์ทำงานได้ สคริปต์สามารถรันได้โดยรูทเท่านั้น ดังนั้นให้ใช้คำสั่ง sudo เพื่อรันสคริปต์ดังต่อไปนี้:

chmod +x sys_info.sh
sudo bash -x sys_info.sh

จากเอาต์พุตด้านบน เราสามารถสังเกตได้ว่า คำสั่งจะถูกดำเนินการก่อน ก่อนที่เอาต์พุตจะถูกแทนที่เป็นค่าของตัวแปร

ตัวอย่างเช่น วันที่ ถูกดำเนินการครั้งแรก และเอาต์พุตของมันถูกแทนที่เป็นค่าของตัวแปร DATE

เราสามารถตรวจสอบไวยากรณ์เพื่อแสดงเฉพาะข้อผิดพลาดทางไวยากรณ์ดังต่อไปนี้:

sudo bash -n sys_info.sh 

หากเราพิจารณาเชลล์สคริปต์อย่างมีวิจารณญาณ เราจะพบว่าคำสั่ง if ไม่มีคำปิดท้าย fi ดังนั้นให้เราเพิ่มเข้าไปและสคริปต์ใหม่ควรมีลักษณะดังนี้:

#!/bin/bash
#script to print brief system info

ROOT_ID="0"

DATE=`date`
NO_USERS=`who | wc -l`
UPTIME=`uptime`

check_root(){
    if [ "$UID" -ne "$ROOT_ID" ]; then
        echo "You are not allowed to execute this program!"
        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

บันทึกไฟล์อีกครั้งและเรียกใช้เป็นรูทและทำการตรวจสอบไวยากรณ์:

sudo bash -n sys_info.sh

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

หากเราพิจารณาสคริปต์ในเชิงวิเคราะห์อีกครั้ง ข้อผิดพลาดใน บรรทัด 21 เกิดจากการไม่มีเครื่องหมายคำพูดคู่ปิด ( ) ในคำสั่ง echo สุดท้ายภายใน ฟังก์ชัน print_sys_info

เราจะเพิ่มเครื่องหมายคำพูดคู่ปิดในคำสั่ง echo และบันทึกไฟล์ สคริปต์ที่เปลี่ยนแปลงอยู่ด้านล่าง:

#!/bin/bash
#script to print brief system info

ROOT_ID="0"

DATE=`date`
NO_USERS=`who | wc -l`
UPTIME=`uptime`

check_root(){
    if [ "$UID" -ne "$ROOT_ID" ]; then
        echo "You are not allowed to execute this program!"
        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

ตอนนี้ตรวจสอบสคริปต์ทางวากยสัมพันธ์อีกครั้ง

sudo bash -n sys_info.sh

คำสั่งด้านบนจะไม่สร้างผลลัพธ์ใดๆ เนื่องจากสคริปต์ของเราตอนนี้มีไวยากรณ์ที่ถูกต้องแล้ว เราสามารถติดตามการทำงานของสคริปต์ทั้งหมดเป็นครั้งที่สองได้เช่นกัน และมันควรจะทำงานได้ดี:

sudo bash -x sys_info.sh

ตอนนี้รันสคริปต์

sudo ./sys_info.sh

ความสำคัญของการติดตามการดำเนินการเชลล์สคริปต์

การติดตามสคริปต์เชลล์ช่วยให้เราระบุข้อผิดพลาดทางไวยากรณ์และที่สำคัญกว่านั้นคือข้อผิดพลาดเชิงตรรกะ ยกตัวอย่างฟังก์ชัน check_root ในเชลล์สคริปต์ sys_info.sh ซึ่งมีจุดประสงค์เพื่อตรวจสอบว่าผู้ใช้เป็น root หรือไม่ เนื่องจากสคริปต์ได้รับอนุญาตให้ดำเนินการเท่านั้น โดยผู้ใช้ระดับสูง

check_root(){
    if [ "$UID" -ne "$ROOT_ID" ]; then
        echo "You are not allowed to execute this program!"
        exit 1;
    fi
}

ความมหัศจรรย์ที่นี่ถูกควบคุมโดยนิพจน์ if [ "$UID" -ne "$ROOT_ID" ] เมื่อเราไม่ใช้ตัวดำเนินการตัวเลขที่เหมาะสม ( -ne ในกรณีนี้ ซึ่งหมายถึงไม่เท่ากับ ) เราจึงพบข้อผิดพลาดทางตรรกะที่เป็นไปได้

สมมติว่าเราใช้ -eq ( หมายถึง เท่ากับ) ซึ่งจะอนุญาตให้ผู้ใช้ระบบใดๆ รวมถึงผู้ใช้รูทสามารถรันสคริปต์ได้ ดังนั้นจึงเกิดข้อผิดพลาดเชิงตรรกะ

check_root(){
    if [ "$UID" -eq "$ROOT_ID" ]; then
        echo "You are not allowed to execute this program!"
        exit 1;
    fi
}

หมายเหตุ: ดังที่เราได้ดูไปก่อนหน้านี้เมื่อเริ่มซีรีส์นี้ คำสั่ง set shell ในตัวสามารถเปิดใช้งานการแก้ไขจุดบกพร่องในส่วนใดส่วนหนึ่งของเชลล์สคริปต์ได้

ดังนั้น บรรทัดด้านล่างจะช่วยเราค้นหาข้อผิดพลาดเชิงตรรกะในฟังก์ชันโดยการติดตามการดำเนินการ:

สคริปต์ที่มีข้อผิดพลาดเชิงตรรกะ:

#!/bin/bash
#script to print brief system info

ROOT_ID="0"

DATE=`date`
NO_USERS=`who | wc -l`
UPTIME=`uptime`

check_root(){
    if [ "$UID" -eq "$ROOT_ID" ]; then
        echo "You are not allowed to execute this program!"
        exit 1;
    fi
}

print_sys_info(){
    echo "System Time    : $DATE"
    echo "Number of users: $NO_USERS"
    echo "System Uptime  : $UPTIME"
}

#turning on and off debugging of check_root function
set -x ; check_root;  set +x ;
print_sys_info

exit 0

บันทึกไฟล์และเรียกใช้สคริปต์ เราจะเห็นว่าผู้ใช้ระบบทั่วไปสามารถเรียกใช้สคริปต์ได้โดยไม่ต้อง sudo ดังที่แสดงในผลลัพธ์ด้านล่าง เนื่องจากค่าของ USER_ID คือ 100 ซึ่งไม่เท่ากับราก ROOT_ID ซึ่งก็คือ 0

./sys_info.sh

ตอนนี้ก็มาถึงจุดสิ้นสุดของซีรีส์การดีบักเชลล์สคริปต์แล้ว แบบฟอร์มตอบกลับด้านล่างสามารถใช้เพื่อตอบคำถามหรือข้อเสนอแนะเกี่ยวกับคู่มือนี้หรือซีรีส์ทั้ง 3 ส่วน