Chinaunix首页 | 论坛 | 博客
  • 博客访问: 862966
  • 博文数量: 72
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1693
  • 用 户 组: 普通用户
  • 注册时间: 2014-08-04 15:53
个人简介

主要从事Linux,云原生架构改造,服务网格,ELK,python,golang等相关技术。

文章分类

全部博文(72)

文章存档

2015年(52)

2014年(20)

分类: LINUX

2015-05-09 14:47:00

问题1:用for循环在/hy目录下批量创建10个文件,名称依次为:

hy-1

hy-2

hy-3

......

hy-10

问题2:将以上文件名中的hy全部改为linux。

问题3:批量创建10个系统账号hy01-hy10并设置密码(密码不能相同)。

问题4:批量创建10个系统账号hy01-hy10并设置密码(密码为随机8位字符串)。

 

首先我们看一下Linux系统产生随机数的6种方法:

法1:通过环境变量($RANDOM)

[root@vm1 ~]# echo $RANDOM //生成随机字符串,注意必须是大写的

407

[root@vm1 ~]# echo $RANDOM

25323

[root@vm1 ~]# echo $RANDOM |md5sum 

90cd97bddf48d363501657d4fd146a29  -

[root@vm1 ~]# echo $RANDOM |md5sum |cut -c 15-22

510d0dad

[root@vm1 ~]# echo "$RANDOM$(date +%N%t)" |md5sum |cut -c 15-22

3584e8a4

[root@vm1 ~]# echo "$(date +%N%t)"

071768889

法2:通过openssl产生随机数

[root@vm1 ~]# openssl rand -base64 8

nC3sA9PwJ2A=

[root@vm1 ~]# openssl rand -base64 8 |md5sum 

550e53355fe9a93b695c5734b453a7d4  -

法3:通过时间获得随机数(date)

[root@vm1 ~]# date +%s%N

1425193783826121785

法4:

说明:/dev/random设备,存储着系统当前运行环境的实时数据。它可以看作是系统某个时候,唯一值数据,因此可以用做随机数元数据。我们可以通过文件读取方式,读得里面数据。/dev/random这个设备数据与random里面一样。只是,它是非阻塞的随机数发生器,读取操作不会产生阻塞。

[root@vm1 ~]# head /dev/urandom |cksum 

2019172889 4161

[root@vm1 ~]# head /dev/urandom |cksum 

1926990877 3707

法5:

说明:UUID码全称是通用唯一识别码(Universally Unique Identifier,UUID),它是一个软件构建的标准,亦为自由软件基金会(Open Software Foundation,OSF)的组织在分布式计算环境(Distributed Computing Environment,DCE)领域的一部分。

UUID的目的,是让分布式系统中的所有元素,都能有唯一的辨识信息,而不需要通过中央控制端来做辨识信息的指定。如此以来,每个人都可以创建不与其他人冲突的UUID。在这样的情况下,就不需要考虑数据库创建的名称重复问题。它会让网络任何一台计算机所生成的UUID码,都是互联网整个服务器网络中唯一的。它的原信息会加入硬件,时间,机器当前运行信息等等。

UUID格式是:包含32个16进位数字,以“_”连接号分为五段,形式为8-4-4-4-12的32个字符。范例: ,所以:UUID理论上的总数为216x8=2128,约3.4x1038。也就是说若每奈秒产生1兆个UUID,要花100亿年才会将所有UUID用完。

[root@vm1 ~]# cat /proc/sys/kernel/random/uuid 

0e0d49d8-5bcc-45ee-8997-b396c4e19166

[root@vm1 ~]# cat /proc/sys/kernel/random/uuid 

418e6bfd-84d9-43f0-81b1-5c31d0ca7299

法6:

[root@vm1 ~]# yum install expect -y

[root@vm1 ~]# mkpasswd -l 8

y6xsIH0%

[root@vm1 ~]# mkpasswd -l 10

ugh~26UvhF

[root@vm1 ~]# mkpasswd 

6Vc9np!vG

[root@vm1 ~]# mkpasswd |md5sum 

13fe3c0a58bf4a45f62cf9f04823af75  -

[root@vm1 ~]# mkpasswd -s 0

6QZvtnl6y

接下来可以做一下测试:

[root@vm1 ~]# for n in `seq 20`;do echo $RANDOM | md5sum |cut -c 1-9 |sort;done|uniq -c|sort -nk1

      1 9bd8901bd

      1 3c48a44eb

      1 1133ef500

      1 5292813ff

      1 9450f6e72

      1 d974b28e8

      1 3cf34dbb0

      1 eb745c2e2

      1 38c2a4b46

      1 29169cc32

      1 5ad39e4aa

      1 df75bcd8f

      1 cdd8caac3

      1 9c4de78ed

      1 28142141f

      1 3713969da

      1 1c25e7d82

      1 381144d62

      1 ebc7c6fe3

      1 bc909ea55

[root@vm1 ~]# for n in `seq 20`;do date +%s%N | md5sum |cut -c 1-9 |sort;done |uniq -c|sort -nk1

      1 4990645b3

      1 dc539afaa

      1 2b8ec3334

      1 02cfd2ed7

      1 3dc97e660

      1 a430a3c13

      1 1aa42a9c1

      1 d7ee33537

      1 bf7053d18

      1 5b772fb2b

      1 2e1be8ce2

      1 d5f1eeb66

      1 bc66db35c

      1 93a4e633d

      1 c9b7cdfd4

      1 0d9452599

      1 c7352ab46

      1 4cb04a6cb

      1 1b163309f

      1 7855f1240

[root@vm1 ~]# for n in `seq 20`;do date +%F | md5sum |cut -c 1-9 |sort;done |uniq -c|sort -nk1

     20 be7979ded

 

企业面试题1:

写一个脚本,实现判断10.0.0.0/24网络里,当前在线用户的IP有那些(方法很多)

 

1.5break continue exit

1.5.1break continue exit对比

break continue exit一般用于循环结构中控制循环的走向。


1.5.2 break continue exit范例

下面举几个break、continue、exit的例子

范例1:break跳出整个循环,执行循环下面的其他程序

[root@vm1 ~]# vim break-1.sh

for ((i=0;i<=5;i++))

do

        if [ $i -eq 3 ];then

                #continue;

                break;

                #exit;

        fi

        echo $i

done

echo "ok"

[root@vm1 ~]# sh break-1.sh 

0

1

2

ok

范例(生产场景):开发shell脚本实现给服务器临时配置多个别名IP,并可以随时撤消配置的所有IP。IP地址为:10.0.0.1-10.0.0.15,其中10.0.0.10不能配置。

首先我们会想到continue

for ((i=0;i<=15;i++))

do

        if [ $i -eq 10 ];then

                continue;

                #exit;

        fi

        ifconfig eth0:$i 10.0.0.$i netmask 255.255.240.0 up

done

echo "ok"

然后根据上面的思路完善脚本,通过用户输入控制ip地址的添加和删除,得到如下脚本:

[root@vm1 ~]# vim continue_ip.sh 

#!/bin/sh

#create by hy

#1020659371@qq.com

#config ip add

RE=0

case "$1" in

up)

for ((i=0;i<=15;i++))

do

        if [ $i -eq 10 ];then

                continue;

                #exit;

        fi

        ifconfig eth0:$i 10.0.0.$i netmask 255.255.240.0 $1

done

echo "ok"

;;

 

down)

for ((i=0;i<=15;i++))

do

        if [ $i -eq 10 ];then

                continue;

                #exit;

        fi

        ifconfig eth0:$i 10.0.0.$i netmask 255.255.240.0 $1

done

echo "ok"

;;

 

*)

        echo "Usage:$0 {up|down}"

;;

 

esac

exit $RE

上述这样做在系统服务启动脚本中十分有用,从这个例子,我们应该学会举一反三。另外我们从上面的例子中可以看出我们并没有重启网卡,这是生产环境中的大忌,绝对不能重启网卡,重启后我们的连接会直接断掉,也不能重启系统,另外有可能我们的一些线上服务会出现问题。

从上面的例子我们可以看到break、continue、exit的区别了?如果还是没有弄清除请看表格

 

1.6shell函数

1.6.1shell函数语法

语法格式:

简单的语法:

函数名(){

指令...

return n

}

规范的语法:

Function 函数名(){

指令...

return n

}

1.6.2shell函数执行

调用函数

1)直接执行函数名即可。注意,不需要带小括号了。

函数名

2)带参数的函数执行方法

函数名 参数1 参数2

【函数带参数的说明】

l 在函数体中位置参数($1、$2、$3、$4、$5、$#、$*、$?以及$@)都可以是函数的参数

l 父脚本的参数则临时地被函数所掩盖或隐藏。

l $0比较特殊,他仍然是父脚本的名称。

l 当函数完成的时候原来的命令行参数会恢复。

l 在shell函数里面,return命令的功能与工作方式与exit相同,用于跳出函数。

l 在shell函数体里使用exit会终止整个shell脚本。

l Return语句会返回一个退出值给调用的程序。

1.6.3shell函数范例

范例1:开发脚本建立两个简单函数并调用执行

[root@vm1 ~]# vim func-0.sh

#!/bin/bash

husiyang(){

        echo "I am dadoubi"

}

 

function tangpeng(){

        echo "I am doubi"

}

husiyang <——在一个脚本里调用函数

tangpeng <——在一个脚本里调用函数

#定义两个函数husiyang和tangpeng

范例2:把函数体和执行的脚本分离(规范的方法)

[root@vm1 ~]# vim /etc/init.d/hy_functions

#!/bin/bash

husiyang(){

        echo "I am dadoubi"

}

 

function tangpeng(){

        echo "I am doubi"

}

[root@vm1 ~]# chmod +x /etc/init.d/hy_functions 

[root@vm1 ~]# ls -l /etc/init.d/hy_functions 

-rwxr-xr-x 1 root root 90 3月   1 22:32 /etc/init.d/hy_functions

(2)开发执行脚本调用上述函数

[root@vm1 ~]# vim func-exec.sh

#!/bin/bash

#加载函数

[ -x /etc/init.d/hy_functions ] && . /etc/init.d/hy_functions || exit

#提示,可以用source或.(点号)来加载脚本function.sh中的命令或变量参数等。

#调用函数

husiyang

tangpeng

提示:

1)注意调用函数的函数名,及函数脚本路径的写法,不带括号吆!

2)函数一定要在调用之前定义。

执行

[root@vm1 ~]# sh func-exec.sh 

I am dadoubi

I am doubi

范例3:带参数的shell函数例子

[root@vm1 ~]# vim func-2.sh

#!/bin/bash

function Check_Url(){

        curl -I -s $1 |head -1 && return 0 || return 1

}

 

Check_Url oschina.net 如果是想接受命令行传参,我们就是用$1

[root@vm1 ~]# sh func-2.sh 

HTTP/1.1 301 Moved Permanently

如果我们定义的是服务器的url的话,我们可以在服务器上停掉80端口,然后使用lsof -i :80去检测80端口是否还是开启状态,然后再次进行检测。

范例4:从命令行传参

[root@vm1 ~]# sh func-3.sh

#!/bin/bash

if [ $# -ne 1 ] //注意这里的$#是计算输入参数的个数

then

        echo "error" && exit 1

fi

 

function Check_Url(){

        curl -I -s $1 |head -1 && return 0 || return 1

}

 

Check_Url $1

[root@vm1 ~]# sh func-3.sh oschina.net

HTTP/1.1 301 Moved Permanently

范例5:/etc/init.d/rpcbind     //也就是企业5里面的portmap脚本

#! /bin/sh

#

# rpcbind       Start/Stop RPCbind

#

# chkconfig: 2345 13 87

# description: The rpcbind utility is a server that converts RPC program \

#              numbers into universal addresses. It must be running on the \

#              host to be able to make RPC calls on a server on that machine.

#

# processname: rpcbind

# probe: true

# config: /etc/sysconfig/rpcbind

 

 

# This is an interactive program, we need the current locale

[ -f /etc/profile.d/lang.sh ] && . /etc/profile.d/lang.sh

# We can't Japanese on normal console at boot time, so force LANG=C.

if [ "$LANG" = "ja" -o "$LANG" = "ja_JP.eucJP" ]; then

    if [ "$TERM" = "linux" ] ; then

        LANG=C

    fi

fi

 

# Source function library.

. /etc/init.d/functions

 

# Source networking configuration.

[ -f /etc/sysconfig/network ] &&  . /etc/sysconfig/network

 

prog="rpcbind"

[ -f /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog

 

RETVAL=0

uid=`id | cut -d\( -f1 | cut -d= -f2`

 

start() {

        # Check that networking is up.

        [ "$NETWORKING" = "yes" ] || exit 6

 

        [ -f /sbin/$prog ] || exit 5

 

        # Make sure the rpcbind is not already running.

        if status $prog > /dev/null ; then

                exit 0

        fi

 

        # Only root can start the service

        [ $uid -ne 0 ] && exit 4

 

        echo -n $"Starting $prog: "

        daemon $prog $1 "$RPCBIND_ARGS"

        RETVAL=$?

        echo

        if [ $RETVAL -eq 0 ] ; then

                touch /var/lock/subsys/$prog

                [ ! -f /var/run/rpcbind.pid ] &&

                        /sbin/pidof $prog > /var/run/rpcbind.pid

        fi

        return $RETVAL

}

 

 

stop() {

        echo -n $"Stopping $prog: "

        killproc $prog

        RETVAL=$?

        echo

        [ $RETVAL -eq 0 ] && {

                rm -f /var/lock/subsys/$prog

                rm -f /var/run/rpcbind*

        }

        return $RETVAL

}

 

# See how we were called.

case "$1" in

  start)

        start

        RETVAL=$?

        ;;

  stop)

        stop

        RETVAL=$?

        ;;

  status)

        status $prog

        RETVAL=$?

        ;;

  restart | reload| force-reload)

        stop

        start

        RETVAL=$?

        ;;

  condrestart | try-restart)

        if [ -f /var/lock/subsys/$prog ]; then

                stop

                start -w

                RETVAL=$?

        fi

        ;;

  *)

        echo $"Usage: $0 {start|stop|status|restart|reload|force-reload|condrestart|try-restart}"

        RETVAL=2

        ;;

esac

 

exit $RETVAL

范例6:/etc/init.d/httpd

#!/bin/bash

#

# httpd        Startup script for the Apache HTTP Server

#

# chkconfig: - 85 15

# description: The Apache HTTP Server is an efficient and extensible  \

#              server implementing the current HTTP standards.

# processname: httpd

# config: /etc/httpd/conf/httpd.conf

# config: /etc/sysconfig/httpd

# pidfile: /var/run/httpd/httpd.pid

#

### BEGIN INIT INFO

# Provides: httpd

# Required-Start: $local_fs $remote_fs $network $named

# Required-Stop: $local_fs $remote_fs $network

# Should-Start: distcache

# Short-Description: start and stop Apache HTTP Server

# Description: The Apache HTTP Server is an extensible server 

#  implementing the current HTTP standards.

### END INIT INFO

 

# Source function library.

. /etc/rc.d/init.d/functions

 

if [ -f /etc/sysconfig/httpd ]; then

        . /etc/sysconfig/httpd

fi

 

# Start httpd in the C locale by default.

HTTPD_LANG=${HTTPD_LANG-"C"}

 

# This will prevent initlog from swallowing up a pass-phrase prompt if

# mod_ssl needs a pass-phrase from the user.

INITLOG_ARGS=""

 

# Set HTTPD=/usr/sbin/httpd.worker in /etc/sysconfig/httpd to use a server

# with the thread-based "worker" MPM; BE WARNED that some modules may not

# work correctly with a thread-based MPM; notably PHP will refuse to start.

 

# Path to the apachectl script, server binary, and short-form for messages.

apachectl=/usr/sbin/apachectl

httpd=${HTTPD-/usr/sbin/httpd}

prog=httpd

pidfile=${PIDFILE-/var/run/httpd/httpd.pid}

lockfile=${LOCKFILE-/var/lock/subsys/httpd}

RETVAL=0

STOP_TIMEOUT=${STOP_TIMEOUT-10}

 

# The semantics of these two functions differ from the way apachectl does

# things -- attempting to start while running is a failure, and shutdown

# when not running is also a failure.  So we just do it the way init scripts

# are expected to behave here.

start() {

        echo -n $"Starting $prog: "

        LANG=$HTTPD_LANG daemon --pidfile=${pidfile} $httpd $OPTIONS

        RETVAL=$?

        echo

        [ $RETVAL = 0 ] && touch ${lockfile}

        return $RETVAL

}

 

# When stopping httpd, a delay (of default 10 second) is required

# before SIGKILLing the httpd parent; this gives enough time for the

# httpd parent to SIGKILL any errant children.

stop() {

        echo -n $"Stopping $prog: "

        killproc -p ${pidfile} -d ${STOP_TIMEOUT} $httpd

        RETVAL=$?

        echo

        [ $RETVAL = 0 ] && rm -f ${lockfile} ${pidfile}

}

reload() {

    echo -n $"Reloading $prog: "

    if ! LANG=$HTTPD_LANG $httpd $OPTIONS -t >&/dev/null; then

        RETVAL=6

        echo $"not reloading due to configuration syntax error"

        failure $"not reloading $httpd due to configuration syntax error"

    else

        # Force LSB behaviour from killproc

        LSB=1 killproc -p ${pidfile} $httpd -HUP

        RETVAL=$?

        if [ $RETVAL -eq 7 ]; then

            failure $"httpd shutdown"

        fi

    fi

    echo

}

 

# See how we were called.

case "$1" in

  start)

        start

        ;;

  stop)

        stop

        ;;

  status)

        status -p ${pidfile} $httpd

        RETVAL=$?

        ;;

  restart)

        stop

        start

        ;;

  condrestart|try-restart)

        if status -p ${pidfile} $httpd >&/dev/null; then

                stop

                start

        fi

        ;;

  force-reload|reload)

        reload

        ;;

  graceful|help|configtest|fullstatus)

        $apachectl $@

        RETVAL=$?

        ;;

  *)

        echo $"Usage: $prog {start|stop|restart|condrestart|try-restart|force-reload|reload|status|fullstatus|graceful|help|configtest}"

        RETVAL=2

esac

 

exit $RETVAL

范例7:生产环境批量检查web服务是否正常并且发送相关邮件或手机报警

[root@vm1 ~]# vim check_url_by_hy.sh 

#!/bin/bash

#this script is created by hy.

#e_mail:1020659371@qq.com

#qqinfo:1020659371

#function:hy trainning scripts,check_service.

#version:1.1

###################################################

#hy trainning info

#QQ 1020659371

###################################################

. /etc/init.d/functions

 

RETVAL=0

FAILCOUNT=0

SCRIPTS_PATH="/root"

MAIL_GROUP="1020659371@qq.com 1161629766@qq.com"

#Mobile_GROP="13227018723"

##web detection function

LOG_FILE="/tmp/web_check.log"

function Get_Url_Status(){

        for ((i=1;i<=3;i++))

        do

                wget -T 10 --tries=1 --spider {1} >/dev/null 2>&1

                [ $? -ne 0 ] && let FAILCOUNT+=1;

        done

        #if 3 times then send mail

        if [ $FAILCOUNT -gt 1 ];then

                RETVAL=1

                NowTime=`date +"%m-%d %H:%M:%S"`

                SUBJECT_CONTENT="{HOST_NAME} service is error,${NowTime}."

                echo "send to:$MAIL_USER,Title:$SUBJECT_CONTENT" >$LOG_FILE

                for MAIL_USER in cat $MAIL_GROUP

                do

                        mail -s "$SUBJECT_CONTENT" $MAIL_USER <$LOG_FILE

                done

        else

                RETVAL=0

        fi

        return $RETVAL

}

 

#func.end

[ ! -d "$SCRIPTS_PATH" ] && mkdir -p $SCRIPTS_PATH

#[ ! -f "$SCRIPTS_PATH/domain.list" ] && {

cat >$SCRIPTS_PATH/domain.list<

192.168.2.2

xupt.org

EOF

#}

 

#service check

for HOST_NAME in $(cat $SCRIPTS_PATH/domain.list)

do

        echo -n "checking $HOST_NAME:"

        Get_Url_Status $HOST_NAME && echo ok || echo no

done

[root@vm1 ~]# sh check_url_by_hy.sh 

checking 192.168.2.2:ok

checking :ok

checking :ok

checking xupt.org:no

提示:上面的脚本在工作中一般用于服务重启后的快速检查,可以和启动脚本放在一起(此时无需发邮件)。

如果通过定时任务处理,则为下面的脚本

#!/bin/bash

#this script is created by hy.

#e_mail:1020659371@qq.com

#qqinfo:1020659371

#function:hy trainning scripts,check_service.

#version:1.1

###################################################

#hy trainning info

#QQ 1020659371

###################################################

. /etc/init.d/functions

 

RETVAL=0

FAILCOUNT=0

SCRIPTS_PATH="/root"

#MAIL_GROUP="1020659371@qq.com 1161629766@qq.com"

MAIL_GROUP="13227018723"

##web detection function

LOG_FILE="/tmp/web_check.log"

function Get_Url_Status(){

        for ((i=1;i<=3;i++))

        do

                wget -T 10 --tries=1 --spider {1} >/dev/null 2>&1

                [ $? -ne 0 ] && let FAILCOUNT+=1;

        done

        #if 3 times then send mail

        if [ $FAILCOUNT -gt 1 ];then

                RETVAL=1

                NowTime=`date +"%m-%d %H:%M:%S"`

                SUBJECT_CONTENT="{HOST_NAME} service is error,${NowTime}."

                echo "send to:$MAIL_USER,Title:$SUBJECT_CONTENT" >$LOG_FILE

                for MAIL_USER in cat $MAIL_GROUP

                do

                        mail -s "$SUBJECT_CONTENT" $MAIL_USER <$LOG_FILE

                done

        else

                RETVAL=0

        fi

        return $RETVAL

 

}

 

#func.end

[ ! -d "$SCRIPTS_PATH" ] && mkdir -p $SCRIPTS_PATH

#[ ! -f "$SCRIPTS_PATH/domain.list" ] && {

cat >$SCRIPTS_PATH/domain.list<

192.168.2.2

xupt.org

EOF

#}

 

#service check

for URL in $(cat $SCRIPTS_PATH/domain.list)

do

        Get_Url_Status $URL

done

范例8:在开始编写shell脚本之前,请回忆一下,如何优化linux系统?

(1)先编写剧本<==请看第二节课第11个考试题

11.如何优化linux系统(可以不说太具体)?

解答:

根据上周和本周讲的,我们先来10点,后续将课在逐渐添加。

1.精简安装包(最小化安装)

2.配置国内高速yum源。

3.禁用开机不需要的启动的服务。

4.优化内核参数/etc/sysctl.conf。

5.增加系统文件描述符、堆栈等配置。

6.禁止root远程登录,修改SSH端口为特殊端口,禁用DNS,空密码。

7.有外网IP的机器要开启配置防火墙,仅对开启需要提供服务的端口,配置或关闭SELINUX。

8.清除无用的默认系统账户或组(非必须)(添加运维成员的用户)。

9.锁定敏感文件,如/etc/passwd(非必须)。

10.配置服务器和互联网时间同步。

11.配置sudo对普通用户权限精细控制。

12.把以上11点写成一键优化脚本。

...更多优化后面还会将的....

锁定敏感文件用

[root@vm1 ~]# chattr +i /etc/passwd 将passwd这个文件锁定后我们将不能去修改这个文件

[root@vm1 ~]# useradd kkk

useradd: cannot open /etc/passwd

[root@vm1 ~]# rm -fr /etc/passwd

rm: cannot remove `/etc/passwd': Operation not permitted

[root@vm1 ~]# lsattr /etc/passwd  

----i--------e- /etc/passwd

[root@vm1 ~]# chattr -i /etc/passwd

第11题总结:

1)本题主要考虑linux系统优化的总结能力,面试时可能会问到,总结时可以分点按脉诺简单总结(用于口头表述),如果是实战优化,需要逐点详细研究并总结。

2)要求同学们能口述出来本题的答案。

3)总结时先按照脉络把要点简单总结,用口头表述,今后jin时间允许,再逐项一点一点深入研究。这样,慢慢就对系统优化逐步擅长了。

4)后续会有几十条超强优化措施,呵呵,慢慢来吧。本文的这些已经够基本工作用了。

(2)开始游戏

  1 #!/bin/bash

  2 #set env

  3 export PATH=$PATH:/bin:/sbin:/usr/sbin

  4 export LANG="zh_CN.GB18030"

  5 

  6 #Require root to run this script.

  7 if [[ "$(whomi)"!="root" ]];then

  8         echo "Please run this script as root.">&2

  9         exit 1

 10 fi

 11 

 12 #define cmd var

 13 SERVICE=`which service`

 14 CHKCONFIG=`which chkconfig`

 15 

 16 #Source function library

 17 . /etc/init.d/functions

 18 

 19 #Config Yum Centos-Base.repo

 20 ConfigYum(){

 21         echo "Config Yum Centos-Base.repo."

 22         cd /etc/yum.repo.d/

 23         \cp Centos-Base.repo Centos-Base.repo.hy.$(date +%F)

 24         ping -c 1 baidu.com >/dev/null

 25         [ ! $? -eq 0 ] && echo $"Networking not configured - exiting" && exit 1

 26         wget --quiet -o /dev/null 

 27         \cp CentOS-Base-sohu.repo CentOS-Base.repo

 28 }

 29 

 30 #Install Chinese Package

 31 #yum -y install fonts-chinese fonts-ISO8859-2 >/dev/null 2>&1

 32 installTool(){

 33         echo "sysstat ntp net-snmp lrzsz rsync"

 34         yum -y install sysstat ntp net-snmp lrzsz rsync >/dev/null 2>&1

 35 }

 36 #Charset GB18030

 37 initT18n(){

 38         echo "#set LANG="zh_cn.gb18030""

 39         \cp /etc/sysconfig/i18n /etc/sysconfig/i18n..$(date +%F)

 40         sed -i 's#LANG="en_US.UTF-8"#LANG="zh_CN.GB18030"#' /etc/sysconfig/i18n

 41         source LANG /etc/sysconfig/i18n

 42         sleep 1

 43 }

 44 #Close Selinux and Iptables

 45 initFirewall(){

 46         echo "#Close Selinux and Iptables"

 47         cp /etc/selinux/config /etc/selinux/config.`date +"%Y-%m-%d_%H-%M-%S"`

 48         /etc/init.d/iptables stop

 49         sed -i 's/SELINUX=enable/SELINUX=disabled/' /etc/selinux/config

 50         setenforce 0

 51         /etc/init.d/iptables status

 52         grep SELINUX=disabled /etc/selinux/config

 53         echo "Close selinux->OK and iptables->OK"

 54         sleep 1

 55 }

 56 

 57 #Init Auto Startup Service

 58 initService(){

 59         echo "Close Nouseful Service"

 60         export LANG="en_US.UTF-8"

 61         for hy in `chkconfig --list | grep 3:on |awk '{print $1}';do chkconfig --level 3 $hy off;done`

 62         for hy in crond network syslog sshy;do chkconfig --level 3 $hy on;done

 63         export LANG="zh_CN.GB18030"

 64         echo "关闭不需要的服务->OK"

 65         sleep 1

 66 }

 67 

 68 initSsh(){

 69         echo "#----------sshconfig修改ssh默认登录端口,禁止root登录-----------"

 70         \cp /etc/sshsshhy_config /etc/ssh/sshy_config.`date +"%Y-%m-%d_%H-%M-%S"`

 71         sed -i 's%#Port 22%Port 52113%' /etc/ssh/sshy_config

 72         sed -i 's%#PermitRootLogin yes%PermitRootLogib no%' /etc/ssh/sshy_config

 73         sed -i 's%#UseDNS yes%UseDNS no%' /etc/ssh/sshy_config

 74         /etc/init.d/sshy reload && action $"修改ssh默认端口,禁止root登录:" /bin/true || action $"修改ssh默认端口,禁止root登录:" /bin/false

 75 }

 76 

 77 AddSAUser(){

 78         echo "#--------添加为系统用户-----------------#"

 79         datetmp=`date +"%Y-%m-%d_%H-%M-%S"

 80         \cp /etc/sudoers /etc/sudoers.${datetmp}`

 81         saUserArr=(hy hy1 hy2)

 82         groupadd -g 888 sa

 83         for((i=0;i<${#saUserArr[];i++}))

 84         do

 85                 #添加用户

 86                 useradd -g sa -u 88${i} ${saUserArr[$i]}

 87                 #设置密码

 88                 echo "${saUserArr[$i]}123"|passwd ${saUserArr[$i]} --stdin

 89                 #设置sudo权限

 90                 #[ $(grep "${saUserArr[$i]} ALL=(ALL) NOPASSWD:ALL" /etc/sudoers | wc -l) -le 0 ] && echo "${saUserArr[$i]} ALL=(ALL) NOPASSWD:ALL    " >>/etc/sudoers

 91                 [ `grep "\%sa"|grep -v grep |wc -l` -ne 1 ] && \

 92                 echo "%sa       ALL=(ALL)       NOPASSWD:ALL">>/etc/sudoers

 93         done

 94         /usr/sbin/visudo -c

 95         [ $? -ne 0 ] && /bin/cp /etc/sudoers.${datetmp} /etc/sudoers && echo $"Sudoers not configured - exiting" && exit 1

 96         action $"用户添加成功-->OK" /bin/true

 97 }

 98 

 99 #设置系统同步时间--------------------------------------

100 syncSystemTime(){

101         #同步时间

102         if [ `grep pool.ntp.org /var/spool/cron/root |grep -v grep|wc -l` -lt 1 ];then

103         echo "*/5 * * * * /usr/sbin/ntpdate cn.pool.ntp.org >/dev/null 2>&1" >>/var/spool/cron/root

104         fi

105 }

106 

107 #调整打开文件数

108 openFiles(){

109         echo "---------调整最大打开系统文件个数65535个--------------"

110         \cp /etc/security/limits.conf /etc/security/limits.conf.`date +"%Y-%m-%d_%H-%M-%S"`

111         sed -i '/#End of file/i\*\t\t-\tnofile\t\t65535' /etc/security/limits.conf

112         ulimit -HSn 65535

113         echo "调整最大打开系统文件个数成功!(修改后重新登录生效)"

114         sleep 1

115 }

116 

117 #优化系统内核------------------------------------#

118 optimizationKernel(){

119         echo "优化系统内核---->"

120         \cp /etc/sysctl.conf /etc/sysctl.conf.`date +"%Y-%m-%d_%H-%M-%S"`

121         cat>>/etc/sysctl.conf<

122                 net.ipv4.tcp_timestamps = 0

123                 net.ipv4.tcp_synack_retries = 2

124                 net.ipv4.tcp_syn_retries = 2

125                 net.ipv4.tcp_mem = 94500000 915000000 92700000

126                 net.ipv4.tcp_max_orphans = 3276800

127                 net.core.wmem_default = 8388608

128                 net.core.rmem_default = 8388608

129                 net.core.rmem_max = 16777216

130                 net.core.wmem_max = 16777216

131                 net.ipv4.tcp_rmem = 4096 87380 16777216

132                 net.ipv4.tcp_wmem = 4096 65536 16777216

133                 net.core.netdev_max_backlog = 32768

134                 net.core.somaxconn = 32768

135                 net.ipv4.tcp_syncookies = 1

136                 net.ipv4.tcp_tw_reuse = 1

137                 net.ipv4.tcp_tw_recycle = 1

138                 net.ipv4.tcp_fin_timeout = 1

139                 net.ipv4.tcp_keepalive_time = 600

140                 net.ipv4.tcp_max_syn_backlog = 65536

141                 net.ipv4.ip_local_port_range = 1024 65535

142 EOF

143 /sbin/sysctl -p && action $"内核优化:"/bin/ture || action $"内核优化:" /bin/false

144 }

145 

146 #---------------------------------------------------------#

147 init_safe(){

148         echo "------------------禁止ctrl+alt+del三个键重启系统-----------"

149         cp /etc/inittab /etc/inittab.`date +"%Y-%m-%d_%H-%M-%S"`

150         sed -i "s/ca::ctrlaltdel:\/sbin\/shutdown -t3 -r now/#ca::ctrlaltdel:\/sbin\/shutdown -t3 -r now/" /etc/inittab

151         /sbin/init q

152         [ $? -eq 0 ] && action $"禁止ctrl+alt+del三个键重启系统:" /bin/true ||

153 action $"禁止ctrl+alt+del三个键重启系统:" /bin/false

154 }

 

1.7Shell数组

1.7.1数组介绍

简单的而说,数组就是相同数据类型的元素按一定顺序排列的集合。

数组就是把有限个类型相同的变量用一个名字命名,然后用编号区分他们的变量集合,这个名字成为数组名,编号成为下标,组成数组的各个变量成为数组的分量,也称为数组的元素,有时也称为下标变量。

如果有过用其它语言编程的经历,那么想必会熟悉数组的概念。由于有了数组,可以用相同名字引用一系列变量,并用数字(索引)来识别它们。在许多场合,使用数组可以缩短和简化程序,因为可以利用索引值设计一个循环,高效处理多种情况。

1.7.2数组定义与读取

方法1:array=(value1 value2 value3...)

1)数组定义

[root@vm1 ~]# array=(1 2 3) <===对括号表示是数组,数组元素用“空格”符号分开

2)获取数组的长度

[root@vm1 ~]# echo ${#array[@]} <=====用${#数组名[@或*]}可以得到数组长度

3

[root@vm1 ~]# echo ${#array[*]}

3

3)打印数组元素

[root@vm1 ~]#  echo ${array[0]}

1

[root@vm1 ~]#  echo ${array[1]}

2

[root@vm1 ~]#  echo ${array[2]}

3

[root@vm1 ~]#  echo ${array[3]}

 

[root@vm1 ~]# echo ${array[@]} <====下标是:*或者@得到整个数组内容。

1 2 3

[root@vm1 ~]# echo ${array[*]} <====把前面取数组长度的#号去掉

1 2 3

4)数组赋值

直接通过 数组名[下标] 就可以对其进行引用赋值,如果下标不存在,自动添加新一个数组元素,如果存在就覆盖原来的值。

[root@vm1 ~]#  echo ${array[3]}

4

[root@vm1 ~]# echo ${array[@]}

1 2 3 4

[root@vm1 ~]# echo ${#array[@]}

4

5)数组删除

直接通过:unset 数组[下标] 可以清除相应的元素,不带下标,清除整个数据。

[root@vm1 ~]# array=(1 2 3 4)

[root@vm1 ~]# echo ${array[@]}

1 2 3 4

[root@vm1 ~]# array[1]=hy <=====修改数组的元素

[root@vm1 ~]# echo ${array[@]}

1 hy 3 4

[root@vm1 ~]# unset array[3] <=====删除数组元素

[root@vm1 ~]# echo ${array[@]}

1 2 3

[root@vm1 ~]# unset array <=====删除整个数组元素

[root@vm1 ~]# echo ${array[@]}

 

6)数组内容的截取和替换(和前文变量子串的替换很像)

截取:

[root@vm1 ~]# echo ${array[@]}

1 2 3 4 5

[root@vm1 ~]# echo ${array[@]:1:3} <===从第二个元素开始截取3个元素

2 3 4

[root@vm1 ~]# echo ${array[@]:3:2}

4 5

替换:

[root@vm1 ~]# echo ${array[@]/5/6} <====把数组中的5替换成6,临时生效,原数组未被修改,和sed很像

1 2 3 4 6

[root@vm1 ~]# echo ${array[@]}

1 2 3 4 5

[root@vm1 ~]# array1=(${array[@]/5/6})

[root@vm1 ~]# echo ${array[@]}

1 2 3 4 5

[root@vm1 ~]# echo ${array1[@]}

1 2 3 4 6

调用方法是:${数组名[@或*]/查找字符/替换字符} 该操作不会改变原先数组内容,如果需要修改,可以看上面例子,重新定义数

删除:

[root@vm1 ~]# array1=(one two three four five)

[root@vm1 ~]# echo ${array1[@]}

one two three four five

[root@vm1 ~]# echo ${array1[@]o}

one two three four five

[root@vm1 ~]# echo ${array1[@]#o}

ne two three four five

[root@vm1 ~]# echo ${array1[@]#fo}

one two three ur five

[root@vm1 ~]# echo ${array1[@]%t*e}

one two four five

[root@vm1 ~]# echo ${array1[@]%%t*e}

one two four five

提示:数组也是变量,因此也适合于前面讲解过的变量的子串处理的功能应用。

参考:

man bash然后Arrays(一手资料)

http://www.cnblogs.com/chengmo/archive/2010/09/30/1839632.html

 

方法2:array=([1]=one [2]=two [3]=three)

[root@vm1 ~]# array=([1]=one [2]=two [3]=three)

[root@vm1 ~]# echo ${array[@]}

one two three

方法3:array[0]=a array[1]=b array[2]=c

[root@vm1 ~]# array[0]=a;array[1]=b;array[2]=c;array[3]=d

[root@vm1 ~]# echo ${array[@]}

a b c d

方法4:declare -a array

方法5:array=($(ls))

1.7.3数组实践实战例子

范例1:通过列举法打印数组元素

列举元素写法:

array=(red green blue yellow magenta)

array=(

        hy

        tangpeng

        husiyang

)

实践:

[root@vm1 ~]# vim array.sh

array=(

hy

tangpeng

husiyang

)

 

for ((i=0;i<${#array[*]};i++))

do

        echo "This is num $i,then content is ${array[i]}"

done

echo -------------------------

echo "array len:${#array[*]}"

[root@vm1 ~]# sh array.sh 

This is num 0,then content is hy

This is num 1,then content is tangpeng

This is num 2,then content is husiyang

-------------------------

array len:3

范例2:定义系统命令结果做为数组元素

[root@vm1 ~]# dir=($(ls))

[root@vm1 ~]# echo ${dir[*]}

array.sh break-1.sh check_init.sh check_url_by_hy.sh continue_ip.sh continue.sh create_ip.sh domain.list exit.sh func-0.sh func-2.sh func-exec.sh system_tiaoyou.sh

[root@vm1 ~]# echo ${#dir[*]}

13

范例3:比较专业的生产检查URL地址的脚本(shell数组方法)

[root@vm1 ~]# vim check_url1.sh

#function:case example

#version:1.1

. /etc/init.d/functions

 

url_list=(

http://

)

 

function wait(){

        echo -n '3秒后,执行该操作.'

        for ((i=0;i<3;i++))

        do

                echo -n ".";

                sleep 1

        done

        echo

}

 

function check_url(){

        wait

        echo 'check url...'

        for ((i=0;i<${#url_list[*]};i++))

        do

                #HTTP/1.1 200 OK

                judge=($(curl -I -s --connect-timeout 2 ${url_list[$i]}|head -1|tr "\r" "\n"))

                #judge=($(curl -o /dev/null -s -w "%{http_code}" "${url_list[$i]}"))

                if [[ "${judge[1]}" == '200' && "${judge[2]}" == 'OK' ]]

                        then

                        action "${url_list[$i]}" /bin/true

                else

                        action "${url_list[$i]}" /bin/false

                fi

        done

}

 

check_url

[root@vm1 ~]# sh check_url1.sh 

3秒后,执行该操作....

check url...

http://                                     [  OK  ]

                                       [  OK  ]

                                         [  OK  ]

提示:通过上面的例子我们可以看到通过man或者--help的好处,我们可以查到curl的一些参数的描述。

范例4:实战开发脚本监控Mysql主从同步(shell数组方法)

 

考试题:开发一个守护进程脚本30秒监控MySQL主从同步是否异常,如果异常,则发送短信或者邮件给管理员。

提示:如果没主从同步环境,可以用下面文本放到文件里读取来模拟:

[root@vm1 ~]# mysql -u root -p westos -S /data/3307/mysql.sock -e "show slave status\G;"

[root@vm1 ~]# vim check_mysql_slave_status.sh

#!/bin/bash

################################################

# this script function is:

# check_mysql_slave_relication_status

# USER          YYYY-MM-DD - ACTION

# hy            2015-03-03 - Created

################################################

parasnum=2

#function

help_msg()

{

cat << help

+-----------------------------------------------------+

+ Error Cause:

+ you enter $# parameters

+ the total paramenter number must be $parasnum

+ 1st :HOST_IP

+ 2nd :HOST_PORT

+------------------------------------------------------+

help

exit

}

 

#--------------------------------------------------------

#check paramenter number

[ $# -ne ${parasnum} ] && help_msg

 

#--------------------------------------------------------

# Initialize the log file.

#--------------------------------------------------------

export HOST_IP=$1

export HOST_PORT=$2

MYUSER=root

MYPASS="westos"

MYSOCK=/data/$HOST_PORT/mysql.sock

MYSQL_PATH=/application/mysql/bin

MYSQL_CMD="$MYSQL_PATH/mysql -u$MYUSER -p$MYPASS -S $MYSOCK"

 

MailTitle=""

time1=`date +"%Y%m%d%H%M%S"`

time2=`date +"%Y-%m-%d %H:%M:%S"`

SlaveStatusFile="/tmp/slave_status_${HOST_PORT}.${time1}"

echo "-------------Begins at:"$time2 > $SlaveStatusFile

echo "" >> $SlaveStatusFile

 

#get slave status

$MYSQL_CMD -e "show slave status\G" >> $SlaveStatusFile 2>&1

#get io_thread_status,sql_thread_status,last_errno

IOStatus1=`grep Slave_IO_Running $SlaveStatusFile | awk '{print $2}'`

SQLStatus=`grep Slave_SQL_Running $SlaveStatusFile | awk '{print $2}'`

        Errno=`grep Last_Errno $SlaveStatusFile |awk '{print $2}'`

        Behind=`grep Seconds_Behind_Master $SlaveStatusFile | awk '{print $2}'`

 

echo "" >> $SlaveStatusFile

 

if [ $IOStatus1 = 'NO' ] || [ $SQLStatus 'NO' ];then

        echo "Slave $HOST_IP $HOST_PORT is down on $HOST_IP $HOST_PORT ! ErrNUM:$Errno"

fi

 

#delay behind master

if [ "$Behind" -gt 100 ];then

        echo `date +"%Y-%m-%d %H:%M:%S"` "slave is behind master $Behind seconds!"

>> $SlaveStatusFile

        MailTitle="[Warning] Slave delay $Behind seconds,from $HOST_IP $HOST_PORT"

fi

 

if [ -n "$MailTitle" ];then

        echo "tile:$MailTitle" >>$SlaveStatusFile

        source /server/script/maillist.cfg

        cat ${SlaveStatusFile} | /bin/mail -s "$MailTitle" -c "$Mail_Address_MysqlStatus_cc" $Mail_Address_MysqlStatus

fi

 

#del Tmpfile:SlaveStatusFile

> $SlaveStatusFile

"check_mysql_slave_status.sh" [dos] 77L,2526C written

[root@vm1 ~]# sh check_mysql_slave_status.sh 

+-----------------------------------------------------+

+ Error Cause:

+ you enter 0 parameters

+ the total paramenter number must be 2

+ 1st :HOST_IP

+ 2nd :HOST_PORT

+------------------------------------------------------+

[root@vm1 ~]# sh check_mysql_slave_status.sh localhost 3306

[root@vm1 ~]# mysql -uroot -pwestos -S /data/3307/mysql.sock -e "show slave atatus\G"|egrep "_Running|_Behind"|awk '{print $NF}'

这里由于mysql数据库没搭建放到后面测试。(这里实在第四部分12节)

如果你的脚本是以前写好的从windows下拷过来的,那么我们需要使用dos2unix file.sh将脚本做一下处理。

mysql>grant replication slave on *.* to hy @'10.0.0.%' identified by 'westos' with grant option; 授权mysql登录的ip

mysql>flush privileges;

 

 

GRANT ALL PRIVILEGES ON *.* TO 'hy'@'%' IDENTIFIED BY '123456' WITH GRANT OPTION;

允许任何主机以hy为用户名(root用户不能远程登录,只能本地登录),123456为密码访问MySQL。

flush privileges;

让MySQL重新加载权限,使赋予的权限能够马上生效。

 

1.8Shell脚本的调试

在掌握脚本调试方法之前啊,我们应尽可能的先学习脚本开发规范,从而减少降低脚本调试的问题,达到未雨绸缪的效果。也是老师常说的平时多学习好的习惯、注意规范和制度。这也体现了我们未雨绸缪的思想,下面我们先来讲几个常见错误例子。

1.8.1常见脚本错误范例

1.8.1.1if条件句缺少if结尾关键字

[root@vm1 ~]# cat -n if-debug-1.sh 

     1 #!/bin/bash

     2 #功能,单分支if结构整数比较,用-lt格式例子。

     3 #created by hy QQ:1020659371

     4 #date:2015-03-04

     5

     6 if [ 10 -lt 12 ]

     7 then

     8 echo "YES,10 is less than 12"

[root@vm1 ~]# sh if-debug-1.sh 

if-debug-1.sh: line 9: syntax error: unexpected end of file

if-debug-1.sh:第九行:语法错误 :不是期待的(意外的)文件结尾。,根据这个提示,我们知道脚本的尾部有问题,仔细观察发现,缺少fi结尾。

说明:脚本缺少了一个fi关键字。在shell脚本开发中,经常碰到的问题,如忘了使用引号或在if语句末尾忘记了加fi结束。另外,当执行脚本输出脚本错误后,不要只看那些提示的错误行,而是要观察整个代码段。

Shell脚本解释器一般不会对脚本错误进行精确的定位,而是在视图结束一个语句时进行错误统计。

1.8.1.2循环结构体中缺少关键字错误

For、while、until和case语句中的错误是指实际语句段不正确。也许漏写或拼错固定结构中的一个保留字。

[root@vm1 ~]# vim while-debug-1.sh

#!/bin/bash

while true

do

        status=`curl -I -s --connect-timeout 10 $1|head -1|awk '{print $2}'`

        ok=`curl -I -s --connect-timeout 10 $1|head -1|cut -d " " -f 3`

        if [ "$status" = "200" ] && [ "$ok" = "OK" ];the#缺了个n,应该位then

                echo "this url is good"

        else

                echo "this url is bad"

        fi

        sleep 3

done

[root@vm1 ~]# sh while-debug-1.sh 

while-debug-1.sh: line 8: syntax error near unexpected token `else'

while-debug-1.sh: line 8: ` else'

提示:语法错误,提示 第8行语法错误,在else附近。经过前后观察发现,the缺少了n,应该为then。

1.8.1.3成对的符号落了单导致错误

成对的符号有[],(),””,’’,``等

 

#!/bin/bash

MYUSER=root

MYPASS="westos"

MYSOCK=/data/3306/mysql.sock

MySQL_STARTUP="/data/3306/mysql  #==>这里缺少引号

LOG_PATH=/tmp

提示:有时候我们将在调试或在运行的时候出现的报错信息不是在那一行,而是调用那个行所在的函数。

1.8.1.4中括号[]两端没空格导致错误

这个就不在列举例子,一般我们在写脚本的时候注意一下就,养成良好的习惯就可以了,这个在检查的时候也比较容易。

1.8.2shell脚本调试技巧

1.8.2.1使用dos2unix命令处理脚本

从windows编辑的脚本到linux下的格式:这里就不在展示,我们要养成良好的习惯,每次从windows下复制过来的脚本要记得用dos2unix处理一下,可以避免很多不必要的麻烦。

1.8.2.2使用echo命令调试

Echo命令是最有用的调试脚本工具之一。一般在可能出现问题的脚本重要部分加入echo命令,例如在变量读取或修改操作其前后加入echo命令。

[root@vm1 ~]# vim if-judgenum4-debug.sh

#!/bin/bash

 

read -p "pls input two num:" a b

echo $a $b

exit

 

#################################

#if [ $a -lt $b ]

if (($a < $b))

then

        echo "$a < $b"

elif [ $a -eq $b ]

then

        echo "yes,$a <= $b"

fi

 

提示:这个调试方法不是shell的专利,php,asp,perl,python等语言都可以使用这样简单而好用的调试方法。

1.8.2.3使用bash命令参数调试

[root@vm1 ~]# sh [-nvx] scripts.sh

参数:

-n:不会执行脚本,仅查询脚本语法是否有问题,并给出错误提示。

-v:在执行脚本时,先将脚本的内容输出到屏幕上然后执行脚本,如果有错误,也会给出错误提示。

-x:将执行的脚本内容及输出显示到屏幕上,这个是对调试很有用的参数。

Sh参数-n的测试

我们对这几个参数不再测试,如果用到我们再去测试。

#->-n不会执行该脚本,仅查询脚本语法是否有问题,并给出错误提示,此处没有语法问题,因此不显示任何信息。

#->仅检查语法错误是不错的调试参数。

 

#->使用-x是追踪脚本的非常好的一种方法,它可以在执行前列出所有执行的程序段,

#->如果是程序段落,则输出时,最前面会加上+号,表示它是程序代码,

#->一般情况如果调试逻辑错误的脚本,-x效果更佳。

缺点:set -x可以缩小调试的作用域,sh -x脚本名不行,因此,当脚本内容很多时调试不够精确。

范例5:在跟踪script.sh脚本执行过程里输出脚本的行号

在一个比较长的脚本中,你会看到很多的执行跟踪的输出,有时阅读起来非常费劲,此时,你可以在没一行前加上内容的行号,这会非常有用。要做到这样,你只需要设置下面环境变量;

PS4=‘+’

提示:PS4变量默认情况下表示加号。

[root@vm1 ~]# export PS4='+${LINENO}'  #->此命令即可实现在跟踪过程中显示行号,也可以放到脚本中。

[root@vm1 ~]# sh -x func-exec.sh 

+3'[' -x /etc/init.d/hy_functions ']'

+3. /etc/init.d/hy_functions

+6husiyang

+3echo 'I am dadoubi'

I am dadoubi

+7tangpeng

+7echo 'I am doubi'

I am doubi

提示:(+)号后面的数字就表示行号。

这时,我们可以看到,bash在运行行前打印出了每一行命令。而且每行前面的+号表明了嵌套。这样的输出可以让你看到命令执行的顺序,并可以让你知道整个脚本的行为。

特别说明:

参数-x是一个不可多得的参数,在生产环境中,老男孩就经常通过参数-x来实现调试知道问题出在那一行。

1.8.2.4使用set命令调试部分脚本内容

Set命令可辅助脚本调试,一下是set命令常用的调试选项:

set -n 读命令但并不执行。

set -v 显示读取的所有行。

set -x 显示所有命令及其参数。

提示:

1)同bash命令参数功能。

2)开启调试功能通过set -x命令,而关闭调试功能通过set +x。

优点:和bash -x相比,set -x可以缩小调试的作用域。

范例6:打印9x9乘法表

自己写的:

#!/bin/bash

for ((i=1;i<=9;i++))

do

        for((j=1;j<=9;j++))

        do

                printf "$i x $j= $((i*j))\t"

        done

        printf "\n"

done

[root@vm1 ~]# vim for-7-9x9-2-debug2.sh

#!/bin/bash

#set -x

for a in `seq 9`

do

        for b in `seq 9`

        do

                [ $a -ge $b ] && echo -en "$a x $b = $(expr $a \* $b) "

        done

#set +x

echo " "

done

[root@vm1 ~]# sh for-7-9x9-2-debug2.sh 

1 x 1 = 1  

2 x 1 = 2 2 x 2 = 4  

3 x 1 = 3 3 x 2 = 6 3 x 3 = 9  

4 x 1 = 4 4 x 2 = 8 4 x 3 = 12 4 x 4 = 16  

5 x 1 = 5 5 x 2 = 10 5 x 3 = 15 5 x 4 = 20 5 x 5 = 25  

6 x 1 = 6 6 x 2 = 12 6 x 3 = 18 6 x 4 = 24 6 x 5 = 30 6 x 6 = 36  

7 x 1 = 7 7 x 2 = 14 7 x 3 = 21 7 x 4 = 28 7 x 5 = 35 7 x 6 = 42 7 x 7 = 49  

8 x 1 = 8 8 x 2 = 16 8 x 3 = 24 8 x 4 = 32 8 x 5 = 40 8 x 6 = 48 8 x 7 = 56 8 x 8 = 64  

9 x 1 = 9 9 x 2 = 18 9 x 3 = 27 9 x 4 = 36 9 x 5 = 45 9 x 6 = 54 9 x 7 = 63 9 x 8 = 72 9 x 9 = 81  

 

Linux系统的信号处理

有些情况下,我们不希望自己的shell脚本在运行时被中断,比如说我们写的shell脚本设为某一用户的默认shell,使这一用户进入系统后只能作某一项工作,如数据库备份,我们可不希望用户使用ctrl+c之类便进入到shell状态,做我们不希望做的事情。这便用到了信号处理。

(1)执行kill -l可以列出linux系统的信号名称,如下:

[root@vm1 ~]# kill -l

 1) SIGHUP  2) SIGINT  3) SIGQUIT  4) SIGILL  5) SIGTRAP

 6) SIGABRT  7) SIGBUS  8) SIGFPE  9) SIGKILL 10) SIGUSR1

11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM

16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP

21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ

26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR

31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3

38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8

43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13

48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12

53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7

58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2

63) SIGRTMAX-1 64) SIGRTMAX

(2)Linux信号注释说明:

(3)通过trap使用信号的方法

Trap命令用于指定在接收到信号后将要采取的行动,信号的信息前面已经提到。Trap命令的一种常见用途是在脚本程序被中断时完成清理工作。历史上,shell总是用数字来代表信号,而新的脚本程序应该使用信号的名字,它们保存在用#include命令包含进来的signal.sh头文件中,在使用信号名时需要省略SIG前缀。你可以在命令提示符下输入命令trap -l来查看信号编号及其关联的名称。

对于那些不熟悉信号的人们来说,“信号”是指那些被异步发送到一个程序的事件。默认情况下,它们通常会终止一个程序的运行。

请记住,脚本程序通常是以从上到下的顺序解释执行的,所以必须在你想保护的那部分代码以前指定trap命令。

如果要重置某个信号的处理条件到其默认值,只需简单的将command设置为-。如果要忽略某个信号,就把command设置为空字符串‘’。一个不带参数的trap命令将列出当前设置的信号及其行动的清单。

下表列出了比较重要的信号(括号里面的数字是传统的信号编号)。更多细节请参考signal在线手册的第七部分(man 7 signal)。

[root@vm1 ~]# stty -a

speed 38400 baud; rows 24; columns 80; line = 0;

intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = ;

eol2 = ; swtch = ; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;

werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;

-parenb -parodd cs8 -hupcl -cstopb cread -clocal -crtscts -cdtrdsr

-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff

-iuclc -ixany -imaxbel -iutf8

opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0

isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt

echoctl echoke

更方便的是我们可以在shell中用trap定义我们自己的信号处理程序>

范例1:测试按下ctrl+c组合键而引发的INT(2)信号。

[root@vm1 ~]# trap "" 2

[root@vm1 ~]# 此时无法执行ctrl+c

[root@vm1 ~]# trap ":" 2 <==恢复ctrl+c信号

[root@vm1 ~]# 此时可以执行ctrl+c了

测试:

while true

do

    uptime

    sleep 1

done

 

[root@vm1 ~]# vim while.sh

[root@vm1 ~]# sh while.sh 

 14:15:30 up  1:12,  1 user,  load average: 0.00, 0.00, 0.00

 14:15:31 up  1:12,  1 user,  load average: 0.00, 0.00, 0.00

 14:15:32 up  1:12,  1 user,  load average: 0.00, 0.00, 0.00

 14:15:33 up  1:12,  1 user,  load average: 0.00, 0.00, 0.00

^C

[root@vm1 ~]# trap "" 2

[root@vm1 ~]# sh while.sh 

 14:15:41 up  1:13,  1 user,  load average: 0.00, 0.00, 0.00

 14:15:43 up  1:13,  1 user,  load average: 0.00, 0.00, 0.00

 14:15:44 up  1:13,  1 user,  load average: 0.00, 0.00, 0.00

^C 14:15:45 up  1:13,  1 user,  load average: 0.00, 0.00, 0.00

 14:15:46 up  1:13,  1 user,  load average: 0.00, 0.00, 0.00

^C 14:15:47 up  1:13,  1 user,  load average: 0.00, 0.00, 0.00

 14:15:48 up  1:13,  1 user,  load average: 0.00, 0.00, 0.00

^Z

[1]+  Stopped                 sh while.sh //这里我们按ctrl+z暂停

[root@vm1 ~]# 

如果设置提示信息,在用户按ctrl+c的时候:

[root@vm1 ~]# trap "echo -n 'you are typing ctrl+c'" 2

[root@vm1 ~]# ^Cyou are typing ctrl+c

[root@vm1 ~]# ^Cyou are typing ctrl+c

[root@vm1 ~]# ^Cyou are typing ctrl+c

[root@vm1 ~]# ^Cyou are typing ctrl+c

范例2:同时处理多个信号

trap “” 1 2 3 20 15 或 trap “” HUP INT QUIT TSTP TERM

例:

[root@vm1 ~]# trap "" HUP INT QUIT TSTP TERM

[root@vm1 ~]# trap ":" HUP INT QUIT TSTP TERM

[root@vm1 ~]# trap "" 1 2 3 20 15

[root@vm1 ~]# trap ":" 1 2 3 20 15

 

(4)Linux信号的产生应用案例

trap "find /tmp -type f -name" hy_* " -mmin +1 |xargs rm -f && exit" INT

while true

do

    touch /tmp/hy_$(date +%F-%H-%M-%S)

    usleep 500

done

 

案例2:shell跳板机(触发信号后屏蔽信号)

 

方法1:

1)首先做好ssh key验证,见前面的ssh key免费登录验证。

2)实现传统的远程连接菜单选择脚本

3)利用linux信号防止用户在跳板机上操作。

4)用户登录后即调用脚本。

我们使用两台主机进行测试:

vm1:192.168.2.2 跳板机

m2:192.168.2.3 目标主机

第三方客户端:192.168.1.101 第三方测试机

[root@vm1 mnt]# cat tiaoban.sh 

function trapper () {

#echo 'in trapper'

trap ':' INT EXIT TSTP TERM HUP

}

while :

do

trapper

clear

cat <

1)web a

2)web b

3)exit

menu

read -p "pls select:" num

case "$num" in

1)

ssh -p 22 hy@192.168.2.3

;;

2)

ssh -p 22 hy@192.168.2.2

;;

3|*)

exit

;;

esac

Done

[root@vm1 ~]# su - hy

[hy@vm1 ~]$ ssh-keygen -t dsa

Generating public/private dsa key pair.

Enter file in which to save the key (/home/hy/.ssh/id_dsa): 

Enter passphrase (empty for no passphrase): 

Enter same passphrase again: 

Your identification has been saved in /home/hy/.ssh/id_dsa.

Your public key has been saved in /home/hy/.ssh/id_dsa.pub.

The key fingerprint is:

8b:1e:a7:9c:72:08:7b:1c:69:2a:84:0f:0f:11:1d:fa hy@vm1.example.com

The key's randomart image is:

+--[ DSA 1024]----+

| ...             |

|...              |

|..               |

|..               |

|..E  .  S        |

|+.. +  . .       |

|.= * oo o        |

|. = =o.=         |

| . . o=          |

+-----------------+

[hy@vm1 ~]$ ssh-copy-id -i .ssh/id_dsa.pub "-p 22 hy@192.168.2.3"

hy@192.168.2.3's password: 

Now try logging into the machine, with "ssh '-p 22 hy@192.168.2.3'", and check in:

 

  .ssh/authorized_keys

 

to make sure we haven't added extra keys that you weren't expecting.

 

[hy@vm1 ~]$ ssh  这里我们测试验证

Last login: Sat Mar  7 11:54:46 2015 from vm1.example.com

[hy@vm2 ~]$ 

[root@vm1 ~]# vim /etc/profile.d/tiaoban.sh

[ $UID -ne 0 ] && . /mnt/tiaoban.sh

[root@vm1 ~]# chmod +x /etc/profile.d/tiaoban.sh

[root@vm1 ~]# su - hy

接下来我们使用第三方主机来连接:

这时我们就可以通过选择所要连接的服务器了,这样就实现了跳板机机制。

如果我们想登录到命令行,则我们需要做一下操作:

 

提示:为用户建立普通用户连接跳板机的权限。不要从root切换到普通用户测试。

 

方法2:root连接服务器,expect每次重新建立ssh key。

 

 

阅读(6527) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~