bash

bash: ประยุกต์ทำบัตรเลขที่ลำดับ

มีโจทย์คือ ให้สร้างบัตรแบบเรียงเลขที่ ตั้งแต่ ๑ จนถึง ๕๐๐
ตัดสินใจใช้ bash + inkscape เพราะง่ายดี
โดยสมมุติว่าเราได้สร้างเอกสารเป็นไฟล์ inkscape ไว้แล้ว โดยให้ตัวเลขที่จะเรียงให้มีค่าเป็น XXXX เพื่อให้สะดวกในการใช้คำสั่ง grep

โค๊ดที่สร้างขึ้น ทำแบบง่าย ๆ คือรันตัวเลขตั้งแต่ 1-500 แต่รุ่นนี้เป็นรุ่นทดสอบ ทำแค่ 1-10 พอ ขั้นตอนคือ

  • แปลงตัวเลขเป็นเลขไทย ด้วยคำสั่ง awk
  • นำไปแทนที่ในไฟล์ inkscape แล้วทำออกมาเป็นไฟล์ใหม่ ด้วยคำสั่ง sed
  • แล้วสั่งส่งออกมาเป็นไฟล์นามสกุล png ด้วยคำสั่งแบบบรรทัดคำสั่งของ inkscape เอง ด้วยพารามิเตอร์ -e

เกร็ดคำสั่ง find

(ศึกษาเพราะต้องการเอาไฟล์ในคลังของ apt-proxy เฉพาะไฟล์ใหม่ ๆ เลยต้องการลบไฟล์เก่า ๆ ทิ้ง เพื่อให้ขนาดคลังแพ็กเกจเล็กลง)

เริ่มเลยครับ

ต้องการค้นหาไฟล์ชื่อ *Doc*

$ find /PATH/TO/FILE -name '*Doc*'

ค้นหาและลบไฟล์

$ find /PATH/TO/FILE -name '*Doc*' -exec rm {} \;

ค้นหาไฟล์ที่เก่ากว่า 5 วันลงไป

$ find /PATH/TO/FILE -mtime +5

ค้นหาไฟล์เก่าตั้งแต่ 5 วันขึ้นมา

$ find /PATH/TO/FILE -mtime -5

ค้นหาไฟล์เก่ากว่า 1 ปีลงไป และลบไฟล์เหล่านั้นทิ้ง

$ find /PATH/TO/FILE -mtime +365 -exec rm {} \;

*** ใช้ด้วยความระมัดระวังนะครับ ***

วันนี้แค่นี้ก่อนครับ

อ้างอิง

bash: คัดลอกข้อมูลผู้ใช้ไปเครื่องใหม่

ต้องการโอนข้อมูลผู้ใช้ไปเครื่องใหม่

ถ้าเราคัดลอกไฟล์ /etc/passwd /etc/shadow /etc/group /etc/gshadow ไปทับเครื่องใหม่แบบตรง ๆ จะเกิดปัญหาเรื่องผู้ใช้ของระบบจะติดไปด้วย ซึ่งอาจมีค่า UID และ GID ที่ไม่ตรงกัน

ค้นกูเกิลได้วิธีการจากที่นี่ครับ Move or migrate user accounts from old Linux server to a new Linux server

เขาใช้หลักการที่ว่า UID ของผู้ใช้ทั่วไป จะมีค่ามากกว่า 1000 (ของ RedHat คือ 500) และใช้ awk เป็นตัวกรอง

bash tips: เกร็ดการลบไฟล์

ลูกน้องเอาธัมบ์ไดรฟ์มาให้หาไวรัส
ผลปรากฎว่าพบไฟล์ที่เป็นนามสกุล exe เป็นจำนวนมากภายใต้ไดเรกทอรี่ย่อยเป็นร้อย
ทางแก้คือสแกนแล้วเก็บชื่อไฟล์ไว้ ตัวอย่างของเนื้อไฟล์ที่ถูกสแกนเก็บไว้ เช่น

13. การค้นหาที่ผิดในสคริปต์

เราใช้พารามิเตอร์ -x ต่อท้ายคำสั่งในบรรทัดแรก

#!/bin/bash -x

จะมีผลว่าเชลล์จะแสดงทุกคำสั่งที่ถูกรันออกมาทางจอภาพ

จบแล้วจ้า

12.ตัวอย่างสคริปต์

12.1 ตัวอย่างสคริปต์ดูรายชื่อไฟล์ในไดเรกทอรีย่อย

#!/bin/bash

function listdir {
    local PAT="$1"
    local ROOT="$2"
    for i in *; do
        if [ -d "$i" ]; then
            local CUR="$ROOT/$i"
            pushd "$i" &>/dev/null
            listdir "$PAT" "$CUR"
            popd &>/dev/null
        fi
    done
    if [ ! -z "$( ls -d $PAT 2>/dev/null )" ]; then
        echo "Directory: $ROOT"
        ls -d $PAT 2>/dev/null
        echo 
    fi
}

if [ -z "$1" ]; then
   echo List file in PATTERN recursively into directories.
   echo Usage: $0 "PATTERN"
   exit
fi
PATTERN="$1"
echo "List $PATTERN"
listdir "$PATTERN" "."

ให้ผลคล้ายคำสั่ง

$ find * -name PATTERN

12.2 ตัวอย่างสคริปต์บีบอัดสำรองข้อมูล

#!/bin/bash          
SRCD="/home/"
TGTD="/var/backups/"
OF=home-$(date +%Y%m%d).tgz
tar -cZf $TGTD$OF $SRCD

12.3 เปลี่ยนชื่อไฟล์ทีละหลายไฟล์

#!/bin/sh
# renna: rename multiple files according to several rules
# written by felix hudson Jan - 2000

#first check for the various 'modes' that this program has
#if the first ($1) condition matches then we execute that portion of the
#program and then exit

# check for the prefix condition
if [ $1 = p ]; then

#we now get rid of the mode ($1) variable and prefix ($2)
  prefix=$2 ; shift ; shift

# a quick check to see if any files were given
# if none then its better not to do anything than rename some non-existent

11. ตัวดำเนินการ (operators) และคำสั่งน่าสนใจ

11.1 ตัวดำเนินการเปรียบเทียบตัวอักษร (String comparison operators)

  • [ "$s1" = "$s2" ] หรือ [ "$s1" == "$s2" ] เป็นจริง ถ้า s1 เท่ากับ s2
  • [ "$s1" != "$s2" ] เป็นจริง ถ้า s1 ไม่เท่ากับ s2
  • [[ "$s1" < "$s2" ]] หรือ [ "$s1" \< "$s2" ] เป็นจริง ถ้า s1 น้อยกว่า s2
  • [[ "$s1" > "$s2" ]] หรือ [ "$s1" \> "$s2" ] เป็นจริง ถ้า s1 มากกว่า s2
  • [ -n "$s1" ] เป็นจริง ถ้า s1 มีค่าใด ๆ
  • [ -z "$s1" ] เป็นจริง ถ้า s1 ไม่มีค่า

11.2 ตัวอย่างการเปรียบเทียบอักษร

#!/bin/bash
S1='string'
S2='String'
if [ "$S1" = "$S2" ]; then
    echo "S1('$S1') is not equal to S2('$S2')"
fi
if [ "$S1" = "$S1" ]; then
    echo "S1('$S1') is equal to S1('$S1')"
fi

11.3 ตัวดำเนินการทางคณิตศาลตร์ (Arithmetic operators)

  • + การบวก
  • - การลบ
  • * การคูณ
  • / การหาร

10.เกร็ดอื่น ๆ

10.1 การสั่งรันสคริปต์และคำสั่ง source

การสั่งรันสคริปต์ในเชลล์ มีเกร็ดคือ

  • ถ้าเราใส่ชื่อสคริปต์พร้อมพาธ เชลล์จะค้นหาสคริปต์จากชื่อเต็มที่เราใส่ เช่น
    $ /bin/ls
  • ถ้าเราใส่ชื่อสคริปต์โดด ๆ เชลล์จะค้นหาสคริปต์จากตัวแปร $PATH โดยไม่สนใจไดเรกทอรีปัจจุบัน เช่น
    $ mycode

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

    $ ./mycode

9.การติดต่อผู้ใช้ (User Interfaces)

9.1 ใช้คำสั่ง select ในการสร้างหัวข้อให้เลือก

#!/bin/bash
OPTIONS="Hello Quit"
select opt in $OPTIONS; do
    if [ "$opt" = "Quit" ]; then
        echo done
        exit
    elif [ "$opt" = "Hello" ]; then
        echo Hello World
    else
        clear
        echo bad option
    fi
done

ตัวอย่างนี้จะสร้างหัวข้อ 1) และ 2) จากตัวแปร OPTIONS เพื่อมาให้เลือก โดยจะวนรอบถามไปเรื่อย ๆ จนกว่าจะพบคำสั่ง exit ให้ออกจากการวนรอบ

9.2 ใช้การตรวจสอบว่ามีการใส่ค่าพารามิเตอร์หรือไม่

#!/bin/bash        
if [ -z "$1" ]; then 
   echo usage: $0 directory
   exit
fi
SRCD=$1
TGTD="/var/backups/"
OF=home-$(date +%Y%m%d).tgz
tar -cZf $TGTD$OF $SRCD

บรรทัดที่ 2 จะตรวจว่ามีการใส่พารามิเตอร์ให้กับโปรแกรมหรือไม่ (if [ -z "$1" ] -z หมายถึงการตรวจสอบว่ามีค่าหรือไม่) ถ้าไม่มีการใส่ค่าพารามิเตอร์ โปรแกรมจะทำคำสั่งในบรรทัดที่ 3 คือแสดงวิธีใช้ ($0 คือชื่อโปรแกรมนี้) และบรรทัดที่ 4 คือออกจากโปรแกรม

8.ฟังก์ชั่น (functions)

ในการใช้งานเชลล์สคริปต์แบบจริงจัง เราจำเป็นต้องเขียนฟังก์ชันเพื่อประโยชน์ในการเรียกใช้งานแบบซ้ำ ๆ เพื่อให้ประหยัดการเขียนโค้ด และให้โค้ดดูง่าย

มีรูปแบบเป็น

function FUNCTION_NAME {
    COMMAND
}

หรือ

FUNCTION_NAME () {
    COMMAND
}

โปรแกรมจะเว้นไม่ถูกเรียกทำงานในช่วงตั้งแต่ชื่อฟังก์ชันจนกระทั่งจบบล็อก { COMMAND }

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

8.1 ตัวอย่างฟังก์ชัน

#!/bin/bash

function quit {
    exit
}

function hello {
    echo Hello!
}

hello
quit
echo foo

ตัวอย่างนี้ บรรทัดที่ 13 คือคำสั่ง echo foo จะไม่ถูกเรียกใช้ เนื่องจากโปรแกรมจะหลุดสู่เชลล์ในบรรทัดที่ 12 คือคำสั่ง quit

Syndicate content