shell编程企业级实战

Posted yxiaodao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了shell编程企业级实战相关的知识,希望对你有一定的参考价值。

Vim配置文件.vimrc

技术图片vim配置文件

if 条件语句

if是最常见的条件判断语句

技术图片

技术图片

 

 

例1:如果不存在/backup目录就创建。
[[email protected] /server/tools]# vim 07-01.sh
#!/bin/bas
path=/backup
[ -d $path ] || mkdir $path -p
# 相当于
# :冒号表示什么也不干
if [ -d $path ]
then
        :
else
        mkdir $path -p
fi
# 或者
[ !-d $path ] && mkdir /backdir -p
# 相当于
if [ !-d $path ]
then
        mkdir /backdir -p
if
"07-01.sh" 18L, 248C writte
vim命令:替换:%s#/backup#$path#g
例2:开发Shell脚本判断系统剩余内存的大小,如果低于100MB就提示内存不足,否则提示内存充足。 考查if双分支: 分析:
1)提取系统内存。 2)if判断, [[email protected] 07]# cat 07_02.sh #!/bin/bash ############################################################## # File Name: 07_02.sh # Version: V1.0 # Author: pizza # Created Time : 2018-06-06 22:58:54 # Description: ############################################################## mem=`free -m|awk NR==3{print $NF}` if [ $mem -lt 1000 ] then echo "内存严重不足。" else echo "内存还够" fi

在第一章的中添加了内存不足发邮件的例子
例3:分别使用变量定义、read读入及脚本传参方式实现比较2个整数的大小。 1)变量定义: a=6 b=2 2)read读入: read -p "请输入两个数字:" a b 3)传参: 分析: 大于 等于 小于 #!/bin/bash
##############################################################
# File Name: 07-03.sh
# Version: V1.0
# Author: pizza
# Created Time : 2019-03-28 21:20:46
# Description:
##############################################################
# 第一种,传参
a=6
b=7
# 第二种,read
read -p "请输入两个数字" a b
# 第三种,参数
$a=$1
$b=$2
# 判断输入
# 1、判断数字是不是够,判断b是不是空,或者使用$#
# 2、判断是不是整数,利用expr
# 3、

if [ $a -gt $b ]
then
    echo "$a>$b"
elif [ $a -lt $b ]
then
    echo "$a<$b"
else
    echo "$a=$b"
fi

例4:打印一个菜单如下,当用户选择对应的数字时,就执行对应项的应用。
1.install lamp 2.install lnmp 3.exit 第一章已讲解: bash内置核心命令read的企业级应用实践 read企业应用 [[email protected] scripts]# cat select1.sh #!/bin/bash cat <<EOF 1.install lamp 2.install lnmp 3.exit EOF read -p "请选择一个序号(必须是数字):" num #1.判断是否为整数 expr 2 + $num &>/dev/null if [ $? -ne 0 ] then echo "Usage:$0 {1|2|3}" exit 1 fi #2.判断执行处理 if [ $num -eq 1 ] then echo "install lamp..." elif [ $num -eq 2 ] then echo "install lnmp..." elif [ $num -eq 3 ] then echo "bye." exit else echo "Usage:$0 {1|2|3}" exit 1 fi

 

Shell函数的知识与实践

函数的作用就是将程序里多次被调用的相同代码组合起来,并为其取个名字。其他所有想重复调用这部分代码的复方都只需要调用这个这个名字就可以了。当需要修稿这部分重复代码的时候,也只需要改变函数内的一份代码即可实现所有的修改,也可以把函数独立写到文件里面,当需要调用的时候,再加载进来。

 

函数的语法体

技术图片

 

 

oldboy() {
    echo "I am oldboy."
}
function oldgirl {
    echo "I am oldgirl."
}
test() {
    echo "Hello world."
}
oldboy
oldgirl

[[email protected] ~]# sh test_hanshu.sh
I am oldboy.
I am oldgirl.
Hello world.
[[email protected] ~]#

 

向函数传参

带参数的函数编写执行
oldboy() {
    echo "I am $1."
}
oldboy oldboy
将函数传参转为脚本传参
oldboy() {
    echo "I am $1."
}
oldboy $1

函数和执行函数分离
./etc/init.d/function
pizza $1

 

Shell函数的执行注意事项

技术图片

 

企业案例:通过脚本传参的方式,检查Web 网站URL是否正常。

wget命令:
--spider 模拟爬虫
-q 安静访问
-o /dev/null 不输出
-T --timeout 超时时间
-t --tries 重试次数
[[email protected] ~]# wget --spider -T 5 -q -o /dev/null -t 2 www.baidu.com
[[email protected] ~]# echo $?
0
curl命令:
-I 看响应头
-s 安静的 安静模式。不显示进度表或错误信息。使cURL 不反馈信息。
-o /dev/null 不输出
-w %{http_code} 返回状态码,200
-m 超时时间
[[email protected] ~]# curl www.baidu.com -s &>/dev/null [[email protected] ~]# echo $? 0 [[email protected] ~]# curl -I -m 5 -s -w "%{http_code}\\n" -o /dev/null www.baidu.com 200 不用函数的实现写法 #!/bin/sh if [ $# -ne 1 ] then echo $"usage:$0 url" exit 1 fi wget --spider -q -o /dev/null --tries=1 -T 5 $1 #<==-T指定超时时间,这里的$1为脚本的参数。 if [ $? -eq 0 ] then echo "$1 is yes." else echo "$1 is no." fi 高端专业的函数写法: [[email protected] ~]# cat checkurl.sh #!/bin/bash ############################################################## # File Name: checkurl.sh # Version: V1.0 # Author: oldboy # Organization: www.oldboyedu.com # Created Time : 2018-06-07 18:29:19 # Description: ############################################################## usage(){ echo "Usage:$0 url" exit 1 } checkurl(){ wget -q -o /dev/null -t 2 -T 5 $1 if [ $? -eq 0 ] then echo "$1 is ok" else echo "$1 is fail" fi } main(){ if [ $# -ne 1 ] then usage fi checkurl $1 } main $* [[email protected] scripts]# cat 8_5_1.sh #!/bin/sh function usage() { #<==帮助函数 echo $"usage:$0 url" exit 1 } function check_url() { #<==检测URL函数。 wget --spider -q -o /dev/null --tries=1 -T 5 $1 #<==这里的$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 $* #<==这里的$*就是把命令行接收的所有参数作为函数参数传给函数内部,常用手法。

 

 

CASE结构条件句

技术图片

几乎所有的case都可以用if替代
case "$1" in
    1)
    dddd
    ;;
    2)
    dddd
    ;;
    *)
    dddd
esac

企业应用:
启动脚本
read 读入 菜单选择。

范例9_2:执行shell脚本,打印一个如下的水果菜单:
1.apple
2.pear
3.banana
4.cherry
当用户输入对应的数字选择水果的时候,告诉他选择的水果是什么,并给水果单词加上一种颜色(随意),要求用case语句实现。
范例9_3:给内容加不同的颜色。
内容的颜色用数字表示,范围为30-37,每个数字代表一种颜色。代码如下:
echo -e "\\033[30m 黑色字 \\033[0m" #<==30m表示黑色字。
echo -e "\\033[31m 红色字 \\033[0m" #<==31m表示红色字。
echo -e "\\033[32m 绿色字 \\033[0m" #<==32m表示绿色字。
echo -e "\\033[33m 棕色字 \\033[0m" #<==33m表示棕色字(brown),和黄色字相近。
echo -e "\\033[34m 蓝色字 \\033[0m" #<==34m表示蓝色字。
echo -e "\\033[35m 洋红字 \\033[0m" #<==35m表示洋红色字(magenta),和紫色字相近。
echo -e "\\033[36m 蓝绿色 \\033[0m" #<==36m表示蓝绿色字(cyan),和浅蓝色字相近。
echo -e "\\033[37m 白色字 \\033[0m" #<==37m表示白色字。
说明:不同的数字对应的字体颜色,见系统帮助(来源man console_codes命令的结果)。
范例9_6: 给输出的字符串加不同的背景颜色。
字的背景颜色对应的数字范围为40-47,代码如下。
echo -e "\\033[40;37m 黑底白字\\033[0m"   #<==40m表示黑色背景。
echo -e "\\033[41;37m 红底白字\\033[0m"   #<==41m表示红色背景。
echo -e "\\033[42;37m 绿底白字\\033[0m"   #<==42m表示绿色背景。
echo -e "\\033[43;37m 棕底白字\\033[0m"   #<==43m表示棕色背景(brown),和黄色背景相近。
echo -e "\\033[44;37m 蓝底白字\\033[0m"   #<==44m表示蓝色背景。
echo -e "\\033[45;37m 洋红底白字\\033[0m"  #<==45m表示洋红色背景(magenta),和紫色背景相近。
echo -e "\\033[46;37m 蓝绿底白字\\033[0m"   #<==46m表示蓝绿色背景(cyan),和浅蓝色背景相近。
echo -e "\\033[47;30m 白底黑字\\033[0m"    #<==47m表示白色背景。

创建case3.sh,定义函数 ,执行函数color $*
创建case4.sh,用.或者source调用函数,打印菜单,输入数字,显示不同颜色的字体 范例9_10:利用case语句开发Rsync服务启动停止脚本,本例采用case语句以及新的思路来实现。 分析: 启动: rsync
--daemon 停止: pkill rsync killall rsync kill 进程号 ---->最专业的方法 /etc/init.d/rsyncd {start|stop|restart} case

 rsync.sh简单版

case "$1" in
    start)
        rsync --deamon
        if [ $? -eq 0 ]
        then
            echo "rsync startup ok"
        else
            echo "rsync startup fail"
        fi
        ;;
    stop)
        killall rsync
        if [ $? -eq 0 ]
        then
            echo "rsync stop ok"
        else
            echo "rsync stop fail"
        fi
        ;;
    restart)
        killall rsync && sleep 1 && rsync --deamon
        if [ $? -eq 0 ]
        then
            echo "rsync restart ok"
        else
            echo "rsync restart fail"
        fi
        ;;

    *)
        echo "usage:$0 {start|stop|restart}"
        exit 1
esac

 

升级版

 start(){                                                                                                        
     rsync --deamon
     retval=$?
     if [ $retval -eq 0 ]
     then
         echo "rsync startup ok"
         return $retval
     else
         echo "rsync startup fail"
         return $retval
     fi
 }
 stop(){
     killall rsync
     retval=$?
     if [ $? -eq 0 ]
     then
          echo "rsync stop ok"
                                                                                                  9,1           Top
        return $retval
    else
        echo "rsync restart fail"
        return $retval
    fi  
    }   
case "$1" in
    start)
        start
        # 为了向外传值
        retval=$?
        ;;  
    stop)
        stop
        retval=$?
        ;;  
    restart)
        restart
        retval=$?
        ;;  

    *)  
        echo "usage:$0 {start|stop|restart}"
        exit 1
esac

 

想要使用chkconfig(man ckhconfig),找到这些信息

RUNLEVEL FILES
       Each service which should be manageable by chkconfig needs two or more commented lines added to its init.d
       script. The first line tells chkconfig what runlevels the service should be started in by default, as well
       as the start and stop priority levels. If the service should not, by default, be started in any runlevels,
       a  -  should  be used in place of the runlevels list.  The second line contains a description for the ser‐
       vice, and may be extended across multiple lines with backslash continuation.

       For example, random.init has these three lines:
       # chkconfig: 2345 20 80  表示在2345这几个启动级别上 启动顺序排20 停止顺序排80
       # description: Saves and restores system entropy pool for        #              higher quality random number generation.

 

在脚本首行加入

#!/bin/bash
# chkconfig: 2345 20 80
# description: rsync start stop and restart   

 

将脚本移动到/etc/init.d/下,并添加执行权限,添加到chkconfig中才能使用

[[email protected]01 /server/tools]# mv /etc/init.d/rsync_up.sh /etc/init.d/rsyncd
[[email protected]-01 /server/tools]# chmod +x /etc/init.d/rsyncd
[[email protected]-01 /server/tools]# chkconfig --list rsyncd

Note: This output shows SysV services only and does not include native
      systemd services. SysV configuration data might be overridden by native
      systemd configuration.

      If you want to list systemd services use systemctl list-unit-files.
      To see services enabled on particular target use
      systemctl list-dependencies [target].

service rsyncd supports chkconfig, but is not referenced in any runlevel (run chkconfig --add rsyncd)
[[email protected]-01 /server/tools]# chkconfig --add rsyncd
[[email protected]-01 /server/tools]# chkconfig --list rsyncd

Note: This output shows SysV services only and does not include native
      systemd services. SysV configuration data might be overridden by native
      systemd configuration.

      If you want to list systemd services use systemctl list-unit-files.
      To see services enabled on particular target use
      systemctl list-dependencies [target].

rsyncd             0:off    1:off    2:on    3:on    4:on    5:on    6:off

 

更好一些,调用了系统函数,action。并优化了重复停止的输出 

#!/bin/bash                                                       
# chkconfig: 2345 20 80
# description: rsync start stop and restart
##############################################################
# File Name: syncd.sh
# Version: V1.0
# Author: pizza
# Created Time : 2019-03-29 22:06:46
# Description:
##############################################################
. /etc/init.d/functions
start(){
    rsync --deamon
    retval=$?
    if [ $retval -eq 0 ]
    then
        action  "rsync startup ok" /bin/true
        return $retval
    else
        action "rsync startup fail" /bin/false
        return $retval
    fi
}
                                                1,1           Top
        return $retval
    fi
    }
case "$1" in
    start)
        start
        # 我了向外传值
        retval=$?
        ;;
    stop)
        stop
        retval=$?
        ;;
    restart)
        restart
        retval=$?
        ;;

    *)
        echo "usage:$0 {start|stop|restart}"
        exit 1
esac
     

 

开发和系统媲美的脚本

 

                                                         92,0-1        Bot
#!/bin/bash
# chkconfig: 2345 20 80
# description: rsync start stop and restart
##############################################################
# File Name: syncd.sh
# Version: V1.0
# Author: pizza
# Created Time : 2019-03-29 22:06:46
# Description:
##############################################################
# 定义锁文件
lockfile=/var/lock/subsys/rsyncd
# 定义变量,指定rsyncd的的pid,是需要自己rsync的conf中去创建

#[[email protected]-01 /server/tools]# vim /etc/rsyncd.conf
#pid file=/var/run/rsyncd.pid    

srsync_pid_file_path=/var/run/rsyncd.pid
. /etc/init.d/functions
start(){
    rsync --deamon
    retval=$?
    if [ $retval -eq 0 ]
    then
        action  "rsync startup ok" /bin/true
        touch $lockfile
        return $retval
    else
        action "rsync startup fail" /bin/false
        return $retval
    fi
}
stop(){
    # 为了在重复停止操作的时候,不提示,将其扔到黑洞
    if test -s "$rsyncd_pid_file_path"
    then
        rsyncd_pid=`cat $rsyncd_pid_file_path`
        # 判断进程号是不是真实存在
        if (kill -0 $rsyncd_pid &>/dev/null)
        then
            kill $rsyncd_pid

            retval=$?
            if [ $? -eq 0 ]
            then
                action "rsync stop ok" /bin/true
                rm -f $lockfile
                return $retval
            else
                action "rsync stop fail" /bin/false
                return $retval
            fi
        else
            echo "rsyncd process is not exist."
            return 2
        fi
    else
        echo "$srsync_pid_file_path is not exits,or rsyncd doesnot start"
    fi
}
restart(){
    killall rsync && sleep 1 && rsync --deamon
    retval=$?
    if [ $? -eq 0 ]
    then
        action "rsync restart ok" /bin/true
        return $retval
    else
        action "rsync restart fail" /bin/false
        return $retval
    fi
    }
case "$1" in
    start)
        start
        # 我了向外传值
        retval=$?
        ;;
    stop)
        stop
        retval=$?
        ;;
    restart)
        restart
        retval=$?
        ;;

    *)
        echo "usage:$0 {start|stop|restart}"
        exit 1
esac
  

 

case总结

1、case语句和if条件句的使用性

case语句比较适合变量较少且为固定的数字或者字符串集合的情况(非不确定内容,如范围)

2、if和case的常用应用场景

case只要写服务的启动脚本,一般情况下,传参不同且具有少量的字符串,其使用范围较窄

if就是取值判断、比较,应用比case更广,几乎所有的case语句都可以用if条件语句实现。

3、case语句的特点和优势

它相当于多分支的if/elif/else语句,但是case语句的优势是更规范。易读

 

while循环

循环语句命令常用于重复执行一条指令或一组指令,直到条件不满足停止,Shell脚本语言的循环语句常见的有while、until、for以及select循环语句。 while循环语句主要用来重复执行一组命令或语句,在企业实际应用中,常用于守护进程或持续运行的程序,除此以外,大多数循环都会用后文即将讲解 的for循环语句。

技术图片

while true
do
    uptime >> /tmp/uptime.log
    sleep 2 # 暂停2s
    usleep 2000 # 微秒                                                                                              
done

 

脚本进程管理命令

 技术图片

    后台运行  &、nohup、screen(运维人员)

 为什么要用后台运行,防止你在执行重要命令的时候,网络宕机

进程管理的其他常见命令

技术图片

范例1:请使用while循环对下面的脚本进行修改,是的当执行脚本时,每次执行完脚本后,不退出脚本,而是提示用户输入

while true
do
    read -p "请输入两个数字:" a b
    if [ -z $b ]
    then                                                                                
        echo "请输入两个数字"
        continue
    fi
    expr 10 + $a + $b &>/dev/null
    if [ $? -ne 0 ]
    then
        echo "请输入两个数字"
        continue
    fi
    echo "a+b=$(($a+$b))"
done

 

范例2:猜数字游戏。首先让系统随机生成一个数字,给这个数字定一个范围(1-60),让用户输入猜的数字,对输入进行判断,如果不符合要求,就给予高或低的提示,猜对后则给出猜对用的次数,请用while语句实现。

提示:可以赋予一个猜水果的价格游戏。

1、给数字定范围(1-60)
RANDOM随机数,它的范围是0-32767
[[email protected]-01 /server/tools]# echo $RANDOM
9279
为随机数取模。控制在1-60
[[email protected]-01 /server/tools]# echo $((RANDOM%60))
11
2、用户输入数字
read -p “请输入数字:” num

3、对比,直到正确才推出
while 
4、代码:
random="$(($RANDOM%60))"
#做计数
count=0
echo $random
while true
do
    read -p "请输入数字:" num
    ((count++))
    if [[ $num -lt $random ]]
    then
        echo "低了"
        continue
    elif [[ $num -gt $random ]]
    then
        echo "高了"
        continue
    elif [[ $num -eq $random ]]                                          
    then
        echo "恭喜你,猜对了,一共猜了$count次"
        exit 0
    else
        echo "请输入数字"
    fi
done

还可以加入函数,其他的限制内判断,使脚本更完善

 

范例3:分析Apache访问日志(access_2010-12-8.log)日志每行访问字节数对应字段数字相加,计算出的访问量。给出实现程序,请用while循环实现。(3分钟)

方式1:在while循环结尾done通过输入重定向指定读取的文件。
while read line
do
    cmd
done<FILE
方式2:使用cat读取文件内容,然后通过管道进入while循环处理。
cat FILE_PATH|while read line
do
    cmd
done
方式3:采用exec读取文件后,然后进入while循环处理。
exec <FILE
sum=0
while read line
do
    cmd
done

 

体验

while read line
do
    echo $line
    sleep 1
done < ./while_01.sh                                                     
~                                                                        
~                                                                        
                                                                      
"while_readline.sh" [New] 13L, 320C written            
[[email protected]-01 /server/tools]# sh while_readline.sh
#!/bin/bash   
##############################################################
# File Name: while_01.sh
# Version: V1.0
# Author: pizza
# Created Time : 2019-03-30 07:19:26
# Description:
##############################################################
while true
do
uptime >> /tmp/uptime.log
sleep 2 # 暂停2s
usleep 2000 # 微秒
done

 

体验2

[[email protected]01 /server/tools]# seq 10 >>num.log
脚本
sum=0
while read line
do
    ((sum+=line))

done<./num.log
echo $sum     
执行
[[email protected]-01 /server/tools]# sh while_num_add.sh
55

 

答案

sum=0
awk {print $10} access_2010-12-8.log |grep -v -|while read line
do
    ((sum+=line))
done
echo sum 
# 已经计算了,但是最后的结果是0
# 这是因为执行了子shell
# 使用下面的方法可以成功输出                                             

sum=0
awk {print $10} access_2010-12-8.log |grep -v - > any_sum.log
do
    ((sum+=line))
done<./any_sum.log
echo sum 

 

 小结

1、while循环的特长是执行守护进程,以及实现我们希望循环不退出持续执行的应用

擅长用于频率小于1分钟循环处理,其他的while循环几乎都可以被for以及定时任务crond替代

2、if、for最常用,然后是while(守护进程),case(服务启动脚本)

Shell脚本中各个语句的使用场景

  1、条件表达式,用于简短的条件判断及输出(文件是否存在,字符串是否为空)

  2、if取值判断,多用于不同值数量较少的情况

  3、for正常的循环应用处理,最常用

  4、while多用于守护进程,无限循环(要加sleep,usleep,控制pinlv)应用

  5、case 多用于服务启动脚本,打印菜单可用select语句,不过很少用,都用cat的here文档方法替代

  6、函数用途主要指编码逻辑清晰,减少重复语句开发

for循环

for循环语句和while循环语句类似,但for循环语句主要用于执行次数有限的循环,而不是用于守护进程以及无限循环。for循环语句常见的语法有两种, 下面将在不同的语法中对for循环语句进行详尽的讲解。

技术图片

..

范例1:用for循环竖向打印1、234、5共5个数字。
范例2:通过开发脚本实现仅设置sshd rsyslog crond network sysstat服务开机自启动。
范例3:计算从1加到100之和。
范例4:在Linux下批量修改文件名,将文件名中的“_finished”去掉。
准备测试数据,如下。
[[email protected] test]# mkdir /oldboy -p
[[email protected] test]# cd /oldboy
[[email protected] oldboy]# touch stu_102999_1_finished.jpg stu_102999_2_finished.jpg stu_102999_3_finished.jpg 
[[email protected] oldboy]# touch stu_102999_4_finished.jpg stu_102999_5_finished.jpg
[[email protected] oldboy]# ls -l
总用量 0
-rw-r--r-- 1 root root 0 9月   5 10:43 stu_102999_1_finished.jpg
-rw-r--r-- 1 root root 0 9月   5 10:43 stu_102999_2_finished.jpg
-rw-r--r-- 1 root root 0 9月   5 10:43 stu_102999_3_finished.jpg
-rw-r--r-- 1 root root 0 9月   5 10:43 stu_102999_4_finished.jpg
-rw-r--r-- 1 root root 0 9月   5 10:43 stu_102999_5_finished.jpg

ls *.jpg|awk -F "_finished" {print "mv",$0,$1$2}|bash
rename "_finished" "" *.jpg
for file in `ls ./*.jpg`
do
    mv $file `echo ${file/_finished/}`
done

 

范例1答案

for n in 1 2 3 4 5  或者 {1..5}  或者seq 5 
do
    echo $n
done
echo "---------"
for ((i=1;i<=5;i++))
do
    echo $i
done                                                                                                                                                                                                                                                                               
"for_printnum.sh" [New] 18L, 350C written              
[[email protected]-01 /server/scripts]# sh for_printnum.sh
1
2
3
4
5
---------
1
2
3
4
5

 

范例2答案

for name in sshd rsyslog crond network sysstat
do
    echo "chkconfig $name on"                                            
done

相当于在命令行执行
[[email protected] /server/scripts]# chkconfig |grep 3:on |awk ‘{print "chkconfig",$1,"off"}‘|bash

 

范例3

1、for循环
2、while循环
3、算法 

 

范例4

1mv $file echo ${file/_finished/}
2、不用for循环
[[email protected]-01 /server/scripts]# ls *.jpg|awk -F "_finished" {print $0,$1$2}
3、rename  from  to  file
rename  _finished ""  *.jpg

 

循环控制语句break、continue、exit、return

上述命令中breakcontinue在条件语句及循环语句(forwhileif等)中用于控制程序的走向,

exit用于终止所有语句并退出当前脚本,除此之外,exit还可以返回上一次程序或命令的执行状态值给当前Shell

return类似exit,只不过return用于函数内部返回函数执行的状态值

break n    如果省略n表示跳出整个循环,n 表示跳出循环的层数
continue n    如果省略n表示跳过本次循环,忽略本次循环的剩余代码,进入循环的下一次循环。n 表示退到第n层继续循环
exit n    退出当前shell程序,n为上一次程序执行的状态返回值。n也可以省略,再下一个shell里可通过$?接收exit n的n值
return n    用于在函数里,作为函数的返回值,用于判断函数执行是否正确。再下一个shell里可通过$?接收exit n的n值

 

 

Shell编程数组应用实践

为什么会产生shell数组

通常在开发Shell脚本时,我们定义变量采用的形式为a=1;b=2;c=3,可如果有多个变量呢?这时再一个一个定义很费劲,并且多个不确定的变量内容,也难以进行变量定义,此外快速读取不同变量的值也是一件很痛苦的事情,于是数组就诞生了,就是为了解决上述问题而来的

什么是Shell数组

 

如果读者有过其他语言的编程经历,那么想必会熟悉数组的概念。简单地说,Shell的数组就是把有限个元素(变量或字符内容)用一个名字命名,然后用编号对它们进行区分的元素集合。这个名字就称为数组名,用于区分不同内容的编号就称为数组下标。组成数组的各个元素变量称为数组的元素,有时也称为下标变量。

 

有了Shell数组后,就可以用相同名字引用一系列变量及变量值,并通过数字(索引)来识别使用它们。在许多场合,使用数组可以缩短和简化程序开发。


数组的本质还是变量,是特殊的变量形式
array=(1 2 3 4 5)

 

Shell数组的定义*****
    方法1:推荐,用小括号把变量值括起来赋值给数组变量,中间用空格分割
    array=(one two three four)
    方法2:用小括号把变量值括起来,同时采用键值对的形式赋值
    array=([0]=one [1]=two [2]=three [3]=four)
    方法3:通过分别定义数组变量的方式
    [[email protected] ~]# array[0]=one
    [[email protected] ~]# array[1]=two
    [[email protected] ~]# array[2]=three
    [[email protected] ~]# array[3]=four
    [[email protected] ~]# echo ${array[@]}
    one two three four
    方法4:命令的结果放到数组里,推荐。动态定义数组变量,使用命令的输出结果作为数组的内容
    array=(`ls /server/scripts`)

说明:还可以使用declare -a array来定义数组类型,但是比较少这样用。


操作数组元素
打印单个数组元素用${数组名[下标]},当未指定数组下标时,数组的下标是从0开始。
使用*或者@可以得到整个数组内容。
用${#数组名[@或*]}可以得到数组长度,这和前文讲解的变量子串知识是一样的,因为数组也是变量,只不过是特殊的变量,因此也适合变量的子串替换等知识。

读取数组内容:*****
[[email protected] ~]# array=( 1 2 3 4 5)
[[email protected] ~]# echo ${array[0]}
1
[[email protected] ~]# echo ${array[1]}
2
[[email protected] ~]# echo ${array[2]}
3
[[email protected] ~]# echo ${array[3]}
4
[[email protected] ~]# echo ${array[4]}
5
[[email protected] ~]# echo ${array[5]}

[[email protected] ~]# echo ${array[*]}
1 2 3 4 5
[[email protected] ~]# echo ${array[@]}
1 2 3 4 5
[[email protected] ~]# echo ${#array[@]}
5
[[email protected] ~]# echo ${#array[*]}
5

给数组增加内容:
[[email protected] ~]# array[5]=oldboy   <==增加下标为5的数组元素。
[[email protected] ~]# echo ${#array[*]}
6
[[email protected] ~]# echo ${array[*]}
1 2 3 4 5 oldboy

删除数组元素:
[[email protected] ~]# unset array[1]
[[email protected] ~]# echo ${array[*]}
1 3 4 oldboy
[[email protected] ~]# unset array[0]
[[email protected] ~]# echo ${array[*]}
3 4 oldboy

数组赋值:
[[email protected]-01 /server/scripts]# array[4]=999
[[email protected]-01 /server/scripts]# echo ${array[*]}
1 2 3 4 999 6

数组的删除:
因为数组本质上还是变量,因此可通过“unset 数组[下标]”清除相应的数组元素,
如果不带下标,表示清除整个数组的所有数据。
[[email protected]-01 /server/scripts]# unset array[1]  删除单个元素
[[email protected]-01 /server/scripts]# echo ${array[*]}
1 3 4 999 6
[[email protected]-01 /server/scripts]# unset array    删除整个数组
[[email protected]-01 /server/scripts]# echo ${array[*]} 没有数据输出了

数组内容的截取和替换:
这里和前文变量子串的替换是一样的,因为数组是特殊的变量
[[email protected]-01 /server/scripts]# echo ${array[*]:1:3}  从下表为1的元素截取3个元素
2 3 4
替换 和sed命令,和变量子字符串的替换 很像,是一样的
[[email protected]-01 /server/scripts]# echo ${array[*]/1/999}
999 2 3 4 5 6 7 8 9 9990
[[email protected]-01 /server/scripts]# echo ${array[*]}  该操作不会改变原数组,要改变请参考赋值修改
1 2 3 4 5 6 7 8 9 10

数组也是变量,因此也适合于前面讲解过的变量的子串处理的功能应用。
数组的其他相关知识通过man bash然后搜Arrays来了解。

数组元素部分内容的删除如下:
[[email protected] data]# array=(one two three four five)
[[email protected] data]# echo ${array[@]}               
one two three four five
[[email protected] data]# echo ${array[@]#o*}    #<==从左边开始匹配最短的,并删除。
ne two three four five
[[email protected] data]# echo ${array1[@]##o*}  #<==从左边开始匹配最长的,并删除。
two three four five
[[email protected] data]# echo ${array[@]%f*}    #<==从右边开始匹配最短的,并删除。
one two three
[[email protected] data]# echo ${array[@]%%f*}   #<==从右边开始匹配最长的,并删除。
one two three

使用for循环打印数组元素
array=(1 2 3 4 5)
for n in ${array[*]}
do
    echo $n
done
echo =====================
#i为数组下标
for ((i=0;i<${#array[*]};i++))
do
    echo ${array[i]}
done 

array=([1]=one [2]=two [3]=three) 
array[0]=a;array[1]=b;array[2]=c
array=($(命令))
或
array=(`命令`)

 

shell数组企业面试题

1、利用bash for循环打印下面这句话中字母数不大于6的单词(某企业面试真题)。

I am pizza teacher welcome to luffy training class

array=(I am oldboy teacher welcome to oldboy training class)

for word in ${array[*]}
#或者
#for ((i=0;i<=${
array[*];i++})) do if [ ${#word} -lt 6 ]
  # if [ ${#array[i]} -lt 6 ]
then echo $word
   # echo
array[i] fi done

 

    

 

第十四章 编程规范
第十五章 脚本调试
第十六章 vim配置
第十七章 trap
第十八章 expect
第十九章 企业案例实战

第十九章 
企业面试题1:
分析:
1、获取随机小写字符。
echo $RANDOM$(date +%N)|md5sum|tr "[0-9]" "a-z"|cut -c 2-11

2、for循环

企业面试题3:
101..10
[[email protected] ~]# seq -w 10
01
02
03
04
05
06
07
08
09
10
[[email protected] ~]# echo ${01..10}
-bash: ${01..10}: bad substitution
[[email protected] ~]# echo {01..10}
01 02 03 04 05 06 07 08 09 10

2echo $RANDOM|md5sum|cut 1-8
3、for循环批量设置用户和密码。

企业面试题4:

1、如何判断机器是否是活的。
ping 10.0.0.53 -c 2 -W 3 有返回。
nmap -sP 10.0.0.0/24

2.for循环

#!/bin/sh
CMD="nmap -sP"
Ip="10.0.0.0/24"
$CMD $Ip|awk /Nmap scan report for/ {print $NF}

http://blog.51cto.com/oldboy/1632876
10,11,18,19,2013,6

 

以上是关于shell编程企业级实战的主要内容,如果未能解决你的问题,请参考以下文章

牛!一文详解企业级Shell脚本编程!(建议收藏)

云计算 | Shell脚本自动化编程实战视频教程

SHELL用法五(Case语句)

shell编程基础-shell分库备份

Shell企业案例实战和企业面试题

CentOS shell企业案例实战