=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
`