分类:shell习题


shell习题-自动增加公钥


写一个shell脚本,当我们执行时,提示要输入对方的ip和root密码,然后可以自动把本机的公钥增加到对方机器上,从而实现密钥认证。

 

参考答案:

#!/bin/bash

read -p "Input IP: " ip
ping $ip -w 2 -c 2 >> /dev/null

## 查看ip是否可用
while [ $? -ne 0 ]
do
    read -p "your ip may not useable, Please Input your IP: " ip
    ping $ip -w 2 -c 2 >> /dev/null
done
read -p "Input root\'s password of this host: " password

## 检查命令子函数

check_ok() {
if [ $? != 0 ]
then
    echo "Error!."
    exit 1
fi
}

## yum需要用到的包
myyum() {
if ! rpm -qa |grep -q "$1"
then
    yum install -y $1
    check_ok
else
    echo $1  already installed
fi
}

for p in openssh-clients openssh expect
do
    myyum $p
done

## 在主机A上创建密钥对

if [ ! -f ~/.ssh/id_rsa ] || [ ! -f ~/.ssh/id_rsa.pub ]
then
    if [ -d ~/.ssh ]
    then
        mv ~/.ssh/  ~/.ssh_old
    fi
    echo -e "\n" | ssh-keygen -t rsa -P ''
    check_ok
fi

## 传私钥给主机B

if [ ! -d /usr/local/sbin/rsync_keys ]
then
    mkdir /usr/local/sbin/rsync_keys
fi
cd /usr/local/sbin/rsync_keys
if [ -f rsync.expect ]
then
    d=`date +%F-%T`
    mv rsync.expect $d.expect
fi

#创建远程同步的expect文件

cat >  rsync.expect <<EOF
#!/usr/bin/expect
set host [lindex \$argv 0]
#主机B的密码
set passwd [lindex \$argv 1]
spawn rsync -av /root/.ssh/id_rsa.pub root@\$host:/tmp/tmp.txt
expect {
"yes/no" { send "yes\r"; exp_continue}
"password:" { send "\$passwd\r" }
}
expect eof
spawn ssh root@\$host
expect {
"password:" { send "\$passwd\r" }
}
expect "]*"                         
send "\[ -f /root/.ssh/authorized_keys \] && cat /tmp/tmp.txt >>/root/.ssh/authorized_keys \r"
expect "]*"
send "\[ -f /root/.ssh/authorized_keys \] || mkdir -p /root/.ssh/ \r"            
send "\[ -f /root/.ssh/authorized_keys \] || mv /tmp/tmp.txt /root/.ssh/authorized_keys\r"            
expect "]*"
send "chmod 700 /root/.ssh; chmod 600 /root/.ssh/authorized_keys\r"
expect "]*"
send "exit\r"
EOF

check_ok
/usr/bin/expect /usr/local/sbin/rsync_keys/rsync.expect $ip $password
echo "OK,this script is successful. ssh $ip  to test it"

shell习题-域名到期提醒


写一个shell脚本,查询指定域名的过期时间,并在到期前一周,每天发一封提醒邮件。

思路: 大家可以在linux下使用命令“whois 域名”,如”whois apelearn.com”,来获取该域名的一些信息。

提示: whois命令,需要安装jwhois包

 

参考答案:

#!/bin/bash

t1=`date +%s`
is_install_whois()
{
    which whois >/dev/null 2>/dev/null
    if [ $? -ne 0 ]
    then
        yum install -y jwhois
    fi
}

notify()
{
    e_d=`whois $1|grep 'Expiry Date'|awk '{print $4}'|cut -d 'T' -f 1`
    e_t=`date -d "$e_d" +%s`
    n=`echo "86400*7"|bc`
    e_t1=$[$e_t-$n]
    if [ $t1 -ge $e_t1 ] && [ $t1 -lt $e_t ]
    then
        /usr/local/sbin/mail.py aming_test@163.com "Domain $1 will be expire." "Domain $1 expire date is $e_d."
    fi
}

is_install_whois
notify aminglinux.com

shell习题-取消后缀


至少用两种方法,批量把当前目录下面所有文件名后缀为.bak的后缀去掉,比如1.txt.bak去掉后为1.txt

 

参考答案:

假设取消的后缀为.bak

方法一:

for i in `ls *.bak`
do 
    mv $i `echo $i|sed 's/\.bak//g'`
done


方法二:

for i in `ls *.bak`
do 
    newname=`echo $i|awk -F '.bak' '{print $1}'` 
    mv $i $newname
done

shell习题-重启tomcat服务


在生产环境中,经常遇到tomcat无法彻底关闭,也就是说用tomcat自带shutdown.sh脚本无法将java进程完全关掉。所以,需要借助shell脚本,将进程杀死,然后再启动。

写一个shell脚本,实现上述功能。彻底杀死一个进程的命令是 kill -9 pid.

 

参考答案:

说明:以下脚本为猿课同学实际线上跑的shell脚本,考虑的方面比较多,大家可以学一学他的思路

#!/bin/bash

###功能: 重启 tomcat 进程
###要求:对于tomcat中的某些应用,使用shutdown.sh是无法完全停掉所有服务的 实际操作中都需要kill掉tomcat再重启
##
### root can not run this script.
##

if [ $USER = root ]
then
        echo "root cann't run this script!please run with other user!"
        exit 1
fi

##
### check the Parameter
##

if [[ $# -ne 1 ]]
then
        echo "Usage:$0 tomcatname"
        exit 1
fi

##
### only one process can run one time
##

TMP_FILE_U=/tmp/.tmp.ps.keyword.$USER.956327.txt
#echo $TMP_FILE_U
KEYWORD1="$0"
KEYWORD2="$1"

# 使用赋值会多fork出一个进程,所以要先重定向到一个文本,再统计.

ps ux |grep "$KEYWORD1"|grep "\<$KEYWORD2\>"|grep -v "grep" > $TMP_FILE_U
Pro_count=`cat $TMP_FILE_U |wc -l`
if [ $Pro_count -gt 1 ]
then
        echo "An other process already running ,exit now!"
        exit 1
fi

###################################################
#                                                 #
#               begin of the script               #
#                                                 #
###################################################

##
### set the Parameter
##

TOM=`echo $1|sed 's#/##g'`
TOMCAT_DIRECTORY=~/usr/local/$TOM
STARTUP_SCRIPT=$TOMCAT_DIRECTORY/bin/startup.sh
TOMCAT_LOG=$TOMCAT_DIRECTORY/logs/catalina.out
CONF_FILE=$TOMCAT_DIRECTORY/conf/server.xml
TEMPFILE=/tmp/.tmpfile.x.89342.c4r3.tmp

##
### check if the tomcat directory exist
##

if [ ! -d "$TOMCAT_DIRECTORY" ]
then
        echo "the tomcat \"$TOM\" not exist.check again!"
        exit 1
fi

##
### log roteta and delete log one week ago
##

rotate_log(){
TIME_FORMART=$(date +%Y%m%d%H%M%S)
LOG_DIR=$(dirname $TOMCAT_LOG)
mv $TOMCAT_LOG ${TOMCAT_LOG}_${TIME_FORMART}
find $LOG_DIR -type f -ctime +7 -exec rm -rf {} \;
}

##
### function start the tomcat
##

start_tomcat()
{
#echo start-tomcat-func
if [ -x  "$STARTUP_SCRIPT" ]
then
      
        rotate_log
        $STARTUP_SCRIPT
        sleep 1
        tail -f $TOMCAT_LOG
else
        if [ -e $STARTUP_SCRIPT ]
        then
                chmod +x $STARTUP_SCRIPT
#               echo "permition added!"
                if [ -x  "$STARTUP_SCRIPT" ]
                then
                      
                        rotate_log
                        $STARTUP_SCRIPT
                        sleep 1
                        tail -f $TOMCAT_LOG
                else
                        echo "The script not have excute permision,Couldn't add permision to Script!"
                        exit 1
                fi
        else
                echo "error,the script \"startup.sh\" not exist!"
                exit 1
        fi
fi
}

##
### function stop the tomcat
##

stop_tomcat()
{
rm -rf $TEMPFILE
ps ux |grep /$TOM/ |grep -v "grep /$TOM/"|grep java > $TEMPFILE
Pro_Count=`cat $TEMPFILE|wc -l`
PIDS=`cat $TEMPFILE|awk '{print $2}'`
rm -rf $TEMPFILE
#echo $Pro_Count

if [ $Pro_Count -eq 0 ]
then
        echo "The tomcat not running now!"
else
        if [ $Pro_Count -ne 1 ]
        then
                echo "The have $Pro_Count process running,killed!"
                kill -9 `echo $PIDS`
                WC=`ps aux | grep "/$TOM/" | grep -v "grep /$TOM/" | grep java |wc -l`
                [ $WC -ne 0 ] && (echo "kill process failed!";exit 1)
        else
                echo "Process killed!"
                kill -9 `echo $PIDS`
                WC=`ps aux | grep "/$TOM/" | grep -v "grep /$TOM/" | grep java |wc -l`
                [ $WC -ne 0 ] && (echo "kill process failed!";exit 1)
        fi
fi
}

###########################
####                   ####
####  The main script  ####
####                   ####
###########################

echo -e "are you sure restart $TOM?(y or n)"
read ANS
if [ "$ANS"a != ya ]
then
   echo -e "bye! \n"
   exit 1
fi

stop_tomcat
echo "start tomcat ..."
sleep 2
start_tomcat
# end

shell习题-关闭服务


在centos6系统里,我们可以使用ntsysv关闭不需要开机启动的服务,当然也可以使用chkconfig工具来实现。

写一个shell脚本,用chkconfig工具把不常用的服务关闭。脚本需要写成交互式的,需要我们给它提供关闭的服务名字。

 

参考答案:

#!/bin/bash

LANG=en
c="1"

while [ ! $c == "q" ]
do
    echo -e "\033[35mPlease chose a service to close from this list: \033[0m"
    chkconfig --list |awk '/3:on/ {print $1}'
    read -p "Which service to close: " s
    chkconfig $s off
    service $s stop
    read -p  "If you want's to quit this program, tab "q", or tab "Ctrl c": " c
done

shell习题-统计并发量


需求背景:

需要统计网站的并发量,并绘图。

思路:

1 借助zabbix成图

2 通过统计访问日志每秒的日志条数来判定并发量

3 zabbix获取数据间隔30s

说明: 只需要写出shell脚本即可,不用关心zabbix配置。

 

参考答案:

假设日志路径 /data/logs/www.aaa.com_access.log 

日志格式如下
112.107.15.12 - [07/Nov/2017:09:59:01 +0800] www.aaa.com "/api/live.php" 200"-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)"

#!/bin/bash
log=/data/logs/www.aaa.com_access.log
t=`date -d "-1 second" +%Y:%H:%M:%S`
#可以大概分析一下每分钟日志的量级,比如说不超过3000
n=tail -3000 $log |grep -c "$t"
echo $n

shell习题-批量同步代码


需求背景是:

一个业务,有3台服务器(A,B,C)做负载均衡,由于规模太小目前并未使用专业的自动化运维工具。有新的需求时,开发同事改完代码会把变更上传到其中一台服务器A上。但是其他2台服务器也需要做相同变更。

写一个shell脚本,把A服务器上的变更代码同步到B和C上。

其中,你需要考虑到不需要同步的目录(假如有tmp、upload、logs、caches)

 

参考答案:

#!/bin/bash

echo "该脚本将会把A机器上的/data/wwwroot/www.aaa.com目录同步到B,C机器上";
read -p "是否要继续?(y|n) "

rs() {
    rsync -azP \
    --exclude logs \
    --exclude upload \
    --exclude caches \
    --exclude tmp \
www.aaa.com/ $1:/data/wwwroot/www.aaa.com/

}

if [ $REPLY == 'y' -o $REPLY == 'Y' ]
then
    echo "即将同步……"
    sleep 2
    cd /data/wwwroot/
    rs B机器ip
    rs C机器ip
    echo "同步完成。"   
elif [ $REPLY == 'n' -o $REPLY == 'N' ]
then
    exit 1
else
    echo "请输入字母y或者n"
fi

shell习题-数组


写一个脚本让用户输入多个城市的名字(可以是中文),要求不少于5个,然后把这些城市存到一个数组里,最后用for循环把它们打印出来。

参考答案:

#!/bin/bash  

read -p "请输入至少5个城市的名字,用空格分隔:" city
n=`echo $city|awk '{print NF}'`

if [ $n -lt 5 ]
then
    echo "输入的城市个数至少为5"
    exit
fi

name=($city)

for i in ${name[@]}
do
    echo $i
done

shell习题-截取tomcat日志


写一个截取tomcat   catalina.out日志的脚本

tomcat实例t1-t4

# tree  -L  1   /opt/TOM/

/opt/TOM/

├── crontabs

├── t1

├── t2

├── t3

└── t4

5 directories, 0 files

# find  /opt/TOM/   -name  catalina.out

/opt/TOM/t1/logs/catalina.out

/opt/TOM/t3/logs/catalina.out

/opt/TOM/t4/logs/catalina.out

/opt/TOM/t2/logs/catalina.out

要求:

1.这个脚本可以取tomcat实例t1-t4的日志

2.这个脚本可以自定义取日志的起始点 ,比如取今天早上10点之后到现在的数据

3.这个脚本可以自定义取日志的起始点和终点,比如取今天早上9点到晚上8点的数据

catalina.out 日志内容

Mar 29, 2016 1:52:24 PM org.apache.coyote.AbstractProtocol start

INFO: Starting ProtocolHandler [“http-bio-8080”]

Mar 29, 2016 1:52:24 PM org.apache.coyote.AbstractProtocol start

INFO: Starting ProtocolHandler [“ajp-bio-8009”]

Mar 29, 2016 1:52:24 PM org.apache.catalina.startup.Catalina start

INFO: Server startup in 2102 ms

 

参考答案:

#!/bin/bash

##
#Author: 7期孙东
#

export LANG=en_US.UTF-8
export PATH=$PATH
IPADD=`/sbin/ifconfig | grep "inet addr" | head -1 | awk '{print $2}'| awk -F '.' '{print $NF}'`
LOGFILE="/opt/TOM/$1/logs/catalina.out"
YEAR=`date +%Y`
DATE=`date +%m%d_%H%M`
TOMCAT=$1
BEGIN_TIME=$YEAR$2
END_TIME=$YEAR$3

##judge is  a.m.or p.m.
TIME_HOUR1=`echo ${BEGIN_TIME:9:2}`

cut_log() {
        N_DATE1=`echo $1 | sed 's/_/ /g'`
        D_DATE1=`echo $2 | sed 's/_/ /g'`
        E_DATE1=`echo $3 | sed 's/_/ /g'`
        [ $4 ] && N_DATE2=`echo $4 | sed 's/_/ /g'`
        [ $5 ] && D_DATE2=`echo $5 | sed 's/_/ /g'`
        [ $6 ] && E_DATE2=`echo $6 | sed 's/_/ /g'`
        BEGIN=`grep -nE "${N_DATE1}|${D_DATE1}|${E_DATE1}" ${LOGFILE} | head -1 | cut -d : -f1`
        [ "$N_DATE2" ] && END=`grep -nE "${N_DATE2}|${D_DATE2}|${E_DATE2}" ${LOGFILE} | tail -1 | cut -d : -f1`
               
        [ ! -z "${TIME_HOUR1}" ] && if [ ${TIME_HOUR1} -gt 12 ] ; then
                BEGIN1=`grep -nE "${N_DATE1}|${D_DATE1}|${E_DATE1}" ${LOGFILE} |grep " PM " |grep "${E_DATE1}" | head -1 | cut -d : -f1`

                if [ ! -z "${BEGIN1}" ] ; then
                [ "${BEGIN1}" -gt "${BEGIN}" ] ; BEGIN=${BEGIN1}
                fi
        fi

        if [ "$BEGIN" ] && [ -z "$END" ] ; then
                if [ "$N_DATE2" ]; then
                        echo  "${END_TIME}时间点没有访问日志,请重新设置时间点."
                else
                        sed -n "${BEGIN},[        DISCUZ_CODE_0        ]quot;p ${LOGFILE} > /home/gcweb/${IPADD}_${TOMCAT}_${DATE}.log
                fi
        elif [ "$END" ];then
                [ "$BEGIN" ] || BEGIN=1
                sed -n "${BEGIN},${END}"p ${LOGFILE} > /home/gcweb/${IPADD}_${TOMCAT}_${DATE}.log
        else
                [ "$END_TIME" != "$YEAR" ] && echo "该时段 ${BEGIN_TIME}~${END_TIME} 没有日志."
                [ "$END_TIME" = "$YEAR" ] && echo "该时段 ${BEGIN_TIME}~now 没有日志."
        fi

        if [ -s /home/gcweb/${IPADD}_${TOMCAT}_${DATE}.log ]; then
                cd /home/gcweb  &&  tar -zcf ${IPADD}_${TOMCAT}_${DATE}.tar.gz ${IPADD}_${TOMCAT}_${DATE}.log
                rm -f /home/gcweb/${IPADD}_${TOMCAT}_${DATE}.log
                sz /home/gcweb/${IPADD}_${TOMCAT}_${DATE}.tar.gz
                echo "Success to get logs."
                rm -f /home/gcweb/${IPADD}_${TOMCAT}_${DATE}.tar.gz
        fi
}

get_time() {
        case "$1" in
                4)      

                 N_DATE=`date -d "$2" +"%Y-%m-%d" 2>/dev/null`
                 D_DATE=`date -d "$2" +"%Y/%m/%d" 2>/dev/null`
                 E_DATE=`date -d "$2" +"%h %e,_%Y" 2>/dev/null|sed 's/ /_/g'`
                 echo $N_DATE $D_DATE $E_DATE
                 ;;      

                7)      

                 TIME=`echo $2 | awk -F'_' '{print $1,$2}'`
                 N_DATE=`date -d "$TIME" +"%Y-%m-%d_%H" 2>/dev/null`
                 D_DATE=`date -d "$TIME" +"%Y/%m/%d_%H" 2>/dev/null`
                 E_DATE=`date -d "$TIME" +"%h %e,_%Y %l" 2>/dev/null|sed 's/ /_/g'`
                 echo  "$N_DATE"  "$D_DATE" "$E_DATE"
                ;;

                9)     

                 TIME=`echo $2 | awk -F'_' '{print $1,$2}'`
                 N_DATE=`date -d "$TIME" +"%Y-%m-%d_%H:%M" 2>/dev/null`
                 D_DATE=`date -d "$TIME" +"%Y/%m/%d_%H:%M" 2>/dev/null`
                 E_DATE=`date -d "$TIME" +"%h %e,_%Y %l:%M" 2>/dev/null|sed 's/ /_/g'`
                 echo  "$N_DATE" "$D_DATE" "$E_DATE"
                ;;

                *)      
                 echo 1
                ;;
       esac
}

check_arguments () {

        if [ "$1" == 1 ] || [ -z  "$1" ] ;then
                echo "你输入时间参数的格式无法识别, usage: 0108、0108_10、0108_1020"
                exit 3
        fi

}

check_tomcat () {

        if [ ! -s "${LOGFILE}" ] ;then
          echo "tomcat_name: ${TOMCAT} is not exist"
          echo "you can choose:"
          /bin/ls  /home/gcweb/usr/local/
        fi

        if [ $1 -lt 2 ] || [ ! -s "${LOGFILE}" ];then
                echo "usage: $0 tomcat_name {begin_time|begin_time end_time}"
                exit 2
        fi
}

case "$#" in

    0)
        echo "usage: $0 tomcat_name {begin_time|begin_time end_time}"
        exit 1
        ;;

    1)
        check_tomcat $#
        ;;

    2)

        check_tomcat $#
        len=`echo $2 | awk '{print length($0)}'`
        A_DATE=$(get_time  $len $BEGIN_TIME)
        eval  $( echo $A_DATE |awk '{print "N_DATE="$1,"D_DATE="$2,"E_DATE="$3}')
        check_arguments "${N_DATE}"
        cut_log "${N_DATE}" "${D_DATE}" "${E_DATE}"
        ;;

    3)

        check_tomcat $#
        len1=`echo $2 | awk '{print length($0)}'`
        len2=`echo $3 | awk '{print length($0)}'`

        A_DATE=$(get_time ${len1}  $BEGIN_TIME)
        eval  $( echo $A_DATE |awk '{print "N_DATE1="$1,"D_DATE1="$2,"E_DATE1="$3}')
        check_arguments "${N_DATE1}"
        A_DATE=$(get_time ${len2}  $END_TIME)
        eval  $( echo $A_DATE |awk '{print "N_DATE="$1,"D_DATE="$2,"E_DATE="$3}')
        check_arguments "${N_DATE}"
        cut_log ${N_DATE1} ${D_DATE1} ${E_DATE1} "${N_DATE}" "${D_DATE}" "${E_DATE}"
        ;;

    *)

        echo "usage: $0 tomcat_name {begin_time|begin_time end_time};你使用的参数太多哦."
        ;;

esac

shell习题-监控磁盘io


阿里云的机器,今天收到客服来的电话,说服务器的磁盘io很重。于是登录到服务器查看,并没有发现问题,所以怀疑是间歇性地。

正要考虑写个脚本的时候,幸运的抓到了一个线索,造成磁盘io很高的幕后黑手是mysql。此时去show processlist,但未发现队列。原来只是一瞬间。

只好继续来写脚本,思路是,每5s检测一次磁盘io,当发现问题去查询mysql的processlist。

帮助:你可以用iostat -x 1  5 来判定磁盘的io,主要看%util

 

参考答案:

#!/bin/bash

while :
do
    n=`iostat -x 1 5 |tail -n3|head -n1 |awk '{print $NF}'|cut -d. -f1`
    if [ $n -gt 70 ]
    then
        echo "`date` util% is $n%" >>/tmp/mysql_processlist.log
        mysql -uroot -pxxxxxx -e "show  full processlist" >> /tmp/mysql_processlist.log
    fi
    sleep 5
done