สร้าง CLI แรกของคุณด้วย Shell Script

Cocodev
Lotus’s IT

--

บทความนี้จะพาไปสร้าง CLI เป็นของตัวเอง สามารถนำไปเป็นปรับใช้กับงานอื่นๆ หรือสามารถใช้งาน command, option และ help รวมถึงเทคนิคการ export PATH, Dotfile และชนิดของ shell

CLI (Command Line Interface)

CLI (Command Line Interface) คือแอปพลิเคชันซอฟต์แวร์ที่ช่วยให้ผู้ใช้สามารถติดต่อกับโปรแกรมโดยใช้คำสั่งที่พิมพ์ผ่านหน้าจอคำสั่ง (Text-based) ซึ่งต่างจากหน้าจอผู้ใช้แบบกราฟิก (GUI) โดย CLI ทำงานใน Terminal หรือ Console ซึ่งเหมาะกับงาน software develoment, network และงาน system เนื่องจากมีประสิทธิภาพสูงและสามารถทำ automate ต่าง ๆ ผ่านสคริปต์ได้. CLI ที่นิยมเช่น Git, ตัวจัดการแพ็คเกจเช่น apt หรือ npm หรือแม้แต่ command พื้นฐานอย่าง ls, rm and mkdir และอื่นๆ

ข้อดีของ Command Line Interface (CLI)
1. Automate: CLI ช่วยในการสร้างสคริปต์และการทำงานอัตโนมัติ, เพิ่มประสิทธิภาพในการดำเนินการงานหรือการบริหารจัดการระบบ.
2. Light weight: CLI มีการใช้ทรัพยากรน้อยกว่า GUI, ทำให้เหมาะสำหรับการใช้งานในสภาพแวดล้อมที่ทรัพยากรมีจำกัด และต้องการความรวดเร็ว
3. Flexibility: ผู้ใช้สามารถทำงานด้วยคำสั่งที่กำหนดเอง, เพิ่มความยืดหยุ่นในการปรับแต่งการทำงาน.

CLI มีข้อดีเหล่านี้ทำให้เป็นเลือกที่น่าสนใจสำหรับผู้ใช้ที่ต้องการความรวดเร็ว, ความยืดหยุ่น, และความสามารถในการทำงานอัตโนมัติ.

เชื่อว่าผู้เริ่มเป็น developer ทุกคนต้องเคยใช้ Command-Line Interface (CLI) มามากพอสมควร ยกตัวอย่างเช่น

git commit -m "inint cli project"

git ก็เป็น CLI อันหนึ่งซึ่ง 1 บรรทัดนี้ประกอบด้วย

  • git commit เป็น command ใช้เพื่อทำการ commit ความเปลี่ยนแปลงใน code ของโปรเจค
  • -m เป็น option ใช้เพื่อระบุข้อความ commit ที่อธิบายถึง code ที่ถูก เพิ่ม/แก้ไข
  • init cli projectเป็น value ที่อธิบายถึงการ commit นี้, ซึ่งควรเป็นอธิบายที่สั้นและกระชับเกี่ยวกับ code

Design your own CLI

ก่อนอื่นเรามา design interface ของ CLI กันก่อน

ให้โจทย์เราคือสร้าง CLI ชื่อ thaitoolsและ command idcard สำหรับ generate เลขบัตรประชน

  1. CLI name: thaitools
  2. Command: idcard สำหรับ gen บัตรประชาชน
  3. Option: -n,--num-cards เป็น option สำหรับระบุ จำนวน id ที่เราอยากให้ gen
  4. Option: -f, --fileเป็น option สำหรับระบุ path file ให้เขียนลง file
  5. Option: -h, --helpแสดงคู่มือการใช้งาน CLI

ตัวอย่าง CLI ที่เราอยากให้เป็น

# Terminal
thaitools idcard -n 5 -f ~/Desktop/idCards.txt

# output
Generated Card Number 1: 4525559316227
Generated Card Number 2: 7490467785663
Generated Card Number 3: 4142313773738
Generated Card Number 4: 5250857640495
Generated Card Number 5: 2620161605665

Setup script

1. สร้าง file สำหรับ CLI ชื่อ thaitools ใช้คำสั่ง touch <file_name>

# Terminal
touch thaitools

2. change mode ให้เป็น executable file หรือ Unix Executable File

# Terminal
chmod +x thaitools

เราสามารถ ข้ามขั้นตอนนี้ถ้าเราต้องการสร้างแค่ shell script file โดยการ run ผ่านคำสั่ง `sh thaitools.sh`

3. write code

#!/bin/sh

echo "hello world"

สำหรับระบบ unix หรือ linux ที่เราคุ้นเคยกัน เรามักจะคุ้นตากับ บรรทัดแรกของ script ต่างๆ ขึ้นต้นด้วย #!/bin/bash หรือ #!/bin/sh

ทำไมถึงต้องมี? ก็เพื่อต้องบอกให้รู้ว่า script นี้ควรจะถูก execute ด้วย bash หรือ sh บนระบบ unix หรือ linux รูปแบบของ #! บนบรรทัดแรกของ script ไม่ได้จำกัดอยู่แค่บน bash หรือ sh เท่านั้นแต่ยังรวมไปถึง interpreter ตัวอื่นๆได้ด้วย มันมีชื่อเรียกว่า “Shebang” เราสามารถ execute python , ruby ,node ได้ด้วยการแปะ Shebang ลงไปใน script เช่น

#!/bin/bash
#!/usr/local/bin/ruby หรือ #!/usr/bin/env ruby
#!/usr/local/bin/python หรือ #!/usr/bin/env python
#!/usr/local/bin/node หรือ #!/usr/bin/env node

4. run ทดสอบ script

# Terminal
./thaitools

# output
hello world

ถ้าขึ้น hello world เป็นอันว่า script เราทำงานได้

เริ่มเขียน shell script ให้ generate เลขบัตรประชาชน

ขั้นตอนการสร้างเลขบัตรประชาชนมี 4 ขั้นตอน

  1. Random ตัวเลขอะไรมาก็ได้จำนวน 12 ตัว โดยมีกฎอยู่ว่า ตัวแรกห้ามเป็นเลข 0 หรือ 9 เช่น 189353534573
  2. เอาเลข 12 หลักจากข้อแรกมาคูณกับเลข n — index ของมัน แล้วเอามารวมกัน เช่นจากตัวอย่างก็คือ (113) + (812) + (911) + (310) + (59) + (38) + (57) + (36) + (45) + (54) + (73) + (32) ได้ 427
  3. นำผลลัพธ์จากข้อที่แล้วมา mod หรือหารเอาเศษด้วย 11 เช่น จากตัวอย่างจะได้ 427 mod 11 = 9
  4. นำ 11 ไปลบกับผลลัพธ์จากข้อที่แล้ว จะได้เลขหลักที่ 13 เช่นของเราคือ 9 ได้ 11–9 = 2
  5. เราก็จะสุ่มเลขบัตรขึ้นมาได้เป็น 1893535345732

ChatGPT เสกเป็น code shell script ให้หน่อย…

#!/bin/sh

generate_card_number() {
# Step 1: Random ตัวเลขอะไรมาก็ได้จำนวน 12 ตัว โดยมีกฎอยู่ว่า ตัวแรกห้ามเป็นเลข 0 หรือ 9 เช่น 189353534573
random_number=$(shuf -i 200000000000-899999999999 -n 1)

# Step 2: เอาเลข 12 หลักจากข้อแรกมาคูณกับเลข n - index ของมัน แล้วเอามารวมกัน เช่นจากตัวอย่างก็คือ (1*13) + (8*12) + (9*11) + (3*10) + (5*9) + (3*8) + (5*7) + (3*6) + (4*5) + (5*4) + (7*3) + (3*2) ได้ 427
sum=0
for ((i=0; i<12; i++)); do
digit=${random_number:i:1}
position=$((13 - i))
product=$((digit * position))
sum=$((sum + product))
done

# Step 3: นำผลลัพธ์จาก step2 มา mod หรือหารเอาเศษด้วย 11
remainder=$((sum % 11))

# Step 4: นำ 11 ไปลบกับผลลัพธ์จาก stepที่ 3
thirteenth_digit=$((11 - remainder))

# Step 5: นำผลลัพธ์จาก step4มาต่อกับ step1
echo "${random_number}${thirteenth_digit}"
}
generate_card_number

มาลอง run ทดสอบกัน

# Terminal
./thaitools

# output
2792688255096

ตอนนี้เราสามารถ gen เลขบัตรประชาชนได้แล้ว

สร้าง Command

ตาม design ข้องต้นเราเรียกผ่าน command: cardId สำหรับ gen เลขบัตรประชาชน

.....
# Add command cardId
# if param $1 เท่ากับ command name 'cardId'
if [ "$1" == "cardId" ]; then
# เรียก function สำหรับ gen cardId
card_id=$(generate_card_number)
echo $card_id
else
echo "Invalid command."
fi
# Terminal
./thaitools cardId

# output
2635368457988

สร้าง Option

หลังจากเรามี command cardId เราจะเพิ่มความสามารถให้ command ให้มี option เผื่อให้ dynamic มากขั้น

  1. -n,--num-cards: ระบุ จำนวน id ที่เราอยากให้ gen
  2. -h, --file: ระบุ output เป็น file
#!/bin/bash
# Add Command cardId
# if param $1 เท่ากับ command name 'cardId'
if [ "$1" == "cardId" ]; then
num_cards=1 # Default ให้ generating 1 card ถ้าไม่ระบุ -n option
file_path="" # Default ให้ path ไม่มีค่า หรือ ไม่ต้อง write file

# Loop while หา command-line arguments
while [[ $# -gt 0 ]]; do
case "$1" in
# check arguments เท่ากับ option -n --num-cards
-n|--num-cards)
num_cards="$2"
# shift ไป arguments ถัดไป
shift
;;
# check arguments เท่ากับ option -f|--file
-f|--file)
file_path="$2"
# shift ไป arguments ถัดไป
shift
;;
*)
shift
;;
esac
done

# Generate และ display ตามจำนวนของค่า -n หรือ num_cards
for ((i=0; i<num_cards; i++)); do
card_id=$(generate_card_number)
echo "Generated Card Number $((i+1)): $card_id"

# Check file_path ถ้ามีค่าทำ echo
if [ -n "$file_path" ]; then
# echo หรือ write ข้อมูลลง file
echo "$card_id" >> "$file_path"
fi
done
else
echo "Invalid command."
fi
# Terminal
./thaitools cardId -n 10 -f ~/Desktop/card-numbers.txt
# or
./thaitools cardId -n 10
# or
./thaitools cardId -f ~/Desktop/card-numbers.tx

Help

-h, --help เป็น option ที่ขาดไม่ได้สำหรับทุกๆ CLI ถ้ารู้อยากรู้ว่ามันใช้งานยังไง dev ทุกคนรู้กันว่าพิม -h ก่อนเป็นอันดับแรก เพราะมันคือ document ของ CLI นั้นๆ นั้นเอง แล้วมันเขียนยังไง ไปดู!!!!

#!/bin/bash

# function สำหรับแสดง help
display_help() {
echo "Usage: $0 cardId [OPTIONS]"
echo "Generate Thai id"

echo "Options:"
echo " -n, --num-cards NUM Specify the number of card id to generate (default is 1)."
echo " -f, --file FILE Specify the file to save the card id"
echo " -h, --help Display this help message."
}

# Add Command cardId
# if arguments $1 เท่ากับ command name 'cardId'
if [ "$1" == "cardId" ]; then

# check arguments $2 เท่ากับ -h|--help
case "$2" in
-h|--help)
display_help
exit 0
;;
esac
num_cards=1 # Default ให้ generating 1 card ถ้าไม่ระบุ -n option
file_path="" # Default ให้ path ไม่มีค่า หรือ ไม่ต้อง write file
.....
else
echo "Invalid command."
display_help
fi
# Terminal
./thaitools cardid -h

#output
Invalid command.
Usage: thaitools cardId [OPTIONS]
Generate Thai id
Options:
-n, --num-cards NUM Specify the number of card id to generate (default is 1).
-f, --file FILE Specify the file to save the card id
-h, --help Display this help message.

วิธี export path

เราอยากให้สามารถเรียกใช้ CLI thaitools ที่เราสร้างขึ้นมาจาก directory ไหนก็ได้

  1. ตรวจสอบว่า command line tools เราใช่ shell อะไร
# Terminal
echo $SHELL

# output
/bin/bash or /bin/zs

2. เปิด file Dotfile ซึ่งถ้าเป็น /bin/bash ก็จะเป็น file .bash_profile และ /bin/zsh เป็น .zshrc

# Terminal
open -e ~/.zshrc

เป็นคำสั่งเปิด text editor

3. เพิ่ม path ของ thaitools save file และ restart command line tools

มีอีกวิธี คือการย้าย file thaitools ไปอยู่ใน system path ของเครื่องของคุณ
mv thaitools /usr/local/bin

เป็นอันเสร็จวิธี export path

ลองใช้งาน thaitools ของเรากัน

###################### Finish ##########################

--

--