Shell编程之函数
一、Shell函数
1.概念与作用
将程序里多次被调用的相同代码组合起来(函数体),并为其取一个名字(函数名),其他所有想重复调用这部分代码的地方都只需调用这个名字即可。
优势:
- 把相同的程序段定义成函数,减少代码量,提高开发效率
- 增加程序的可读性、易读性,提升管路效率
- 可以实现程序功能模块化,使程序具备通用性
2.函数语法
写法一:
function 函数名() {
指令
return n
}
写法二:
function 函数名 {
指令
return n
}
写法三:
函数名() {
指令
return n
}
3.函数的执行
(1)不带参数的函数
直接输入函数名即可(不带小括号)
注意:
- 执行时,function和小括号都不要带
- 函数的定义或加载必须在执行之前
- 执行顺序:系统别名-函数-系统命令-可执行文件
- 函数执行时,会与脚本共用变量,也可以设定局部变量
- return命令的功能与exit类似,是退出函数,而exit是退出脚本
- return语句会返回一个退出值给调用函数的当前程序,而exit会返回给执行程序的当前Shell
- 若将函数放在单独文件中,在被脚本加载时,需使用source或 . 来加载
- 在函数内一般使用local定义局部变量
(2)带参数的函数
函数名 参数1 参数2
注意:
- 位置参数($1、$2...$#、$*、$?、$@)都可以作为函数的参数使用
- 父脚本的参数临时被函数参数所遮盖或隐藏
- $0比较特殊,它仍是父脚本的名称
- 当函数执行完时,原来的命令行脚本的参数即可恢复
- 函数的参数变量是在函数体里面定义的
4.函数基础实践
(1)建立两个简单的函数并调用执行
[root@codis-178 ~]# cat 8_1.sh
#!/bin/bash
oldboy(){
echo "I am oldboy."
}
function oldgirl(){
echo "I am oldgirl."
}
oldboy
oldgirl
[root@codis-178 ~]# sh 8_1.sh
I am oldboy.
I am oldgirl.
(2)分离函数体和执行函数脚本
[root@codis-178 ~]# cat >> /root/8_2.sh<<- EOF
> oldboy(){
> echo "I am oldboy."
> }
> EOF
[root@codis-178 ~]# cat 8_2.sh
oldboy(){
echo "I am oldboy."
}
[root@codis-178 ~]# cat 8_3.sh
#!/bin/bash
[ -f /root/8_2.sh ] && . /root/8_2.sh || exit 1
oldboy
[root@codis-178 ~]# sh 8_3.sh
I am oldboy.
(3)带参数的函数
[root@codis-178 ~]# cat 8_2.sh
oldboy(){
echo "I am oldboy.you are $1"
}
[root@codis-178 ~]# cat 8_4.sh
#!/bin/bash
[ -f /root/8_2.sh ] && . /root/8_2.sh || exit 1
oldboy xiaoda
[root@codis-178 ~]# sh 8_4.sh
I am oldboy.you are xiaoda
(4)将函数的传参转换成脚本文件命令传参
[root@codis-178 ~]# cat 8_2.sh
oldboy(){
echo "I am oldboy.you are $1"
}
[root@codis-178 ~]# cat 8_4.sh
#!/bin/bash
[ -f /root/8_2.sh ] && . /root/8_2.sh || exit 1
oldboy $1
[root@codis-178 ~]# sh 8_4.sh xiaoda
I am oldboy.you are xiaoda
5.利用函数开发企业及URL检测脚本
[root@codis-178 ~]# cat 8_5.sh
#!/bin/bash
function usage(){
echo $"usage:$0 url"
exit 1
}
function check_url(){
wget --spider -q -o /dev/null --tries=1 -T 5 $1
if [ $? -eq 0 ]
then
echo "$1 is yes."
else
echo "$1 is no."
fi
}
function main(){
if [ $# -ne 1 ] #传入多个参数,打印帮助函数
then
usage
fi
check_url $1
}
main $* # 将命令行接收的所有参数传给函数
[root@codis-178 ~]# sh 8_5.sh
usage:8_5.sh url
[root@codis-178 ~]# sh 8_5.sh www.baidu.com
www.baidu.com is yes.
[root@codis-178 ~]# sh 8_5.sh www.163.163.com
www.163.163.com is no.
牛逼写法
[root@codis-178 ~]# cat 8_5_1.sh
#!/bin/bash
. /etc/init.d/functions #引入系统函数库
function usage(){
echo $"usage:$0 url"
exit 1
}
function check_url(){
wget --spider -q -o /dev/null --tries=1 -T 5 $1
if [ $? -eq 0 ]
then
action "$1 is yes." /bin/true
else
action "$1 is no." /bin/false
fi
}
function main(){
if [ $# -ne 1 ]
then
usage
fi
check_url $1
}
main $*
[root@codis-178 ~]# sh 8_5_1.sh www.anzhi.com
www.anzhi.com is yes. [ OK ]
[root@codis-178 ~]# sh 8_5_1.sh www.bbaidu.com
www.bbaidu.com is no. [FAILED]
6.开发一键优化系统脚本
思路:
- 配置yum源
- 禁用开机不需要的启动脚本
- 优化内核参数
- 增加系统文件描述符、堆栈等配置
- 禁止root远程登录,修改SSH端口,禁止DNS及空密码
- 有外网IP的机器需要开启、配置防火墙,关闭SELinux
- 清除无用的默认系统账户和组,添加运维成员
- 锁定敏感文件,如/etc/passwd
- 配置时间同步
- 初始化用户,配置sudo权限控制
- 修改系统字符集
- 修补漏洞
[root@codis-178 ~]# cat sys_opt.sh
#!/bin/bash
# author:tongxiaoda
# set env
export PATH=$PATH:/bin:/sbin:/usr/sbin
# Require root to run this script
if [ "$UID" != "0" ];then
echo "Please run this script by root."
exit 1
fi
# define cmd var
SERVICE=`which service`
CHKCONFIG=`which chkconfig`
function mod_yum(){
# modify yum path
if [ -e /etc/yum.repos.d/centos6.7 ]
then
mv /data/soft/centos6.7 /etc/yum.repos.d/
fi
}
function close_selinux(){
#1.close selinux
sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
setenforce 0 &>/dev/null
}
function close_iptables(){
#2.close iptables
/etc/init.d.iptables stop
/etc/init.d iptables stop
chkconfig iptables off
}
function least_service(){
#3.least service starup
chkconfig|awk '{print "chkconfig",$1,"off"}'|bash
chkconfig|egrep "crond|sshd|network|rsyslog|sysstat"|awk '{print "chkconfi",$1,"on"}'|bash
}
function adduser(){
#4.add xiaoda and sudo
if [ `grep -w xiaoda /etc/passwd|wc -l` -lt 1 ]
then
useradd xiaoda
echo 123456|passwd --stdin xiaoda
\cp /etc/sudoers /etc/sudoers.ori
echo "xiaoda ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
tail -l /etc/sudoers
visudo -x &>/dev/null
fi
}
function charset(){
#5.charset config
cp /etc/sysconfig/i18n /etc/sysconfig/i18n.ori
echo 'LANG="zh_CN.UTF-8"' >/etc/sysconfig/i18n
source /etc/sysconfig/i18n
}
function time_sync(){
#6.time sync
cron=/var/spool/cron/root
if [ `grep -w "ntpdate" $cron|wc -l` -lt 1 ]
then
echo '#time sync by xiaoda at 2017-08-10' >> $cron
echo '*/5 * * * * /usr/sbin/ntpdate time.nist.gov >dev/null 2>&1' >> $cron
crontab -l
fi
}
function com_line_set(){
#7.command set
if [ `egrep "TMOUT|HISTSIZE|ISTFILESIZE" /etc/profile |wc -l` -lt 3 ]
then
echo 'export TMOUT=300' >>/etc/profile
echo 'export HISTSIZE=5' >>/etc/profile
echo 'export ISTFILESIZE=5' >>/etc/profile
. /etc/profile
fi
}
function open_file_set(){
#8.increase open file
if [ `grep 65535 /etc/security/limits.conf|wc -l` -lt 1 ]
then
echo '* - nofile 65535' >> /etc/security/limits.conf
tail -l /etc/security/limits.conf
fi
}
function set_kernel(){
#9.kernel set
if [ `grep kernel_flag /etc/sysctl.conf|wc -l` -lt 1 ]
then
cat >>/etc/sysctl.conf<<EOF
#kernel_flag
net.ipv4.tcp_fin_timeout = 2
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_keepalive_time = 600
net.ipv4.ip_local_port_range = 4000 65000
net.ipv4.tcp_max_syn_backlog = 16384
net.ipv4.tcp_max_tw_buckets = 36000
net.ipv4.route.gc_timeout = 100
net.ipv4.tcp_syn_retries = 1
net.ipv4.tcp_synack_retries = 1
net.core.somaxconn = 16384
net.core.netdev_max_orphans = 16384
net.ipv4.tcp_max_orphans = 16384
net.nf_conntrack_max = 25000000
net.netfilter.nf_conntrack_max = 25000000
net.netfilter.nf_conntrack_tcp_timeout_established = 180
net.netfilter.nf_conntrack_tcp_timeout_time_wait = 120
net.netfilter.nf_conntrack_tcp_timeout_close_wait = 60
net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 120
EOF
sysctl -p
fi
}
function init_ssh(){
\cp /etc/ssh/sshd_config /etc/ssh/sshd_config.`date +"%Y-%m-%d_%H-%M-%S"`
sed -i 's%#Port 22%Port 52113%' /etc/ssh/sshd_config
sed -i 's%#PermitRootLogin yes%PermitRootLogin no%' /etc/ssh/sshd_config
sed -i 's%#PermitEmptyPasswords yes%PermitEmptyPasswords no%' /etc/ssh/sshd_config
sed -i 's%#UseDNS yes%UseDNS no%' /etc/ssh/sshd_config
/etc/init.d/sshd reload &>/dev/null
}
function update_linux(){
#10.upgrade linux
if [ `rpm -qa lrzsz nmap tree dos2unix nc|wc -l` -le 3]
then
yum install lrzsz nmap tree dos2unix nc -y
yum update -y
fi
}
main(){
mod_yum
close_selinux
close_iptables
least_service
adduser
charset
time_sync
com_line_set
open_file_set
set_kernel
init_ssh
ipdate_linux
}
main
检查脚本
[root@codis-178 ~]# cat check_opt.sh
#!/bin/bash
# set env
export PATH=$PATH:/bin:/sbin:/usr/sbin
# Require root to run this script
if [ "$UID" != "0" ];then
echo "Please run this script by root."
exit 1
fi
# Source function library
. /etc/init.d/functions
function check_yum(){
Base=/etc/yum.repos.d/centos6.7
if [ `grep aliyun $Base|wc -l` -ge 1 ];then
action "$Base config" /bin/true
else
action "$Base config" /bin/false
fi
}
function check_selinux(){
config=/etc/selinux/config
if [ `grep "SELINUX=disabled" $config|wc -l` -ge 1 ];then
action "$config config" /bin/true
else
action "$config config" /bin/false
fi
}
function check_services(){
export LANG=en
if [ `chkconfig|grep 3:on|egrep "crond|sshd|network|rsyslog|sysstat"|wc -l` -eq 5 ];then
action "sys service init" /bin/true
else
action "sys service init" /bin/false
fi
}
function check_open_file(){
limits=/etc/security/limits.conf
if [ `grep 65535 $limits|wc -l` -eq 1 ];then
action "$limits" /bin/true
else
action "$limits" /bin/false
fi
}
main(){
check_yum
check_selinux
check_service
check_open_file
}
main
7.开发rsync启动脚本
[root@codis-178 ~]# cat rsync_start
#!/bin/bash
# chkconfig: 2345 20 80
# description: Rsync Startup scripts
. /etc/init.d/functions
function usage(){
echo $"usage:$0 {start|stop|restart}"
exit 1
}
function start(){
rsync --daemon
sleep 1
if [ `netstat -lntup |grep rsync|wc -l` -ge 1 ];then
action "rsync is stared." /bin/true
else
action "rsync is stared." /bin/false
fi
}
function stop(){
killall rsync &>/dev/null
sleep 2
if [ `netstat -lntup|grep rsync|wc -l` -eq 0 ];then
action "rsync is stopped." /bin/true
else
action "rsync is stopped." /bin/false
fi
}
function main(){
if [ $# -ne 1 ];then
usage
fi
if [ "$1" = "start" ];then
start
elif [ "$1" = "stop" ];then
stop
elif [ "$1" = "restart" ];then
stop
sleep 1
start
else
usage
fi
}
main $*