bash

เกร็ดคำสั่ง 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

7.การวนรอบ โดยใช้คำสั่ง for, while และ until

คำสั่ง for มีลักษณะคล้าย for ในภาษาไพธอน มีรูปแบบเป็น

for VAR in SCOPE; do
    COMMAND
done

คำสั่ง while มีรูปแบบเป็น

while [ CONDITION ]; do
    COMMAND
done

ตราบใดที่เงื่อนไข CONDITION ยังเป็นจริง ก็จะทำคำสั่ง COMMAND ซ้ำไปเรื่อย ๆ

คำสั่ง until มีความหมายตรงกันข้ามกับ while โดยมีรูปแบบเป็น

until [ CONDITION ]; do
    COMMAND
done

คือจะทำคำสั่ง COMMAND จนกว่าเงื่อนไข CONDITION จะเป็นจริง

7.1 ตัวอย่าง for

#!/bin/bash
for i in $( ls ); do
    echo item: $i
done

เป็นการนำผลลัพธ์ของคำสั่ง ls ไปเป็นตัวแปรชั่วคราวในการกำหนดขอบเขตให้กับตัวแปร i ในคำสั่ง for

ในที่นี้จะทำการแสดงผลว่า item: FILENAME ...

Syndicate content