Contents
3.52. 老男孩Shell编程实战¶
3.52.1. 什么是shell脚本¶
第一个脚本示例
#!/usr/bin/env bash
LPG_DIR=/var/log
ROOT_UID=0
#脚本需要使用root用户权限
if [ -$"$UID" -ne "$ROOT_UID" ]; then
echo "Must be root to run this script."
exit 1
fi
cd $LPG_DIR || {
echo "Cannot change to necessary directory."
exit 1
}
cat /dev/null>messages && {
echo "Logs cleaned up."
exit 0 # 退出之前返回0表示成功,返回1表示失
}
echo "Logs cleaned up fail."
exit 1
脚本开头(第一行)
#!/bin/sh
#!/bin/bash
提示:sh为bash的软链接,大多数情况下,脚本的开头使用“#!/bin/bash”和“#!/bin/sh”是没有区别的,但更规范的写法是在脚本的开头使用“#!/bin/bash”。
脚本的执行方式¶
1)bash script-name或sh script-name
2)path/script-name或./script-name:指在当前路径下执行脚本(脚本需要有执行权限)
chmod 755 path/script-name
3)source script-name或.script-name
使用source或“.”可以将san.sh自身脚本中的变量值或函数等的返回值传递到当前父Shell脚本father.sh中使用。这是它和其他几种方法最大的区别
使用的是父shell
4)sh<script-name或cat scripts-name|sh:同样适用于bash
结论:通过source或“.”加载执行过的脚本,由于是在当前Shell中执行脚本,因此在脚本结束之后,脚本中的变量(包括函数)值在当前Shell中依然存在,而sh和bash执行脚本都会启动新的子Shell执行,执行完后退回到父Shell。因此,变量(包括函数)值等无法保留。
# 通过管道符也能执行
cat oldboy.sh | bash
环境变量初始化与对应文件的生效顺序¶
/etc/profile —> /etc/profile.d –> $HOME/.bash_profile —-> $HOME/.bashrc —> /etc/bashrc
顺序如下
/etc/profile #每个用户登录时都将启动此文件,存储环境变量,加载完/etc/profile再去加载/etc/profile.d/
/etc/profile.d/*.sh
$HOME/.bash_profile #存储环境变量
$HOME/.bashrc
/etc/bashrc
交互式
/etc/profile——当用户在运行级别3登录系统时首先运行。
/etc/profile.d——当/etc/profile运行时,会调用该目录下的一些脚本。
$HOME/.bash_profile
$HOME/.bashrc——上述脚本的中一个运行后即调用此脚本。
非交互式
$HOME/.bashrc——如果此文件存在即被运行。
/etc/bashrc——将被$HOME/.bashrc调用运行。
/etc/profile.d——此目录下的脚本将被/etc/bashrc或/etc/bash.bashrc调用运行。
提示
如果希望在非登录Shell下也可读到设置的环境变量等内容,就需要将变量设定等写入
$HOME/.bashrc
/etc/bashrc
3.52.2. 初始化操作系统脚本¶
#!/usr/bin/env bash
#usage:xxx
#scripts_name:${NAME}.sh
# author:xiaojian
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/CentOS-Base.repo ]
then
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup&&\
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-6.repo
fi
}
function close_selinux(){
#1.close selinux
sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
#grep SELINUX=disabled /etc/selinux/config
setenforce 0 &>/dev/null
#getenforce
}
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 startup
chkconfig|awk '{print "chkconfig",$1,"off"}'|bash
chkconfig|egrep "crond|sshd|network|rsyslog|sysstat"|awk '{print "chkconfig",$1,"on"}'|bash
export LANG=en
chkconfig --list|grep 3:on
}
function adduser(){
#4.add oldboy and sudo
if [ `grep -w oldboy /etc/passwd|wc -l` -lt 1 ]
then
useradd oldboy
echo 123456|passwd --stdin oldboy \cp /etc/sudoers /etc/sudoers.ori
echo "oldboy" ALL=(ALL) NOPASSWD: ALL " >>/etc/sudoers
tail -1 /etc/sudoers
visudo -c &>/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
#echo $LANG
}
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 oldboy at 2010-2-1' >>$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 HISTFILESIZE=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 -1 /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_backlog = 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 no%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
}
function main() {
mod_yum
close_iptables
close_selinux
least_service
adduser
charset
time_sync
com_line_set
open_file_set
set_kernel
init_ssh
update_linux
}
main
3.52.3. 开发检测脚本¶
#!/usr/bin/env bash
#usage:xxx
#scripts_name:${NAME}.sh
# author:xiaojian
# set env
export PATH=$PATH:/bin:/sbin:/usr/sbin
[ "UID" != "0" ] && { echo "Please run this script by root." ;exit 1 }
# Source function library
. /etc/init.d/functions
function check_yum() {
Base=/etc/yum.repos.d/CentOS-Base.repo
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_service() {
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
}
function main() {
check_yum
check_selinux
check_service
check_open_file
}
main
3.52.4. 利用Shell函数开发rsync服务启动脚本¶
#!/usr/bin/env bash
#usage:xxx
#scripts_name:${NAME}.sh
# author:xiaojian
. /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 "rsyncd is started." /bin/true
else
action "rsyncd is started." /bin/false
fi
}
function stop(){
killall rsync &>/dev/null
sleep 2
if [ `netstat -lntup|grep rsync|wc -l` -eq 0 ]
then
action "rsyncd is stopped." /bin/true
else
action "rsyncd is started." /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
case "$1" in
"start")
start
;;
"stop")
stop
;;
"restart")
stop
sleep 1
start
;;
*)
usage
;;
esac
}
main $*
3.52.5. 一个颜色打印示例脚本¶
#!/usr/bin/env bash
#usage:xxx
#scripts_name:${NAME}.sh
# author:xiaojian
RED_COLOR='\E[1;31m'
GREEN_COLOR='\E[1;32m'
YELLOW_COLOR='\E[1;33m'
BLUE_COLOR='\E[1;34m'
RES='\E[0m'
usage() {
echo "Usage: basename $0 {1|2|3|4}"
exit 1
}
menu(){
cat <<END
1.apple
2.pear
3.banana
END
}
chose() {
read -p "Pls input your choice: " fruit
case "$fruit" in
1)
echo -e "${RED_COLOR}apple${RES}"
;;
2)
echo -e "${GREEN_COLOR}pear${RES}"
;;
3)
echo -e "${YELLOW_COLOR}banana${RES}"
;;
*)
usage
esac
}
main() {
menu
chose
}
main
3.52.6. 结合case给输出的语句加颜色¶
#!/usr/bin/env bash
#usage:xxx
#scripts_name:${NAME}.sh
# author:xiaojian
plus_color(){
RED_COLOR='\E[1;31m'
GREEN_COLOR='\E[1;32m'
YELLOW_COLOR='\E[1;33m'
BLUE_COLOR='\E[1;34m'
PINK='\E[1;35m'
RES='\E[0m'
if [ $# -ne 2 ];then
echo "Usage $0 content {red|yellow|blue|green|pink}"
exit
fi
case "$2" in
red|RED)
echo -e "${RED_COLOR}$1${RES}";;
green|GREEN)
echo -e "${GREEN_COLOR}$1${RES}";;
yellow|YELLOW)
echo -e "${YELLOW_COLOR}$1${RES}";;
blue|BLUE)
echo -e "${BLUE_COLOR}$1${RES}";;
pink|PINK)
echo -e "${PINK}$1${RES}";;
*)
echo "Usage $0 content {red|yellow|blue|green|pink}"
exit
esac
}
plus_color "I" red
plus_color "am" green
plus_color "hujianli" blue
3.52.7. while循环¶
#!/usr/bin/env bash
#usage:xxx
#scripts_name:${NAME}.sh
# author:xiaojian
# 每隔2s在屏幕上输出负载值
#while true
#do
# uptime
# sleep 2
#done
while [ 1 ]; do
uptime >> /tmp/uptime.log
usleep 2000000 #单位是微秒,其实也是两秒
done
3.52.8. 数组用法¶
#!/usr/bin/env bash
#usage:xxx
#scripts_name:${NAME}.sh
# author:xiaojian
array=(
hujianli1
hujianli2
hujianli3
hujianli4
)
for (( i = 0; i <${#array[*]}; i++ )); do
echo "This is num $i,then content is ${array[$i]}"
done
echo "---------------------------"
echo "array len:${#array[*]}"
#This is num 0,then content is hujianli1
#This is num 1,then content is hujianli2
#This is num 2,then content is hujianli3
#This is num 3,then content is hujianli4
#---------------------------
#array len:4
# C语言的for循环
array=(1 2 3 4 5)
for (( VAR = 0; VAR < ${#array[*]}; VAR++ )); do
echo ${array[VAR]}
done
# 普通for循环
array=(1 2 3 4 5)
for VAR in ${array[*]} ; do
echo $VAR
done
# 使用while循环打印数组元素
array=(1 2 3 4 5)
i=0
while ((i<${#array[*]}))
do
echo ${array[i]}
((i++))
done
3.52.9. while循环按行读文件的方式总结¶
方式1:采用exec读取文件,然后进入while循环处理。
exec <FILE
sum=0
while read line do
cmd
done
方式2:使用cat读取文件内容,然后通过管道进入while循环处理。
cat FILE_PATH|while read line
do
cmd
done
方式3:在while循环结尾done处通过输入重定向指定读取的文件。
while read line
do
cmd
done<FILE
3.52.10. 批量检查多个网站地址是否正常。¶
#!/usr/bin/env bash
#usage:xxx
#scripts_name:${NAME}.sh
# author:xiaojian
. /etc/init.d/functions
check_count=0
url_list=(
#<==定义检测的URL数组,包含多个URL地址。
http://blog.oldboyedu.com
http://blog.etiantian.org
http://oldboy.blog.51cto.com
http://10.0.0.7
)
function wait(){
echo -n '3秒后,执行检查URL操作.';
for ((i=0;i<3;i++))
do
echo -n ".";sleep 1
done
echo
}
function check_url() {
wait
for ((i=0; i<`echo ${#url_list[*]}`; i++))
do
wget -o /dev/null -T 3 --tries=1 --spider ${url_list[$i]} >/dev/null 2>&1
if [ $? -eq 0 ]
then
action "${url_list[$i]}" /bin/true
else
action "${url_list[$i]}" /bin/false
fi
done
((check_count++))
}
main() {
while true; do
check_url
echo "-----------check count:${check_count}-----------------"
sleep 10
done
}
main
3.52.11. 开发一个守护进程脚本,每30秒监控一次MySQL主从复制是否异常¶
#!/usr/bin/env bash
#usage:xxx
#scripts_name:${NAME}.sh
# author:xiaojian
CheckDb(){
status=($(awk -F ':' '/_Running|_Behind/{print $NF}' slave.log))
for((i=0;i<${#status[*]};i++))
do
count=0
if [ "${status[${i}]}" != "Yes" -a "${status[${i}]}" != "0" ]
then
let count+=1
fi
done
if [ $count -ne 0 ];then
echo "mysql replcation is failed"
return 1
else
echo "mysql replcation is sucess"
return 0
fi
}
main(){
while true
do
CheckDb
sleep 30
done
}
main
3.52.12. Shell脚本调试技巧¶
使用echo命令调试¶
echo命令是最有用的调试脚本的工具之一。
一般应在可能出现问题的脚本的重要部分加入echo命令,
例如在变量读取或修改操作的前后加入echo命令,并紧挨着退出命令exit。
使用bash命令参数调试¶
sh [-nvx] scripts.sh
参数说明如下。
·-n:不会执行该脚本,仅查询脚本语法是否有问题,并给出错误提示。
·-v:在执行脚本时,先将脚本的内容输出到屏幕上,然后执行脚本,如果有错误,也会给出错误提示。
·-x:将执行的脚本内容及输出显示到屏幕上,这是对调试很有用的参数。跟踪sh脚本的执行过程。
利用“sh-x脚本名”调试的缺点可以用set-x命令来弥补,它可以缩小调试的作用域。
使用set命令调试部分脚本内容¶
set命令也可以用于辅助脚本调试。
以下是set命令常用的调试选项。
·set-n:读命令但并不执行。
·set-v:显示读取的所有行。
·set-x:显示所有命令及其参数。
其他调试Shell脚本的工具¶
(1)Shell调试工具:bashdb
Shell调试器bashdb是一个类似于GDB的调试工具,可以完成对Shell脚本的断点设置、单步执行、变量观察等许多功能,
(2)Shell调试工具:shellcheck
shellcheck是一个可检查sh/bash脚本和命令语法的小工具
3.52.13. Expect用法¶
在不使用密钥的情况下,实现非人为交互登录。¶
ssh.exp
#!/usr/bin/expect
#usage:xxx
#scripts_name:${NAME}.sh
# author:xiaojian
set IP "192.168.1.9"
set USER "root"
set PASS "admin#123"
set timeout 30
spawn ssh $USER@$IP
expect {
"(yes/no)" {send "yes\r"; exp_continue}
"password:" {send "$PASS\r"}
}
expect "#" # 判断上次输入结果中是否包含"password:"字符串,如果有则立即返回,向下执行,否则就一直等待,知道超时时间到
send "touch /root/hujianli001.txt\r"
send "ls /etc > /root/hujianli001.txt\r"
send "mkdir /tmp/hujianli001\r"
send "exit\r"
expect eof
执行
expect ssh.exp
对服务器批量管理(了解)¶
login.sh
#!/usr/bin/env bash
#usage:xxx
#scripts_name:${NAME}.sh
# author:xiaojian
echo
for ip in `awk '{print $1}' /root/ip_pass.txt` ; do
pass=`grep $ip /root/ip_pass.txt|awk '{print $2}'`
expect /root/ssh2.exp $ip $pass
done
ip_pass.txt
192.168.1.9 admin#123
ssh2.exp
#!/usr/bin/expect
#usage:xxx
#scripts_name:${NAME}.sh
# author:xiaojian
set IP [lindex $argv 0]
set USER "root"
set PASS [lindex $argv 1]
set timeout 30
spawn ssh $USER@$IP
expect {
"(yes/no)" {send "yes\r"; exp_continue}
"password:" {send "$PASS\r"}
}
expect "#" # 判断上次输入结果中是否包含"password:"字符串,如果有则立即返回,向下执行,否则就一直等待,知道超时时间到
send "touch /root/hujianli001.txt\r"
send "ls /etc > /root/hujianli001.txt\r"
send "mkdir /tmp/hujianli001\r"
send "exit\r"
expect eof
3.52.14. 企业生产场景下的Expect案例¶
IP地址 |
主机名 |
角色 |
|---|---|---|
192.168.33.128 |
oldgirl |
管理机 |
192.168.33.129 |
littleboy |
被管理机1 |
192.168.33.130 |
oldboy |
被管理机2 |
批量执行命令¶
1)实现Expect自动交互的脚本: sample1.exp
#!/usr/bin/expect
if { $argc != 2 } {
puts "usage: expect $argv0 ip command"
exit
}
set ip [lindex $argv 0]
set cmd [lindex $argv 1]
set password "123456"
#
spawn ssh root@$ip $cmd
expect { "yes/no" {send "yes\r";exp_continue}
"*password" {send "$password\r"}
}
expect eof
执行命令如下:
expect sample1.exp 192.168.33.128 uptime
2)利用Shell循环执行Expect脚本命令: sample2.sh
#!/bin/sh
if [ $# -ne 1 ]
then
echo $"USAGE:$0 cmd"
exit 1
fi
cmd=$1
for n in 128 129 130
do
expect sample1.exp 192.168.33.$n "$cmd"
done
使用命令如下: sh sample2.sh uptime
如果遇到连接SSH反应慢的问题,请在所有被管理的机器上提前执行如下命令:
sed -ir '13iUseDNS no\nGSSAPIAuthentication no\n' /etc/ssh/sshd_config /etc/init.d/sshd restart
### 批量发送文件
1)实现Expect自动交互的脚本:
sample001.exp
#!/usr/bin/expect
if { $argc != 3 } {
puts "usage: expect $argv0 file host dir"
exit
}
#define var
set file [lindex $argv 0]
set host [lindex $argv 1]
set dir [lindex $argv 2]
set password "123456" s
pawn scp -P22 -rp $file root@$host:$dir
expect { "yes/no" {send "yes\r";exp_continue}
"*password" {send "$password\r"}
}
expect eof
使用方法
expect sample001.exp /etc/hosts 192.168.33.130 /home/oldboy
2)利用Shell循环执行Expect脚本命令: sample002.sh
#!/usr/bin/env bash
#usage:xxx
#scripts_name:${NAME}.sh
# author:xiaojian
if [ $# -ne 2 ]
then
echo $"USAGE:$0 file dir"
exit 1
fi
file=$1
dir=$2
for n in 128 129 130
do
expect sample001.exp $file 192.168.33.$n $dir
done
将/server/scripts目录批量发送到所有服务器指定的/tmp目录:
sh sample002.sh /server/scripts /tmp/
批量执行Shell脚本¶
1)准备脚本文件:
cat /server/scripts/yum.sh
yum install httpd -y
2)使用范例sample002.sh的脚本发送要执行的脚本文件到所有机器:
sh sample002.sh /server/scripts/yum.sh /tmp/
3)使用范例sample2.sh的脚本远程连接所有服务器并远程执行脚本:
sh sample2.sh "source /tmp/yum.sh"
3.52.15. 自动化部署SSH密钥认证+ansible的项目实战¶
1)本地生成密钥对,代码如下:
ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa >/dev/null 2>&1
2)开发Expect脚本自动化交互分发公钥到所有的服务器:
ansible.exp
#!/usr/bin/expect
if { $argc != 2 } { send_user "usage: expect expect.exp file host\n"
exit }
#define var
set file [lindex $argv 0]
set host [lindex $argv 1]
set password "123456"
#start exec command
spawn ssh-copy-id -i $file "-p 22 root@$host"
expect { "yes/no" {send "yes\r";exp_continue}
"*password" {send "$password\r"}
}
expect eof
3)开发Shell脚本循环执行Expect脚本:
sample003.sh
#!/usr/bin/env bash
#usage:xxx
#scripts_name:${NAME}.sh
# author:xiaojian
for n in 128 129 130
do
expect ansible.exp ~/.ssh/id_dsa.pub 192.168.33.$n
done
操作过程如下:
rm -fr ~/.ssh/
ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa >/dev/null 2>&1
sh sample003.sh
4)实现无密码且不需要Expect就可以批量管理: cat exec.sh
ssh 192.168.33.128 uptime
ssh 192.168.33.129 uptime
ssh 192.168.33.130 uptime
5)配合ansible(Python开发的基于SSH的批量管理工具)实现自动化运维管理。 首先安装ansible,命令如下:
yum install epel-release -y
yum install ansible -y
然后编辑ansible的主机配置文件hosts,添加主机组oldboy:
[root@oldboy ~]# tail -4 /etc/ansible/hosts
[oldboy]
192.168.33.128
192.168.33.129
192.168.33.130
接着使用ansible并借助Expect建立好的SSH密钥认证执行命令
ansible oldboy -m command -a "uptime"
3.52.16. 使用exec调用其他外部命令或脚本¶
exec调用后会自动退出
#!/bin/bash
#功能描述(Description):使用exec调用其他外部命令或脚本示例.
ls
echo
echo "----------------------"
exec ls
echo "te
3.52.17. fork子进程的示例.¶
#!/bin/bash
#功能描述(Description):fork子进程的示例.
#调用外部命令时会导致fork子进程.
sleep 5
#绝对路径或相对路径调用外部脚本时会导致fork子进程.
/root/tmp.sh
cd /root; ./tmp.sh
3.52.18. 使用函数与&后台进程实现多进程ping测试1.¶
#!/bin/bash
#Version:1.0
#功能描述(Description):使用函数与&后台进程实现多进程ping测试.
net="192.168.4"
multi_ping() {
ping -c2 -i0.2 -W1 $1 &>/dev/null
if [ $? -eq 0 ];then
echo "$1 is up."
else
echo "$1 is down."
fi
}
#通过循环反复调用函数并将其放入后台并行执行.
for i in {1..254}
do
multi_ping $net.$i &
done
3.52.19. 使用函数与&后台进程实现多进程ping测试2.¶
#!/bin/bash
#Version:2.0
#功能描述(Description):使用函数与&后台进程实现多进程ping测试.
#使用wait命令等待所有子进程结束后再退出脚本.
net="192.168.4"
multi_ping() {
ping -c2 -i0.2 -W1 $1 &>/dev/null
if [ $? -eq 0 ];then
echo "$1 is up."
else
echo "$1 is down."
fi
}
#通过循环反复调用函数并将其放入后台并行执行.
for i in {1..254}
do
multi_ping $net.$i &
done
wait
3.52.20. 控制进程数量的ping测试脚本¶
#!/bin/bash
#Version:3.0
#功能描述(Description):控制进程数量的ping测试脚本.
#使用wait命令等待所有子进程结束后再退出脚本.
num=10 #控制进程数量.
net="192.168.4"
pipefile="/tmp/multiping_$$.tmp"
multi_ping() {
ping -c2 -i0.2 -W1 $1 &>/dev/null
if [ $? -eq 0 ];then
echo "$1 is up."
else
echo "$1 is down."
fi
}
#创建命名管道文件,创建其文件描述符,通过重定向导入数据到管道文件中.
mkfifo $pipefile
exec 12<>$pipefile
for i in `seq $num`
do
echo "" >&12 &
done
#通过循环反复调用函数并将其放入后台并行执行.
#成功读取命名管道中的数据后开启新的进程.
#所有内容读取完后read被阻塞,无法再启动新进程.
#等待前面启动的进程结束后,继续往管道文件中写入数据,释放阻塞,再次开启新的进程.
for j in {1..254}
do
read -u12
{
multi_ping $net.$j
echo "" >&12
} &
done
wait
rm -rf $pipfile
3.52.21. 修改SSHD配置文件,提升SSH安全性¶
#!/bin/bash
#功能描述(Description):修改SSHD配置文件,提升SSH安全性.
config_file="/etc/ssh/sshd_config"
PORT=12345
#将默认端口号修改为自定义端口号.
if grep -q "^Port" $config_file;then
sed -i "/^Port/c Port $PORT" $config_file
else
echo "Port $PORT" >> $config_file
fi
#禁止root远程登陆SSH服务器.
if grep -q "^PermitRootLogin" $config_file;then
sed -i '/^PermitRootLogin/s/yes/no/' $config_file
else
sed -i '$a PermitRootLogin no' $config_file
fi
#禁止使用密码远程登陆SSH服务器.
if grep -q "^PasswordAuthentication" $config_file;then
sed -i '/^PasswordAuthentication/s/yes/no/' $config_file
else
sed -i '$a PasswordAuthentication no' $config_file
fi
#禁止X11图形转发功能.
if grep -q "^X11Forwarding" $config_file;then
sed -i '/^X11Forwarding/s/yes/no/' $config_file
else
sed -i '$a X11Forwarding no' $config_file
fi
#禁止DNS查询.
if grep -q "^UseDNS" $config_file;then
sed -i '/^UseDNS/s/yes/no/' $config_file
else
sed -i '$a UseDNS no' $config_file
fi