shell脚本进阶

一、for循环

for 变量名 in 列表;do

循环体

done

 

列表生成方式:

(1) 直接给出列表

(2) 整数列表:

(a) {start..end}

(b) $(seq [start [step]] end)

(3) 返回列表的命令

$(COMMAND)

(4) 使用glob,如:*.sh

(5) 变量引用;

$@, $*

 

例1:

[root@centos6 data]#for i in /data/*.sh;do echo the filename is $i;done

the filename is /data/67_createuser.sh

the filename is /data/checkint.sh

the filename is /data/createuser.sh

the filename is /data/filetype.sh

the filename is /data/if.sh

 

 

例2:求100以内的偶数和

#!/bin/bash

#

declare -i sum=0

 

for i in `seq 2 2 100`;do

let sum+=i

done

echo sum=$sum

 

 

例3:脚本内多行重定向写法

for i in {1..10};do

cat >> f1 <<-EOF

aa

bb

EOF

done

EOF前加上-

 

例4:创建10个用户,分别为user1到user10,密码分别为12345

#!/bin/bash

#

for i in user{1..10};do

if id $i &>/dev/null;then

echo “$i is exist”

else

useradd $i

echo “$i has created”

echo 12345 |passwd –stdin $i &>/dev/null

fi

done

 

 

例5:扫描某个网段的所有主机,在线显示up,不在线显示down,把在线的主机ip保存到文件中hostup.list

#!/bin/bash

#

net=192.168.67

for i in {1..254};do

{ if ping -c1 -w1 $net.$i &>/dev/null;then

echo “$net.$i is up”

echo $net.$i >> /data/hostup.list

else

echo “$net.$i is down”

fi } &

done

wait

加上{ }加快运行速度,多个程序并行执行,wait表示执行结束自动弹出

 

 

 

二、let命令中 i++与++i 的区别

i++:

[root@centos6 data]#i=0

[root@centos6 data]#let i++

[root@centos6 data]#echo $?

1

++i:

[root@centos6 data]#i=0

[root@centos6 data]#let ++i

[root@centos6 data]#echo $?

0

 

 

三、eval命令

[root@centos6 data]#n=3;for i in `eval echo {1..$n}`;do echo num is $i ;done

num is 1

num is 2

num is 3

eval命令会先引用变量$n,让后在执行echo命令

 

 

四、for循环嵌套

for i in {1..10};do

for i in {1..10};do

done

done

 

例1:打印矩形

 

length=$1

width=$2

for i in `seq 1 $length`;do

for j in `seq 1 $width`;do

color=$[RANDOM%7+31]

bk=$[RANDOM%7+41]

echo -e “\e[1;5;${bk};${color}m*\e[0m\c”

done

echo

done

 

 

例2:打印9*9乘法表

for i in {1..9};do

for j in `seq 1 $i`;do

sum=$[i*j]

echo -e “${j}*${i}=${sum}\t\c”

done

echo

done

 

例3:打印国际象棋

for i in {1..8};do

for k in {1..2};do

if [ $[i%2] -eq 0 ];then

for j in {1..4};do

echo -e “\e[1;42m    \e[0m\c”

echo -e “\e[1;43m    \e[0m\c”

done

echo

else

for j in {1..4};do

echo -e “\e[1;43m    \e[0m\c”

echo -e “\e[1;42m    \e[0m\c”

done

echo

fi

done

done

 

 

 

例4:打印等腰三角形

#!/bin/bash

#

#********************************************************************

#Author:                wqf

#QQ:                    88888888

#Date:                  2018-05-08

#FileName:             sanjiaoixng.sh

#URL:                   http://www.magedu.com

#Description:          The test script

#Copyright (C):         2018 All rights reserved

#********************************************************************

read -p “please input line num: ”  line

declare -i linenum=0

 

for i in `seq 1 $line`;do

let ++linenum

star=$[linenum*2-1]

space=$[line-linenum]

for k in `seq $space`;do

echo -e ” \c”

done

 

for j in `seq $star`;do

echo -e “*\c”

done

echo

done

 

[root@centos6 data]#sanjiaoxing.sh

please input line num: 6

*

***

*****

*******

*********

***********

 

 

五、while循环

while CONDITION; do

循环体

done

 

CONDITION:循环控制条件;进入循环之前,先做一次判断;每一次循环之后会再次做判断;条件为“true”,则执行一次循环;直到条件测试状态为“false”终止循环

因此:CONDTION一般应该有循环控制变量;而此变量的值会在循环体不断地被修正

进入条件:CONDITION为true

退出条件:CONDITION为false

 

 

例1:求100以内奇数和

#!/bin/bash

#

declare -i sum=0

declare -i i=1

while [ $i -le 100 ];do

if [ $[i%2] -eq 1 ];then

sum+=i

fi

let i++

done

echo sum=$sum

 

 

例2:每7分钟执行某个命令

[root@centos6 data]#vim ping.sh

 

#!/bin/bash

#

while true;do

echo task

sleep 420

done

如果要防止脚本意外终端,可以用执行nohup scripts

 

例3:监控http服务,每10秒检查一次服务是否重启,如果没在线,就重启

#!/bin/bash

#

SLEEP=10

while true;do

if killall -0 httpd &>/dev/null;then

:

else

systemctl restart httpd

echo “at `date “+%F %T”` restart the httpd” >>/data/httpd.log

sleep $SLEEP

fi

done

killall -0 httpd 判断httpd服务是否在运行

 

 

 

六、until循环

until CONDITION; do

循环体

done

进入条件: CONDITION 为false

退出条件: CONDITION 为true

 

例1:如果wang用户登陆,则退出

#!/bin/bash

#

until w |grep wang &>/dev/null;do

sleep 1

done

echo “find wang login”

 

 

七、循环控制语句continue

用于循环体中

continue [N]:提前结束第N层的本轮循环,而直接进入下一轮判断;最内层为第1层

while CONDTIITON1; do

CMD1

if CONDITION2; then

continue

fi

CMDn

done

 

 

例1:continue

#!/bin/bash

#

for i in {1..10};do

if [ $i -eq 5 ];then

continue

fi

echo $i

done

执行结果是:当$i=5时,

[root@centos6 data]#continue.sh

1

2

3

4

6

7

8

9

10

 

例2:continue2

#!/bin/bash

#

for i in {1..3};do

for j in {1..10};do

if [ $j -eq 5 ];then

continue 2

fi

echo $j

done

echo

done

执行结果为:

[root@centos6 data]#continue.sh

1

2

3

4

1

2

3

4

1

2

3

4

continue2 退出的是外层的for循环语句,外层循环的echo执行也被终端

 

 

八、循环控制语句break

用于循环体中

break [N]:提前结束第N层循环,最内层为第1层

while CONDTIITON1; do

CMD1

if CONDITION2; then

break

fi

CMDn

done

 

例1:break

#!/bin/bash

#

for i in {1..3};do

for j in {1..10};do

if [ $j -eq 5 ];then

break

fi

echo $j

done

echo

done

执行结果为:

[root@centos6 data]#break.sh

1

2

3

4

 

1

2

3

4

 

1

2

3

4

此时break中断的是内部循环

例2:break2

 

#!/bin/bash

#

for i in {1..3};do

for j in {1..10};do

if [ $j -eq 5 ];then

break 2

fi

echo $j

done

echo

done

执行结果为:

[root@centos6 data]#break.sh

1

2

3

4

此时break 2中断的是外部循环

 

例3:猜数字,生成一个随机数,提示输入1到10以内的数字,然后比较大小,

#!/bin/bash

#

rand=$[RANDOM%11]

while read -p “please input a digit in 0 to 10: ” n;do

if  [[ ! “$n” =~ ^[0-9]+$ ]];then

echo “please in put a digit 1-10”

continue

fi

if [ “$n” -lt “$rand” ];then

echo “less”

elif [ “$n” -gt “$rand” ];then

echo “more”

else

echo “right”

break 2

fi

 

done

 

 

九、循环控制shift命令

shift [n]

用于将参量列表 list 左移指定次数,缺省为左移一次。

参量列表 list 一旦被移动,最左端的那个参数就从列表中删除。while 循环遍历位置参量列表时,常用到 shift

./doit.sh a b c d e f g h

./shfit.sh a b c d e f g h

 

例1:创建用户,

#!/bin/bash

#

until [ -z “$1” ];do

useradd $1

echo “$1 has created”

shift 1

done

echo done

 

例2:打印所有的

#!/bin/bash

while [ $# -gt 0 ] # or (( $# > 0 ))

do

echo $*

shift

done

 

十、while特殊用法

while循环的特殊用法(遍历文件的每一行):

while read line; do

循环体

done < /PATH/FROM/SOMEFILE

依次读取/PATH/FROM/SOMEFILE文件中的每一行,且将行赋值给变量line

 

例1:文件/etc/passwd中uid为偶数的行,显示其用户名和id号

while read  line;do

id=`echo $line|cut -d: -f3 `

user=`echo $line|cut -d: -f1`

 

if [ $[id%2] -eq 0 ];then

echo “$user:$id”

fi

done </etc/passwd

 

 

例2:检查分区利用率,利用率大于5报警,且显示其设备名

#!/bin/bash

df | while read line;do

if echo $line | grep “^/dev/sd” &>/dev/null;then

used=`echo $line | sed -nr “s/.*[ ]+([0-9]{1,3})%.*/\1/p”`

device=`echo $line | cut -d” ” -f1`

if [ $used -gt 5 ];then

echo “$device will full,used $used%”

fi

fi

done

 

 

十一、for循环的特殊格式:

for ((控制变量初始化;条件判断表达式;控制变量的修正表达式))

do

循环体

done

 

例1:1到100的和

#!/bin/bash

#

for ((sum=0,i=1;i<=100;i++ ));do

sum=$[sum+i]

done

echo sum=$sum

 

十二、select循环与菜单

select variable in list

do

循环体命令

done

select 循环主要用于创建菜单,按数字顺序排列的菜单项将显示在标准错误上,并显示 PS3 提示符,等待用户输入

用户输入菜单列表中的某个数字,执行相应的命令

用户输入被保存在内置变量 REPLY 中

select与case

select 是个无限循环,因此要记住用 break 命令退出循环,或用 exit 命令终止脚本。也可以按 ctrl+c 退出循环

select 经常和 case 联合使用

与 for 循环类似,可以省略 in list,此时使用位置参量

 

例1:

PS3=”please select scripts (1-4):”

select menu in etcbakup yum.sh alias.sh reset.sh;do

case $menu in

etcbakup)

echo “$REPLY:start bakup”

break

;;

yum.sh)

echo “$REPLY:start configuure yum”

break

;;

alias.sh)

echo “$REPLY:start configure alias”

break

;;

reset.sh)

echo “$REPLY:start reset the system environment”

break

;;

*)

echo “$REPLY:nothing to do”

;;

esac

done

 

 

十三、信号捕捉trap

trap ‘触发指令’ 信号

自定义进程收到系统发出的指定信号后,将执行触发指令,而不会执行原操作

trap ” 信号

忽略信号的操作

trap ‘-‘ 信号

恢复原信号的操作

trap -p

列出自定义信号操作

 

 

例1:捕捉信号2

trap “press the ctrl+c” 2                     ###使2信号失效,且提示press the ctrl+c

for (( i=0;i<=10;i++ ));do

echo $i

sleep 1

done

 

trap “” 2                                  ###使2信号失效,不提示

for (( i=11;i<=20;i++ ));do

echo $i

sleep 1

done

 

trap “-” 2

for (( i=21;i<=30;i++ ));do

echo $i

sleep 1

done

 

十四、定义函数

函数由两部分组成:函数名和函数体

help function

语法一:

f_name (){

…函数体…

}

语法二:

function f_name {

…函数体…

}

语法三:

function f_name () {

…函数体…

}

 

十五、查看函数、删除函数

declare -f 查看系统所有函数

declare -f function_name 查看函数

unset function_name 删除函数

 

十六、函数中变量生效范围

默认函数和当前shell的变量使通用的

[root@centos6 ~]#func1 () { name=wang;echo “func1:$name”; }

[root@centos6 ~]#func1

func1:wang

[root@centos6 ~]#echo $name

wang

 

让函数中变量只在函数中生效加上local,如:func1 () { local name=wang;echo “func1:$name”; }

 

declare -i 在函数中声明变量相当赋予了local的特性,只在函数中生效

[root@centos6 ~]#func2 () { declare -i num=100;echo “$num”; }

[root@centos6 ~]#func2

100

[root@centos6 ~]#echo $num

 

declare -ig 在函数中声明变量的相当于普通变量,在函数和当前shell生效(在centos6上不支持,支持centos7)

[root@centos7 boot]#func1 () { declare -ig num=100;echo $num; }

[root@centos7 boot]#func1

100

[root@centos7 boot]#echo $num

100

 

 

十七、函数调用

例1:根据参数选择

#!/bin/bash

green_yellow (){

if [ “$1” = “-r” ];then

echo -e “\e[1;43m \e[1;42m \e[0m\c”

else

echo -e “\e[1;42m \e[1;43m \e[0m\c”

fi

echo

}

green_yellow

green_yellow -r

 

例2:写一个函数,显示当前系统版本,如果是6则显示oldversion,否则显示最新版本

方法一

[root@centos7 boot]#version () {

> ver=`sed -r “s/.*[ ]+([0-9]+)\..*/\1/” /etc/centos-release`

> if [ $ver -eq 6 ];then

>     echo “oldversion”

> else

>     echo “newversion”

> fi

> echo $ver

> }

 

方法二

[root@centos7 boot]#version() { ver=`sed -r “s/.*[ ]+([0-9]+)\..*/\1/” /etc/centos-release`;echo “$ver”; }

[root@centos7 boot]#version

7

[root@centos7 boot]#if [ `version` -eq 6 ];then echo version is old;else echo version is new;fi

version is new

 

方法三:根据return返回值判断

[root@centos7 boot]#version() { ver=`sed -r “s/.*[ ]+([0-9]+)\..*/\1/” /etc/centos-release`;return $ver; }

[root@centos7 boot]#version

[root@centos7 boot]#echo $?

7

[root@centos7 boot]#if [ `version` -eq 6 ];then echo version is old;else echo version is new;fi

version is new

 

 

十八、实现多个脚本调用一个函数

编辑一个文件,如functions,把写好的函数都写入文件。然后在别的脚本中调用

写入脚本格式简单如下:

#!/bin/bash

source /data/functions

函数1

函数2

………..

 

十九、action函数

[root@centos7 boot]#source /etc/init.d/functions

[root@centos7 boot]#action “command successd”

command successd                                           [  OK  ]

[root@centos7 boot]#action “command failed” /bin/false

command failed                                             [FAILED]

 

二十、定义全局函数

全局函数在子shell生效,在脚本调用脚本时可用

[root@centos7 boot]#func1 () { local num=100;echo $num; }

[root@centos7 boot]#func1

100

[root@centos7 boot]#export -f func1

 

 

二十一、数组

变量:存储单个元素的内存空间

数组:存储多个元素的连续的内存空间,相当于多个变量的集合

数组名和索引

索引:编号从0开始,属于数值索引

注意:索引可支持使用自定义的格式,而不仅是数值格式,即为关联索引,bash4.0版本之后开始支持

bash的数组支持稀疏格式(索引不连续)

声明数组:

declare -a ARRAY_NAME  普通数组

declare -A ARRAY_NAME: 关联数组  必须先声明,后使用

注意:两者不可相互转换

 

二十二、数组元素的赋值:

(1) 一次只赋值一个元素

ARRAY_NAME[INDEX]=VALUE

weekdays[0]=”Sunday”

weekdays[4]=”Thursday”

(2) 一次赋值全部元素

ARRAY_NAME=(“VAL1” “VAL2” “VAL3″ …)

(3) 只赋值特定元素

ARRAY_NAME=([0]=”VAL1″ [3]=”VAL2” …)

(4) 交互式数组值对赋值

read -a ARRAY

 

1.一次只赋值一个元素

[root@centos6 data]#declare -a name[1]=a

[root@centos6 data]#declare -a name[2]=b

[root@centos6 data]#declare -a name[3]=c

显示所有数组元素

[root@centos6 data]#echo ${name[*]}

a b c

 

2.一次赋值多个元素(可以生成列表)

例1:

[root@centos6 data]#declare -a name=(“c” “d” “e”)

[root@centos6 data]#echo ${name[*]}

c d e

 

例2:生成列表

[root@centos6 data]#number=({1..10})

[root@centos6 data]#echo ${number[*]}

1 2 3 4 5 6 7 8 9 10

 

例3:

[root@centos6 data]#filename=(/data/*.sh)

[root@centos6 data]#echo ${filename[@]}

/data/3.sh /data/67_createuser.sh /data/9×9.sh /data/a.sh /data/checkint.sh

 

3.赋值特定的元素

[root@centos6 data]#name=([1]=x [2]=y)

[root@centos6 data]#echo ${name[*]}

x y

4.交互式数组赋值

例1:

[root@centos6 data]#read -a name

wang li zhang zhao

[root@centos6 data]#echo ${name[*]}

wang li zhang zhao

 

显示所有数组:

declare -a

引用数组

引用数组元素:

${ARRAY_NAME[INDEX]}

注意:省略[INDEX]表示引用下标为0的元素

引用数组所有元素:

${ARRAY_NAME[*]}

${ARRAY_NAME[@]}

数组的长度(数组中元素的个数):

${#ARRAY_NAME[*]}

${#ARRAY_NAME[@]}

删除数组中的某元素:导致稀疏格式

unset ARRAY[INDEX]

删除整个数组:

unset ARRAY

 

二十三、在已有的数组后面添加新元素

  首先不知道哪些下标被占用,可以这样定义declare -a name[${#name[*]}]=wang

${#name[*]}代表元素的个数

 

 

二十四、生成20个随机数保存于数组中,并找出其最大值和最小值

#!/bin/bash

#

declare -a rand

for ((i=0;i<20;i++));do

rand[$i]=$RANDOM

if [ $i -eq 0 ];then

max=${rand[$i]}

min=${rand[$i]}

else

[ $max -lt ${rand[$i]} ] && max=${rand[$i]}

[ $min -gt ${rand[$i]} ] && min=${rand[$i]}

fi

done

echo ${rand[*]}

echo $max $min

 

二十五、数组赋值

#!/bin/bash

#

declare -A disk

df |grep ^/dev/sd |while read line;do

device=`echo $line|cut -d” ” -f1`

used=`echo $line |sed -r “s/.*[ ]([0-9]{1,3}).*/\1/”`

disk[$device]=$used

echo ${disk[$device]}

done

 

二十六、字符串切片

${#var}:返回字符串变量var的长度

例1:

[root@centos6 ~]#str=`echo {a..z}|tr -d ” “`

[root@centos6 ~]#echo $str

abcdefghijklmnopqrstuvwxyz

[root@centos6 ~]#echo ${#str}

26

 

${var:offset}:表示跳过几个开始取值

例:跳过5个开始取值

[root@centos6 ~]#echo $str

abcdefghijklmnopqrstuvwxyz

[root@centos6 ~]#echo ${str:5}

fghijklmnopqrstuvwxyz

 

${var:offset:N }:表示跳过前几个子浮窗,然后取N个子浮窗

例:

[root@centos6 ~]#echo $str

abcdefghijklmnopqrstuvwxyz

[root@centos6 ~]#echo ${str:3:4}

defg

 

${var: -offset}:表示取后面倒数几个字符,注意-offset前面要加空格

例:

[root@centos6 ~]#echo $str

abcdefghijklmnopqrstuvwxyz

[root@centos6 ~]#echo ${str: -3}

xyz

 

${var:offset:-length}:从最左侧跳过offset字符,一直向右取到距离最右侧lengh个字符之前的内容(去头去尾取中间)

例:

[root@centos7 ~]#echo $str

abcdefghijklmnopqrstuvwxyz

[root@centos7 ~]#echo ${str:3:-3}

defghijklmnopqrstuvw

 

例2:取后面4个,再去掉最后两个

[root@centos7 ~]#echo $str

abcdefghijklmnopqrstuvwxyz

[root@centos7 ~]#echo ${str: -4:-2}

wx

 

 

命令matemp

创建随机文件

[root@centos6 data]#mktemp  /data/tmpXXXX

/data/tmp4YEW

创建随机目录-d

[root@centos6 data]#mktemp -d /data/tmpXXXXX

/data/tmpq9VGE

-p指定生成文件后放置的目录

[root@centos6 data]#mktemp -p /data/ tmpXXXXXXX

/data/tmpLCNalET

 

-p指定目录可以用变量替代,执行的结果也可以放置到一个变量之中,方便以后查找删除

tmpfile=`mktemp -p “$dir” tmpXXXX

rm -rf $tempfile

 

 

install命令:

install [OPTION]… [-T] SOURCE DEST 单文件

install [OPTION]… SOURCE… DIRECTORY

install [OPTION]… -t DIRECTORY SOURCE…

install [OPTION]… -d DIRECTORY…创建空目录

选项:

-m MODE,默认755

-o OWNER

-g GROUP

示例:

install -m 700 -o wang -g admins srcfile desfile

install –m 770 –d /testdir/installdir

 

     

本文来自投稿,不代表Linux运维部落立场,如若转载,请注明出处:http://www.178linux.com/98464

(0)
王琪锋王琪锋
上一篇 2018-05-13
下一篇 2018-05-14

相关推荐

  • 实现创建私有CA

    CA的构成:PKI: Public Key Infrastructure签证机构:CA(Certificate Authority)注册机构:RA证书吊销列表:CRL证书存取库:X.509:定义了证书的结构以及认证协议标准版本号序列号签名算法颁发者有效期限主体名称主体公钥CRL分发点扩展信息发行者签名证书类型:证书授权机构的证书服务器用户证书获取证书两种方法…

    Linux笔记 2018-05-22
  • 用户、组和权限

    安全3A Authentication:认证 Authorization:授权 Accouting|Audition:审计 用户user 令牌token,identity Linux用户:username/UID 管理员:root,0(玉玺) 普通用户:1-65535 系统用户:1-499,1-999(centos7)(通关文牒) 对守护进程获取资源进行权限…

    2018-04-04
  • 使用gpg工具实现公钥加密

    本实验通过gpg工具 实现 用非对称密钥加密方法,对Centos 7 主机的文件fstab,用Centos6的公钥加密,并且到Centos6 用私钥解密文件。

    2018-05-16
  • Linux系统计划任务

    在生活、生产环境中,我们可能遇到这样的场景,想在某个时刻,或者固定某个时间周期的在Linux系统中执行某项任务,例如,定时关机,定期自动清理垃圾文件等,at,crontab等命令就是帮你实现这样功能的。

    2018-05-06
  • linux发行版之间的爱恨情仇

    千丝万缕,森罗万象

    Linux笔记 2018-05-13
  • Linux的哲学思想

    Linux的哲学思想 1、一切皆文件(硬件设备亦如此): 所有资源在Linux上都已以文件方式存在,包括硬件设备(设备文件)通信接口。 linux 系统中所有的设备都是作为文件系统的一个节点来挂载和使用的,比如光驱,一般挂载在 /mnt/ cdrom 里,cpu挂载在/dev/cpu. 2、 由众多功能单一的小程序组成: 且每一个小程序只做一件事情,并且只做…

    Linux笔记 2018-08-04