ในบทความแรกของชุดนี้ คุณสร้างสคริปต์ Bash แรกที่เล็กมาก หนึ่งบรรทัด และสำรวจเหตุผลในการสร้างเชลล์สคริปต์ ในบทความที่สอง คุณเริ่มสร้างเทมเพลตที่ค่อนข้างง่าย ที่สามารถเป็นจุดเริ่มต้นสำหรับโปรแกรม Bash อื่นๆ และเริ่มทดสอบมัน ในบทความที่สาม คุณสร้างและใช้ฟังก์ชัน Help เรียบง่าย และเรียนรู้เกี่ยวกับการใช้ฟังก์ชันและวิธาจัดการตัวเลือกบรรทัดคำสั่ง เช่น -h
บทความที่สี่และบทความสุดท้ายในชุดนี้ จะเจาะลึกถึงตัวแปรและการเริ่มต้นค่า (Initializing) รวมถึงวิธีทำ Sanity Testing (การทดสอบความสมเหตุสมผล) เพื่อช่วยให้แน่ใจว่าโปรแกรมรันภายใต้เงื่อนไขที่เหมาะสม จำไว้ว่า เป้าหมายของชุดนี้คือการสร้างโค้ดที่ทำงานได้ จะใช้เป็นเทมเพลตสำหรับโปรเจกต์โปรแกรมมิ่ง Bash ในอนาคต แนวคิดคือ ทำให้เริ่มโปรเจกต์โปรแกรมมิ่งใหม่ง่ายขึ้น โดยมีองค์ประกอบทั่วไปพร้อมใช้ในเทมเพลตแล้ว
ตัวแปร (Variables)
เชลล์ Bash เหมือนภาษาโปรแกรมทั้งหมด จัดการตัวแปรได้ ตัวแปรคือชื่อสัญลักษณ์ที่อ้างอิงตำแหน่งเฉพาะในหน่วยความจำที่มีค่าบางประการ ค่าของตัวแปรเปลี่ยนแปลงได้ คือ มันเปลี่ยนแปลงได้ (Variable) หากคุณไม่คุ้นเคยกับการใช้ตัวแปร อ่านบทความของผม How to program with Bash: Syntax and tools ก่อนไปต่อ
เสร็จแล้ว? ยอดเยี่ยม! มาดูแนวทางปฏิบัติที่ดี (Good Practices) ตอนใช้ตัวแปร
ผมตั้งค่าเริ่มต้น (Initial values) สำหรับทุกตัวแปรที่ใช้ในสคริปต์ของผมเสมอ คุณจะพบสิ่งนี้ในเทมเพลตสคริปต์ของคุณ ทันทีหลัง Procedures (กระบวนงาน) เป็นส่วนแรกของ Main Program Body (เนื้อหาหลักของโปรแกรม) ก่อนที่จะประมวลผลตัวเลือก การเริ่มต้นตัวแปรแต่ละตัวด้วยค่าที่เหมาะสม สามารถป้องกันข้อผิดพลาดที่อาจเกิดขึ้นกับตัวแปรที่ยังไม่ได้เริ่มต้น ในการเปรียบเทียบหรือการคำนวณคณิตศาสตร์ การวางรายการตัวแปรนี้ในที่เดียว ช่วยให้คุณเห็นตัวแปรทั้งหมดที่ควรอยู่ในสคริปต์และค่าเริ่มต้นของพวกมัน
สคริปต์เล็กของคุณมีตัวแปรเดียวคือ $option จนถึงตอนนี้ ให้ตั้งค่ามันโดยแทรกบรรทัดต่อไปนี้ตามที่แสดง:
################################################################################
################################################################################
# Main program #
################################################################################
################################################################################
# Initialize variables
option=""
################################################################################
# Process the input options. Add options as needed. #
################################################################################
ทดสอบเพื่อให้แน่ใจว่าทุกอย่างทำงานเหมือนเดิม และไม่มีอะไรเสียหายจากการเปลี่ยนแปลงนี้
ค่าคงที่ (Constants)
ค่าคงที่ก็เป็นตัวแปรด้วย—อย่างน้อยก็ควรจะเป็น ใช้ตัวแปรทุกที่ที่เป็นไปได้ในโปรแกรม CLI แทนค่าที่ฮาร์ดโค้ด (Hard-coded values) แม้คุณคิดว่าจะใช้ค่าที่เฉพาะเจาะจง (เช่น ชื่อไดเรกทอรี ชื่อไฟล์ หรือสตริงข้อความ) เพียงครั้งเดียว ให้สร้างตัวแปรและใช้มันแทนที่จะวางชื่อฮาร์ดโค้ดไว้
ตัวอย่างเช่น ข้อความที่พิมพ์เป็นส่วนหนึ่งของ Main Body ของโปรแกรม คือ สตริงลิเทอรัล (String Literal) echo "Hello world!" เปลี่ยนให้เป็นตัวแปร ก่อน เพิ่มคำสั่งต่อไปนี้ในส่วนการเริ่มต้นตัวแปร:
Msg="Hello world!"
และตอนนี้ เปลี่ยนบรรทัดสุดท้ายของโปรแกรม จาก:
echo "Hello world!"
เป็น:
echo "$Msg"
ทดสอบผลลัพธ์
การตรวจสอบความสมเหตุสมผล (Sanity Checks)
Sanity Checks คือการทดสอบเงื่อนไขที่ต้องเป็นจริง เพื่อให้โปรแกรมทำงานถูกต้อง เช่น: โปรแกรมต้องรันโดยผู้ใช้ root หรือต้องรันบน Distribution และ Release เฉพาะของ Distro นั้น เพิ่มการตรวจสอบว่าผู้ใช้ที่รันเป็น root ในโปรแกรมเทมเพลตง่ายๆ ของคุณ
การทดสอบว่าผู้ใช้ root เป็นผู้รันโปรแกรม นั้นง่าย เพราะโปรแกรมรันภายใต้ผู้ใช้ที่เปิดมัน
คำสั่ง id ใช้ระบุ User ID (UID) แบบตัวเลขที่โปรแกรมรันอยู่ มันให้ข้อมูลหลายอย่างเมื่อใช้โดยไม่มีตัวเลือก:
[student@testvm1 ~]$ id
uid=1001(student) gid=1001(student) groups=1001(student),5000(dev)
ใช้ตัวเลือก -u จะคืน UID ของผู้ใช้เพียงอย่างเดียว ซึ่งใช้ง่ายในโปรแกรม Bash ของคุณ:
[student@testvm1 ~]$ id -u
1001
[student@testvm1 ~]$
เพิ่มฟังก์ชันต่อไปนี้ลงในโปรแกรม ผมเพิ่มหลัง Procedure Help แต่คุณวางได้ที่ไหนก็ได้ในส่วน Procedures ตรรกะคือ ถ้า UID ไม่ใช่ศูนย์ ซึ่งเป็น UID ของผู้ใช้ root เสมอ โปรแกรมจะออก:
################################################################################
# Check for root. #
################################################################################
CheckRoot()
{
if [ `id -u` != 0 ]
then
echo "ERROR: You must be root user to run this program"
exit
fi
}
ตอนนี้ เรียก Procedure CheckRoot ก่อนการเริ่มต้นตัวแปร ทดสอบนี้ ก่อนรันโปรแกรมเป็นผู้ใช้ student:
[student@testvm1 ~]$ ./hello
ERROR: You must be root user to run this program
[student@testvm1 ~]$
จากนั้นเป็นผู้ใช้ root:
[root@testvm1 student]# ./hello
Hello world!
[root@testvm1 student]#
คุณอาจไม่จำเป็นต้องใช้ Sanity Test นี้เสมอไป ดังนั้น ให้คอมเมนต์การเรียก CheckRoot ออก แต่ทิ้งโค้ดทั้งหมดไว้ในเทมเพลต เพื่อที่ในโปรแกรมอนาคต คุณแค่ต้องเอาคอมเมนต์การเรียกออก
โค้ด (The Code)
หลังจากทำการเปลี่ยนแปลงตามที่ระบุข้างต้น โค้ดของคุณควรจะเป็นแบบนี้:
#!/usr/bin/bash
################################################################################
# scriptTemplate #
# #
# Use this template as the beginning of a new program. Place a short #
# description of the script here. #
# #
# Change History #
# 11/11/2019 David Both Original code. This is a template for creating #
# new Bash shell scripts. #
# Add new history entries as needed. #
# #
# #
################################################################################
################################################################################
################################################################################
################################################################################
# #
# Copyright (C) 2007, 2019 David Both #
# LinuxGeek46@both.org #
# #
# This program is free software; you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation; either version 2 of the License, or #
# (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program; if not, write to the Free Software #
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #
# #
################################################################################
################################################################################
################################################################################
################################################################################
# Help #
################################################################################
Help()
{
# Display Help
echo "Add description of the script functions here."
echo
echo "Syntax: scriptTemplate [-g|h|v|V]"
echo "options:"
echo "g Print the GPL license notification."
echo "h Print this Help."
echo "v Verbose mode."
echo "V Print software version and exit."
echo
}
################################################################################
# Check for root. #
################################################################################
CheckRoot()
{
# If we are not running as root we exit the program
if [ `id -u` != 0 ]
then
echo "ERROR: You must be root user to run this program"
exit
fi
}
################################################################################
################################################################################
# Main program #
################################################################################
################################################################################
################################################################################
# Sanity checks #
################################################################################
# Are we rnning as root?
# CheckRoot
# Initialize variables
option=""
Msg="Hello world!"
################################################################################
# Process the input options. Add options as needed. #
################################################################################
# Get the options
while getopts ":h" option; do
case $option in
h) # display Help
Help
exit;;
\?) # incorrect option
echo "Error: Invalid option"
exit;;
esac
done
echo "$Msg"
تمرين أخير (A Final Exercise)
คุณอาจสังเกตว่า ฟังก์ชัน Help ในโค้ดของคุณ อ้างอิงฟีเจอร์ที่ไม่อยู่ในโค้ด ในการฝึกฝนครั้งสุดท้าย ให้ลองหาวิธีเพิ่มฟังก์ชันเหล่านั้นเข้าไปในเทมเพลตโค้ดที่คุณสร้าง
สรุป
ในบทความนี้ คุณสร้างฟังก์ชัน 2 ตัว เพื่อทำ Sanity Test ว่าโปรแกรมของคุณรันเป็น root หรือไม่ โปรแกรมของคุณเริ่มซับซ้อนขึ้น ดังนั้นการทดสอบจึงกลายสำคัญขึ้น และต้องการเส้นทางการทดสอบ (Test Paths) มากขึ้นเพื่อให้ครบถ้วน
ชุดนี้มองที่โปรแกรม Bash ขั้นต่ำมาก และวิธีสร้างสคริปต์ขึ้นทีละนิด ผลลัพธ์คือเทมเพลตง่าย ที่สามารถเป็นจุดเริ่มต้นสำหรับสคริปต์ Bash อื่นๆ ที่มีประโยชน์มากขึ้น และมีองค์ประกอบที่มีประโยชน์ ทำให้เริ่มสคริปต์ใหม่ได้ง่าย
ตอนนี้คุณเข้าใจแนวคิดแล้ว: โปรแกรมที่คอมไพล์ (Compiled Programs) จำเป็น และเติมความต้องการสำคัญมาก แตสำหรับซิสแอดมิน จะมีวิธีที่ดีกว่ามีอยู่เสมอ ใช้เชลล์สคริปต์ตอบสนองความต้องการอัตโนมัติของงานคุณ เชลล์สคริปต์เปิดเผย (Open) เนื้อหาและวัตถุประสงค์รู้จักได้ สามารถปรับเปลี่ยนได้ง่าย เพื่อตอบสนองความต้องการที่แตกต่างกัน ผมไม่เคยพบอะไรที่ผมต้องทำในบทบาทซิสแอดมิน ที่ทำไม่ได้ด้วยเชลล์สคริปต์
สิ่งที่คุณสร้างจนถึงตอนนี้ในชุดนี้ เพียงแค่จุดเริ่มต้น เมื่อคุณเขียนโปรแกรม Bash มากขึ้น คุณจะพบโค้ดชิ้นเล็กๆ ที่คุณใช้บ่อย และควรรวมไว้ในเทมเพลตโปรแกรมของคุณ
แหล่งข้อมูล (Resources)
- How to program with Bash: Syntax and tools
- How to program with Bash: Logical operators and shell expansions
- How to program with Bash: Loops
ชุดบทความนี้บางส่วนอิงจาก Volume 2, Chapter 10 ของหลักสูตร Linux เรียนรู้ด้วยตนเอง 3 ส่วน ของ David Both: Using and Administering Linux—Zero to SysAdmin.