Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> การเขียนโปรแกรม Bash

เชี่ยวชาญ Shell Tracing: การดีบักการรันคำสั่งทีละขั้นตอน

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

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

  1. How To Enable Shell Script Debugging Mode in Linux – Part 1
  2. How to Perform Syntax Checking Debugging Mode in Shell Scripts – Part 2

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

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

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

#!/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

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

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

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

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

เราสามารถตรวจสอบไวยากรณ์เพื่อแสดงเฉพาะ syntax errors ได้ดังนี้:

$ sudo bash -n sys_info.sh

ถ้าดูเชลล์สคริปต์อย่างละเอียด เราจะพบว่า if statement ขาดคำ 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

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

$ sudo bash -n sys_info.sh

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

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

เราจะเพิ่ม double quote ปิดท้ายในคำสั่ง 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

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

$ sudo bash -x sys_info.sh

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

$ sudo ./sys_info.sh

ความสำคัญของการ Trace การรัน Shell Script

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

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

ความลับอยู่ที่ expression ของ if statement คือ [ "$UID" -ne "$ROOT_ID" ] หากเราไม่ใช้ numerical operator ที่เหมาะสม (-ne ในกรณีนี้ หมายถึง not equal) เราจะจบลงด้วย logical error ที่เป็นไปได้

สมมติเราใช้ -eq (หมายถึงเท่ากับ) นี่จะอนุญาตให้ผู้ใช้ระบบทุกคนรวมถึง root รันสคริปต์ได้ ดังนั้นจึงเป็น logical error

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

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

บรรทัดด้านล่างจะช่วยให้เราพบ logical error นี้ในฟังก์ชันโดยการ trace การรันของมัน:

สคริปต์ที่มี logical error:

#!/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 ROOT_ID ซึ่งคือ 0

$ ./sys_info.sh

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