=Start=
缘由:
简单学习一下Linux下原生的functions脚本提供的功能,可以为自己编写Bash脚本提供一些参考。
正文:
参考解答:
[root@sec-test ~]# ls -lt /etc/init.d/functions -rw-r--r-- 1 root root 17500 May 3 06:17 /etc/init.d/functions [root@sec-test ~]# rpm -qf /etc/init.d/functions initscripts-9.49.39-1.el7.x86_64
&
# 字符串包含判断
# returns OK if $1 contains $2
strstr() {
[ "${1#*$2*}" = "$1" ] && return 1
return 0
}
# 判断给出的第一个参数表示的文件名是否为特定后缀
# Check whether file $1 is a backup or rpm-generated file and should be ignored
is_ignored_file() {
case "$1" in
*~ | *.bak | *.orig | *.rpmnew | *.rpmorig | *.rpmsave)
return 0
;;
esac
return 1
}
# 判断提供的第一个参数是否为「t/T/y/Y/yes/YES/Yes/.../true/...」
# Evaluate shvar-style booleans
is_true() {
case "$1" in
[tT] | [yY] | [yY][eE][sS] | [tT][rR][uU][eE])
return 0
;;
esac
return 1
}
# 判断提供的第一个参数是否为「f/F/n/N/no/NO/No/.../false/...」
# Evaluate shvar-style booleans
is_false() {
case "$1" in
[fF] | [nN] | [nN][oO] | [fF][aA][lL][sS][eE])
return 0
;;
esac
return 1
}
# 判断参数中给定的pid对应进程是否存在
# Check if any of $pid (could be plural) are running
checkpid() {
local i
for i in $* ; do
[ -d "/proc/$i" ] && return 0
done
return 1
}
#起到类似readlink命令的作用
__readlink() {
ls -bl "$@" 2>/dev/null| awk '{ print $NF }'
}
# 输出指定进程的pid列表(通过调用pidof命令实现)
# Output PIDs of matching processes, found using pidof
__pids_pidof() {
pidof -c -m -o $$ -o $PPID -o %PPID -x "$1" || \
pidof -c -m -o $$ -o $PPID -o %PPID -x "${1##*/}"
}
# 以守护进程的方式启动一个进程
# A function to start a program.
daemon() {
}
# 杀掉进程的函数
# A function to stop a program.
killproc() {
}
# 多彩打印
echo_success() {
}
echo_failure() {
}
echo_warning() {
}
...
# 记录操作并以多彩样式输出其执行结果
# Run some action. Log its output.
action() {
local STRING rc
STRING=$1
echo -n "$STRING "
shift
"$@" && success $"$STRING" || failure $"$STRING"
rc=$?
echo
return $rc
}
&
#!/bin/bash
# Date: 20171024
# set -x
# Source function library.
if [ -f /etc/init.d/functions ]; then
. /etc/init.d/functions
else
echo '"/etc/init.d/functions" not exists'
echo 'try "rpm -ql initscripts | grep --color /functions"'
exit 0
fi
export PATH=/usr/local/bin:/bin:/usr/bin:/sbin:/usr/sbin/:/usr/local/sbin
#action 'date +"%F %T"
#' date +"%F %T"
## [ "$?" -eq 0 ] && echo_success || echo_failure
#
## date +"%F %T"
#action 'rpm -ql /etc/init.d/functions
#' rpm -ql /etc/init.d/functions
#
## [ "$?" -eq 0 ] && echo_success || echo_failure
#$SETCOLOR_SUCCESS && echo "success" && $SETCOLOR_NORMAL
#$SETCOLOR_FAILURE && echo "failure" && $SETCOLOR_NORMAL
#$SETCOLOR_WARNING && echo "warning" && $SETCOLOR_NORMAL
#
#echo_s() {
# $SETCOLOR_SUCCESS && echo "$@" && $SETCOLOR_NORMAL
#}
#
#echo_f() {
# $SETCOLOR_FAILURE && echo "$@" && $SETCOLOR_NORMAL
#}
#
#echo_w() {
# $SETCOLOR_WARNING && echo "$@" && $SETCOLOR_NORMAL
#}
#
#echo_s haha
#echo_f haha
#echo_w haha
s=$"Starting $prog (via systemctl): " #在字符串前面添加 $ 是为啥?
echo $s
s2="Starting $prog (via systemctl): " #测试来看没啥区别
echo $s2
#获取屏幕宽度
[ -z "${COLUMNS:-}" ] && COLUMNS=80
echo $COLUMNS
action 'checkpid 1' checkpid 1
action 'checkpid 19999' checkpid 19999
# returns OK if $1 contains $2
action 'strstr()' strstr "this is the whole string." "search_string"
action 'is_true yes' is_true yes
action 'is_true yeS' is_true yeS
action 'is_true Yes' is_true Yes
action 'is_true yEs' is_true yEs
action 'is_true yy' is_true yy
action 'is_false no' is_false no
action 'is_false No' is_false No
action 'is_false N' is_false N
action 'is_false false' is_false false
action 'is_false x' is_false x
参考链接:
=END=
《 “Linux Shell学习 之 /etc/init.d/functions 详解” 》 有 2 条评论
Shell 函数式编程
http://blog.xiayf.cn/2018/05/16/functional-shell-code/
`
true_then_run() {
condition=$1
action=$2
(${condition})
if [ $? -eq 0 ]
then
(${action})
else
echo “‘$1’ is false, don’t run ‘$2′”
fi
}
false_then_run() {
condition=$1
action=$2
(${condition})
if [ $? -ne 0 ]
then
(${action})
else
echo “‘$1’ is true, don’t run ‘$2′”
fi
}
map() {
for item in $2
do
($1 ${item})
done
}
reduce() {
operator=$1
#
list=($2)
list_len=${#list[@]}
#
result=””
if [ ${list_len} -gt 0 ]
then
result=${list[0]}
fi
#
if [ ${list_len} -gt 1 ]
then
for item in ${list[@]:1}
do
result=$(${operator} ${result} ${item})
done
fi
echo ${result}
}
filter() {
for item in $2
do
($1 ${item})
if [ $? -eq 0 ]
then
echo ${item}
fi
done
}
sum() {
v=0
for arg in “$@”
do
v=$(($v+${arg}))
done
echo $v
}
`
运维必看!如何让shell脚本自杀
https://www.yunweipai.com/45372.html
https://www.cnblogs.com/f-ck-need-u/p/8661501.html
`
1.脚本自杀正文
有些时候我们写的shell脚本中有一些后台任务,当脚本的流程已经执行到结尾处或将其kill掉时,这些后台任务会直接挂靠在init/systemd进程下,而不会随着脚本退出而停止。
例如:
[root@mariadb ~]# cat test1.sh
#!/bin/bash
echo $BASHPID
sleep 50 &
[root@mariadb ~]# ps -elf | grep slee[p]
0 S root 10806 1 0 80 0 – 26973 hrtime 19:26 pts/1 00:00:00 sleep 50
从结果中可以看到,脚本退出后,sleep进程的父进程变为了1,也就是挂在了init/systemd进程下。
这时我们可以在脚本中直接使用kill命令杀掉sleep进程。
[root@mariadb ~]# cat test1.sh
#!/bin/bash
echo $BASHPID
sleep 50 &
kill $!
但是,如果这个sleep进程是在循环中(for、while、until均可),那就麻烦了。
例如下面的例子,直接将循环放入后台,杀掉sleep、或者exit、或者杀掉脚本自身进程、或者让脚本自动退出、甚至exec退出当前脚本shell都是无效的。
[root@mariadb ~]# cat test1.sh
#!/bin/bash
echo $BASHPID
while true;do
sleep 50
echo 1
done &
killall sleep
kill $BASHPID
为了分析,新建一个脚本test2.sh:
#!/bin/bash
echo $BASHPID
while true;do
sleep 50
echo 1
done &
sleep 60
然后在脚本执行的60秒内查看test2.sh进程的信息:
[root@mariadb ~]# pstree -p | grep “test2.sh”
| `-bash(2687)—test2.sh(2923)-+-sleep(2925)
| `-test2.sh(2924)—sleep(2926)
其中pid=2923的test2.sh进程是脚本自身进程,pid=2924的test2.sh进程是while开始运行后为while提供执行环境的子shell进程(为什么会生成这个进程,见我的另一篇文章)。
所以,对于前面的test1.sh进程,杀掉了 $BASHPID 对应的test1.sh进程后,其实还有一个为while提供运行环境的test1.sh进程,且这个进程在 $BASHPID 结束后,会挂在init/systemd下。
本文只是提供一种杀脚本的解决方案。很多情形并非如我这里所描述的,例如不是while循环放后台,而是循环内的sleep放后台,这时(脚本终止时)sleep会挂在init/systemd下,不过这很简单。相信读懂了本文,各位已经了解了一些trap的功能以及处理这类问题的逻辑,也知道其他各种情形如何处理。
最后,有一种更方便更精确的自杀手段:man kill。在该man手册中解释了,如果kill的pid值为0,表示发送信号给当前进程组中所有进程,对shell脚本来说这意味着杀掉脚本中产生的所有进程。方案如下:
#!/bin/bash
trap “echo ‘signal_handled:’;kill 0” SIGINT SIGTERM
while true;do
sleep 5
echo “hello world! hello world!”
done &
sleep 60
`