Skip to main content

Function Samples

清理目錄裡的 *.gz 檔案

用法: KEEP=100 CleanUp /path/to/dir

CleanUp() {
    dest="$1"
    if [ $dest ];then
        CheckDIR $dest 
        cd $dest
        echo "-> Cleaning up the directory $dest [$(date +'%Y-%m-%d %T')] ..."
        total=$(ls -lt *.gz 2>/dev/null | grep -v "^d" | grep -v "^total" | wc -l)
        echo " [!] The numbers of the existing files: $total"
        tail_num=$(( $total - $KEEP ))
        if [ $tail_num -gt 0 ];then
            for f in $(ls -lt *.gz | grep -v "^d" | grep -v "^total" | tail -$tail_num | awk -F ' ' '{print $9}')
            do
                #echo " [!] Deleted file: $f"
                rm -vf $f
            done
        else
            echo " [!] No need of deletion"
        fi
    fi
}
檢查目錄

用法: CheckDIR /path/to/dir

CheckDIR() {
    echo -n "-> Checking the directory <$1> ...... "
    if [ ! -d  $1 ]
    then
        echo "[Failed]"
        exit 1
    else
        echo "[OK]"
    fi
}
ip 驗證
# Test an IP address for validity:
# Usage:
#      valid_ip IP_ADDRESS
#      if [[ $? -eq 0 ]]; then echo good; else echo bad; fi
#   OR
#      if valid_ip IP_ADDRESS; then echo good; else echo bad; fi
#
function is_ip()
{
    local  ip=$1
    local  stat=1

    if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
        OIFS=$IFS
        IFS='.'
        ip=($ip)
        IFS=$OIFS
        [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 \
            && ${ip[2]} -le 255 && ${ip[3]} -le 255 ]]
        stat=$?
    fi
    return $stat
}
驗證數值型資料
Is_number() {
    # Usage: Is_number ${your-number} 0
    # Type: Number with decimal
    # If the number is invalid, return 0.
    # If not specify, return NULL
    local input err_num re
    input=$1
    err_num=$2
    re="^[0-9]+([.][0-9]+)?$"
    if [[ $input =~ $re ]]; then
        echo $input
    else
        echo $err_num
    fi
}

log_utilization_percent=$(Is_number $raw 0)

# Validate for integer
[[ $port =~ ^-?[0-9]+$ ]] && dosomething
# No minus character
[[ $port =~ ^[0-9]+$ ]] && dosomething
分割線(自動調整寬度)
CL () { 
WORDS=$@; termwidth="$(tput cols)"; padding="$(printf '%0.1s' ={1..500})"; printf '%*.*s %s %*.*s\n' 0 "$(((termwidth-2-${#WORDS})/2))" "$padding" "$WORDS" 0 "$(((termwidth-1-${#WORDS})/2))" "$padding"; 
}

CL "This is Seperator Line"
大小寫轉換
ToUpper() {
    echo $1 | tr "[:lower:]" "[:upper:]"
}

ToLower() {
    echo $1 | tr "[:upper:]" "[:lower:]"
} 
URL 字串編碼
function urlencode() {
    local data
    if [[ $# != 1 ]]; then
        echo "Error: No string to urlencode"
        return 1
    fi
    data="$(curl -s -o /dev/null -w %{url_effective} --get --data-urlencode "$1" "")"
    if [[ $? != 3 ]]; then
        echo "Unexpected error" 1>&2
    else
        echo "${data##/?}"
    fi
    return 0
}

urlencode "$1"

function urldecode() {
    # urldecode <string>

    local url_encoded="${1//+/ }"
    printf '%b' "${url_encoded//%/\\x}"
}
函數回傳字串
  • https://linuxhint.com/return-string-bash-functions/
  • https://www.linuxjournal.com/content/return-values-bash-functions

Example-1: Using Global Variable

function F1()
{
    retval='I like programming'
}

retval='I hate programming'
echo $retval
F1
echo $retval

Example-2: Using Function Command

function F2()
{
    local  retval='Using BASH Function'
    echo "$retval"
}

getval=$(F2)   
echo $getval

Example-3: Using Variable

function F3()
{
    local arg1=$1
    
    if [[ $arg1 != "" ]]; 
    then
        retval="BASH function with variable"
    else
        echo "No Argument"
    fi
}

getval1="Bash Function"
F3 $getval1
echo $retval
getval2=$(F3)
echo $getval2
is_root

用途:檢查是否以 root 帳號執行

is_root()
{
	current_user="`id`"
	case "$current_user" in
		uid=0\(root\)*)
		;;
		*)
			echo "$0: You must have root privileges in order to install ${product_name}"
			echo "su as root and try again"
			echo
			exit 1
		;;
	esac
}

With if-then

if [ ${EUID} -ne 0 ]
then
	exit 1 # this is meant to be run as root
fi

Run_MyCodes
check_os

用途:檢查 OS 版本
範例一

check_os()
{
	if [ -f /etc/redhat-release ];then
		rhel=`grep "^Red Hat Enterprise Linux" /etc/redhat-release`
		centos=`grep "^CentOS" /etc/redhat-release`
		
		release=`cat /etc/redhat-release | cut -d'.' -f1 | awk '{print $NF}'`
		
		if [ ! -z "${rhel}" ];then
			sys="rhel"
		fi

		if [ ! -z "${centos}" ];then
			sys="rhel"
		fi
	fi

	if [ -z "${sys}" -o -z "${release}" ];then
		echo "Can not determine Linux distribution."
		exit 127
	fi
			
	if [ -f /proc/vz/veinfo ];then
	# we are under Virtuozzo
		virtuozzo=1
	else
		virtuozzo=0
	fi
	
	if [ "${VNDEBUG}" ];then
		debugrpm='--rpmverbosity=debug'
	else
		debugrpm=''
	fi
}

範例二

# Detect the platform for different environment.
OS="$(uname)"
case $OS in
    "Linux")
      MAIL_CMD="/bin/mail"
      ;;
    "AIX")
      MAIL_CMD="/usr/bin/mail"
      ;;
    *)
      MAIL_CMD="/bin/mail"
      ;;
esac

範例三

get_linux_distribution ()
{ 
    if [ -f /etc/debian_version ]; then
        DIST="DEBIAN"
        HTTP_DIR="/etc/apache2/"
        HTTP_CONFIG=${HTTP_DIR}"apache2.conf"
        MYSQL_CONFIG="/etc/mysql/mariadb.conf.d/50-server.cnf"
    elif [ -f /etc/redhat-release ]; then
        DIST="CENTOS"
        HTTP_DIR="/etc/httpd/"
        HTTP_CONFIG=${HTTP_DIR}"conf/httpd.conf"
        MYSQL_CONFIG="/etc/my.cnf"
    else
        DIST="OTHER"
        echo 'Installation does not support your distribution'
        exit 1
    fi
}
IsRunning

用途:檢查自身程序是否已經執行中,如果有,程序立即跳離,可避免同一個 script 重複被執行。

IsRunning() {
    if [ ! -e $script_pid ];then
        RUNCOUNT=0
    else
        RUNPID=$(cat $script_pid)
        RUNCOUNT=$(ps -fp $RUNPID | grep -c `basename $0`)
    fi
    #echo $RUNCOUNT

    if [ $RUNCOUNT -eq 0 ];then
        echo $$ > $script_pid
        return 1  # return False
    else
        return 0  # return True
    fi
}

script_pid="/tmp/$(basename $0).$(whoami).pid"
# Check if the program is already running.
if IsRunning
then
    echo "Abort: The program is already running!"
    exit 1
fi
getopts 指令參數
function usage ()
{
	cat <<- EOT
 
  Usage :  ${0##/*/} [options] -t application -q 1024,1055,1077 -m dpggen -u kroybal -r ods [--] 
 
  Options: 
  -d|debug      Bash Debugging Info
  -m|machine	Database host machine
  -t|table	Starting table
  -u|user	User to connect to DB
  -q|quals	Qualifying records to delete
  -r|relation	Database name
  -s|schema     Logical Partition
  -h|help       Display this message
  -v|version    Display script version
 
	EOT
}    # ----------  end of function usage  ----------

#-----------------------------------------------------------------------
#  Handle command line arguments
#-----------------------------------------------------------------------
 
[[ $# -eq 0 ]] && {
	# no arguments
	usage
	exit 1
}

while getopts ":dhm:q:r:s:t:u:v" opt
do
  case $opt in
 
    d|debug    )  set -x;;
    h|help     )  usage; exit 0   ;;
    t|table    )  table=$OPTARG;;
    q|quals    )  quals=$OPTARG;;
    m|machine  )  host=$OPTARG;;
    u|user     )  user=$OPTARG;;
    r|relation )  db=$OPTARG;;
    s|schema   )  schema=$OPTARG;;
    v|version  )  echo "$0 -- Version $ScriptVersion"; exit 0   ;;
 
    \? )  echo -e "\n  Option does not exist : $OPTARG\n"
          usage; exit 1   ;;
 
  esac    # --- end of case ---
done
shift $(($OPTIND-1))
Usage() {
    echo "Usage: $0 [-t <TEXT-Message>] [-n <phone-number>]";
    echo "For example: $0 -t \"Hello, SuperMan\" -n \"085713 457199\" "
}

while getopts "t:n:" o; do
    case "$o" in
        t)
            t=$OPTARG
            ;;
        n)
            n=$OPTARG
            ;;
        \?)
            echo "Invalid option: -$OPTARG"
            Usage
            exit 1
            ;;
        :)
            echo "Option -$OPTARG requires an argument !"
            Usage
            exit 1
            ;;
    esac
done

if [ $OPTIND -ne 5 ]; then
    echo "Invalid options entered !"
    Usage
    exit 1
fi

常用參數代號

[Option]	[Typical meaning]
-a	All, append
-b	Buffer,block size, batch
-c	Command, check
-d	Debug, delete, directory
-D	Define
-e	Execute, edit
-f	File, force
-h	Headers, help
-i	Initialize
-I	Include
-k	Keep, kill
-l	List, long, load
-m	Message
-n	Number, not
-o	Output
-p	Port, protocol
-q	Quiet
-r	Recurse, reverse
-s	Silent, subject
-t	Tag
-u	User
-v	Verbose
-V	Version
-w	Width, warning
-x	Enable debugging, extract
-y	Yes
-z	Enable compression

Without getopts

while [[ "${1}" != "" ]]; do
	case "${1}" in
    	--vertical)    verticle="true" ;;
        --add-txt)     add_txt="true" ;;
        --replace)     replace="true" ;;
        --verify)      verify="true" ;;
    esac
    
    shift 1
done
Pause 暫停

用法: pause

可用於程式開發及偵錯

pause()
{

	local force_pause=$1

	if [ -z $force_pause ]; then
		if test $NONINTERACTIVE; then
			return 0
		fi
	else
		shift
	fi

	[ $# -ne 0 ] && echo -e $* >&2
	echo -e "Press [Enter] to continue...\c " >&2
	read tmp
	return 0
}
Log 訊息
log() {  # classic logger
    local prefix="[$(date +%Y/%m/%d\ %H:%M:%S)]: "
    echo "${prefix} $@" >&2
} 

log "INFO" "a message"
Error 錯誤訊息

用途:輸出錯誤訊息

error()
{
	echo -e "Error: $*!" >&2
	return 0
}
die()
{
	echo
	echo "ERROR: $*"
	echo
	echo "Check the error reason, fix and try again."
	echo "You are welcome to open a support ticket at https://help.4psa.com!"
	echo
	rm -f ${repolocal} local$$
	rm -f /var/lock/subsys/vninstaller
	exit 1
}

die() {
    printf "ERR: %s\n" "$1" >&2
    exit 1
}
[ -e "$SRC" ] || die "Wal colors not found, exiting script. Have you executed Wal before?"


check_deps()
{
	which yum >/dev/null 2>&1
	if [ $? -gt 0 ];then
		echo "yum binary can not be found."
		die "It's not in the system PATH or in a standard location."
	fi
	
	which ifconfig >/dev/null 2>&1
    if [ $? -gt 0 ];then
		yum -y install net-tools >/dev/null 2>&1
		if [ $? -gt 0 ];then	
			echo "ifconfig binary can not be found and package net-tools could not be installed."
			die "It's not in the system PATH or in a standard location."
		fi
	fi
} 
詢問 Yes/No

用法: getyn "Would you like to install WANPIPE now? [y]"

$NONINTERACTIVE  如果程式執行時,不想讓 user 做任何的輸入時,可以為 1
NONINTERACTIVE=1 ,或者 = 空白,以顯示相關的提示訊息

prompt()
{
	if test $NONINTERACTIVE; then
		return 0
	fi

	echo -ne "$*" >&2
	read CMD rest
	return 0
}

getyn()
{
	if test $NONINTERACTIVE; then
		return 0
	fi

	while prompt "$* (y/n) "
	do	case $CMD in
		[yY])	return 0
			;;
		[nN])	return 1
			;;
		*)	echo -e "\nPlease answer y or n" >&2
			;;
		esac
	done
} 
字串加密 (hash/encryption)
_Decrypt() {
    # Encrypt the string by following the command.
    # echo "your password" | openssl enc -base64
    # NOTE: The openssl requires to be installed.
    #
    # Decrypt the hash code by following the command.
    # _Decrypt "your-hash-key"
    #
    local hash
    hash="$1"
    if which openssl >/dev/null 2>&1;then
        if [ -n $hash ];then
            echo -n "$hash" | openssl enc -base64 -d
        fi
    fi
    return 0
}
# Encrypt
echo -n "123456" | openssl enc -aes-256-cbc -a -pass pass:ThisIsPassword

U2FsdGVkX188Af3yumHOyI19WPbltgRQnPDACmtRniQ=

# Decrypt
echo -n "U2FsdGVkX188Af3yumHOyI19WPbltgRQnPDACmtRniQ=" | openssl enc -aes-256-cbc -a -pass pass:ThisIsPassword -d

123456

帳密資訊雜湊處裡 (hash + salt)

#!/bin/bash
## Create:
salt=12345_

protocol=sha1sum

read -p "Enter login: " username
read -p "Password: " -s pass1
read -p "Repeat: " -s pass2

if [ "$pass1" != "$pass2" ]; then echo "Pass missmatch"; exit 1; else password=$pass1; fi

echo -en "$username " >> ./mypasswd
echo -e "${salt}${password}" | $protocol | awk '{print $1}' >> ./mypasswd
#!/bin/bash
## Read:
salt=12345_ #(samesalt)
protocol=sha1sum

read -p "Enter username: " username
read -p "Enter password: " -s password

if [ `grep $username ./mypasswd | awk '{print $2}'` != `echo "${salt}${password}" | $protocol | awk '{print $1}'` ]; then echo -e "wrong username or password"; exit 127; else echo -e "login successfull"; fi
# With openssl
echo 'mypassword' | openssl passwd -stdin
echo 'mypassword' | openssl passwd -salt "sAlT" -stdin

# Toe see mode details
openssl passwd -h
批次轉檔
# set q here 
q=""
helper(){
    local p="$*"
    for f in $p
    do
        echo "Working on $f"
        ffmpeg -nostdin -vaapi_device /dev/dri/renderD128 -i "$f" -vf format=nv12,hwupload -c:v hevc_vaapi -f mkv -rc_mode 1 -qp "$q" "${f%.*}.HEVC.mkv"
    done
}

helper '/tmp/r/*.mp4'
helper '/tmp/r/*.avi'
helper '/path/to/*.mkv'
亂數密碼
genpasswd() 
{
    length=$1
    [ "$length" == "" ] && length=16
    tr -dc A-Za-z0-9_ < /dev/urandom | head -c ${length} | xargs
}
password=$(genpasswd)

if [ -e "/root/passwordMysql.log" ] && [ ! -z "/root/passwordMysql.log" ]
then
    password=$(awk '{print $1}' /root/passwordMysql.log)
fi

touch /root/passwordMysql.log
echo "$password" > /root/passwordMysql.log
對話框 whiptail

訊息視窗

whiptail --title "Example Dialog" --msgbox "This is an example of a message box. You must hit OK to continue." 8 78

Yes/No

if (whiptail --title "Example Dialog" --yesno "This is an example of a yes/no box." 8 78); then
    echo "User selected Yes, exit status was $?."
else
    echo "User selected No, exit status was $?."
fi

輸入視窗

COLOR=$(whiptail --inputbox "What is your favorite Color?" 8 39 Blue --title "Example Dialog" 3>&1 1>&2 2>&3)

exitstatus=$?
if [ $exitstatus = 0 ]; then
    echo "User selected Ok and entered " $COLOR
else
    echo "User selected Cancel."
fi

echo "(Exit status was $exitstatus)"

A file

echo "Welcome to Bash $BASH_VERSION" > test_textbox
#                  filename height width
whiptail --textbox test_textbox 12 80

密碼遮蔽

PASSWORD=$(whiptail --passwordbox "please enter your secret password" 8 78 --title "password dialog" 3>&1 1>&2 2>&3)

exitstatus=$?
if [ $exitstatus == 0 ]; then
    echo "User selected Ok and entered " $PASSWORD
else
    echo "User selected Cancel."
fi

echo "(Exit status was $exitstatus)"

選單

whiptail --title "Menu example" --menu "Choose an option" 25 78 16 \
"<-- Back" "Return to the main menu." \
"Add User" "Add a user to the system." \
"Modify User" "Modify an existing user." \
"List Users" "List all users on the system." \
"Add Group" "Add a user group to the system." \
"Modify Group" "Modify a group and its list of members." \
"List Groups" "List all groups on the system."

複選清單

whiptail --title "Check list example" --checklist \
"Choose user's permissions" 20 78 4 \
"NET_OUTBOUND" "Allow connections to other hosts" ON \
"NET_INBOUND" "Allow connections from other hosts" OFF \
"LOCAL_MOUNT" "Allow mounting of local devices" OFF \
"REMOTE_MOUNT" "Allow mounting of remote devices" OFF

單選清單

whiptail --title "Radio list example" --radiolist \
"Choose user's permissions" 20 78 4 \
"NET_OUTBOUND" "Allow connections to other hosts" ON \
"NET_INBOUND" "Allow connections from other hosts" OFF \
"LOCAL_MOUNT" "Allow mounting of local devices" OFF \
"REMOTE_MOUNT" "Allow mounting of remote devices" OFF

進度條

#!/bin/bash
{
    for ((i = 0 ; i <= 100 ; i+=5)); do
        sleep 0.1
        echo $i
    done
} | whiptail --gauge "Please wait while we are sleeping..." 6 50 0
Learning