当前位置:   article > 正文

第十五章 SHELL脚本编程进阶

第十五章 SHELL脚本编程进阶

highlight: a11y-dark

theme: juejin

@TOC

实验⼀:建⽴循环脚本

⽬的

建立循环脚本。

前提

linux系统,centos6、centos7或ubuntu,连接网络。

命令介绍

1、循环

1.1、for循环

csharp for 变量名 in 列表;do 循环体 done

【例1】循环。

```csharp [root@localhost data]# for id in a b c d ;do echo id is $id ; done id is a id is b id is c id is d

[root@localhost data]# for id in {a..d} ;do echo id is $id ; done id is a id is b id is c id is d ``` 【例2】循环。

```csharp [root@localhost data]# for id in {1..10} ;do echo id is $id ; done id is 1 id is 2 id is 3 id is 4 id is 5 id is 6 id is 7 id is 8 id is 9 id is 10

[root@localhost data]# for id in {1..10 } ;do echo id is $id ; done id is {1..10 id is } ```

注意:10后不能有空格。

【例3】循环,递增2。

csharp [root@localhost data]# for id in {1..10..2} ;do echo id is $id ; done id is 1 id is 3 id is 5 id is 7 id is 9 【例4】循环,递减2。

csharp [root@localhost data]# for id in {10..1..-2} ;do echo id is $id ; done id is 10 id is 8 id is 6 id is 4 id is 2

【例5】seq。

csharp [root@localhost data]# seq 10 1 2 3 4 5 6 7 8 9 10

【例6】seq,1到10,递增3。

csharp [root@localhost data]# seq 1 3 10 1 4 7 10 【例7】循环+seq。

csharp [root@localhost data]# for id in `seq 1 3 10` ;do echo id is $id ; done id is 1 id is 4 id is 7 id is 10 [root@localhost data]# for id in *.sh ;do echo id is $id ; done id is 9x9.sh id is arg.sh

【例8】循环,批量改⽂件名。

```csharp [root@localhost data]# mkdir /data/dir [root@localhost data]# touch /data/dir/1.jpg [root@localhost data]# touch /data/dir/2.png [root@localhost data]# touch /data/dir/3.bmp [root@localhost data]# ll /data/dir/ total 0 -rw-r--r-- 1 root root 0 May 18 10:06 1.jpg -rw-r--r-- 1 root root 0 May 18 10:06 2.png -rw-r--r-- 1 root root 0 May 18 10:06 3.bmp

[root@localhost data]# vim rename.sh

!/bin/bash

for file in /data/dir/*;do filename=echo $file |sed -nr 's#(.*)\..*$#\1#p' mv $file ${filename}.log echo $file is rename ${file_name}.log done

[root@localhost data]# bash rename.sh /data/dir/1.jpg is rename /data/dir/1.log /data/dir/2.png is rename /data/dir/2.log /data/dir/3.bmp is rename /data/dir/3.log ``` 【例9】for循环,1+100。

```csharp [root@localhost data]# vim sum.sh

!/bin/bash

sum=0 for i in {1..100};do let sum+=i done echo sum=$sum [root@localhost data]# bash sum.sh sum=5050

[root@localhost data]# seq -s+ 100 | bc 5050

[root@localhost data]# echo {1..100} | tr " " "+" | bc 5050

[root@localhost data]# echo {1..100} | tr " \t" "+" | bc 5050

[root@localhost data]# seq 100 | tr "\n" "+" | sed 's#+$#\n#g' | bc 5050 ``` 【例10】批量创建⽤户。

```csharp

把用户名写到文件中

[root@localhost data]# cat /data/name.txt zhao qian sun li

脚本调用文件

[root@localhost data]# vim creatuser.sh

!/bin/bash

for USER in cat /data/name.txt;do if id $USER &>/dev/null;then echo $USER is exist! else useradd $USER echo $SUER |passwd --stdin $USER &>/dev/null echo $USER is created! fi done

[root@localhost data]# bash creatuser.sh zhao is created! qian is created! sun is created! li is created!

[root@localhost data]# chmod +x creatuser.sh [root@localhost data]# ./creatuser.sh zhao is exist! qian is exist! sun is exist! li is exist! ``` 【例11】批量创建⽤户,选项。

```csharp [root@localhost data]# cat batch_users.sh

!/bin/bash

if [ "$1" = '-c' ];then for USER in cat /data/name.txt;do if id $USER &> /dev/null;then echo "$USER is exist" else useradd $USER echo $USER | passwd --stdin $USER &>/dev/null echo "$USER is created" fi done elif [ "$1" = '-r' ];then for USER in cat /data/name.txt;do userdel -r $USER &> /dev/null echo $USER is remove done else echo "Usage: basename $0 -c | -r " fi

[root@localhost data]# bash batchusers.sh -c #创建 zhao is created qian is created sun is created li is created [root@localhost data]# bash batchusers.sh -r #删除 zhao is remove qian is remove sun is remove li is remove ``` 【例12】扫描地址段。

```csharp [root@localhost data]# vim scan.sh

!/bin/bash

IP地址、可变更

NET=192.168 for SUBNET in {0..3};do for HOST in {1..5};do ping -c1 -W1 $NET.$SUBNET.$HOST &> /dev/null && echo $NET.$SUBNET.$HOST is up! || echo $NET.$SUBNET.$HOST is down! done wait done wait echo "scan host is finished"

[root@localhost data]# bash scan.sh 172.22.0.1 is up! 172.22.0.2 is down! 172.22.0.3 is down! 172.22.0.4 is down! 172.22.0.5 is down! 172.22.1.1 is down! 172.22.1.2 is down! 172.22.1.3 is down! 172.22.1.4 is down! 172.22.1.5 is down! 172.22.2.1 is down! 172.22.2.2 is down! 172.22.2.3 is down! 172.22.2.4 is down! 172.22.2.5 is down! 172.22.3.1 is down! 172.22.3.2 is down! 172.22.3.3 is down! 172.22.3.4 is down! 172.22.3.5 is down! scan host is finished ``` 【例13】扫描地址段,同时。

```csharp [root@localhost data]# vim scan_host.sh

!/bin/bash

NET=192.168 for SUBNET in {0..255};do { for HOST in {1..254};do { ping -c1 -W1 $NET.$SUBNET.$HOST &> /dev/null && echo $NET.$SUBNET.$HOST is up; }& done }& wait done wait echo "scan host is finished"

[root@localhost data]# bash scan_host.sh 172.22.0.6 is up 172.22.0.1 is up 172.22.0.7 is up 172.22.0.50 is up 172.22.0.100 is up 172.22.0.111 is up 172.22.0.154 is up ... ``` 【例14】星星,随机闪光。

```csharp [root@localhost data]# vim star.sh

!/bin/bash

read -p "Line: " line read -p "col: " col

col=10

line=20

BEGIN='\033[1;5;' for i in seq $line;do for j in seq $col;do COL=$[RANDOM%7+31]m echo -e "${BEGIN}${COL}*\c" done echo -e '\033[0m' done

[root@localhost data]# bash star.sh Line: 5 col: 5





```

【例15】100内累加,for循环中,(( ))的⽤法。

```csharp [root@localhost data]# vim sum_for.sh

!/bin/bash

sum=0 for ((i=1;i<=100;i++));do let sum+=i done echo sum=$sum

[root@localhost data]# bash sum_for.sh sum=5050 ``` 【例16】随机数,最⼤,最⼩。

```csharp [root@localhost data]# vim maxminfor.sh

!/bin/bash

for((i=0;i<10;i++));do N=$RANDOM echo -e "$N \c" if [ $i -eq 0 ];then MAX=$N MIN=$N else

if [ $N -gt $MAX ];then

MAX=$N

fi

if [ $N -lt $MIN ];then

MIN=$N

fi

  1. [ $N -gt $MAX ] && MAX=$N
  2. [ $N -lt $MIN ] && MIN=$N
  3. fi

done echo echo MAX=$MAX,MIN=$MIN

[root@localhost data]# bash maxminfor.sh 27556 5595 925 26685 9777 6638 31368 12717 23468 2834 MAX=31368,MIN=925 ```


1.2、while循环

csharp while CONDITION; do 循环体 done 【例17】100内累加.

```csharp [root@localhost data]# vim sum_while.sh

!/bin/bash

sum=0 i=1 while [ $i -le 100 ];do let sum+=i let i++ done echo sum=$sum

[root@localhost data]# bash sum_while.sh sum=5050 ```

【例18】国际象棋,棋盘。 ```csharp [root@localhost data]# vim chess1_while.sh

!/bin/bash

i=1 BEGIN='\033[1;' RED=41m YELLOW=43m while [ $i -le 8 ] ;do j=1 while [ $j -le 4 ];do if [ $[i%2] -eq 0 ];then echo -e "${BEGIN}${RED} ${BEGIN}${YELLOW} \c" else echo -e "${BEGIN}${YELLOW} ${BEGIN}${RED} \c" fi let j++ done echo -e "\e[0m" let i++ done ```

```csharp [root@localhost data]# cat chess2_while.sh

!/bin/bash

i=1 BEGIN='\033[1;' RED=41m YELLOW=43m while [ $i -le 8 ] ;do if [ $[i%2] -eq 0 ];then j=1 while [ $j -le 4 ];do echo -e "${BEGIN}${RED} ${BEGIN}${YELLOW} \c" let j++ done else j=1 while [ $j -le 4 ];do echo -e "${BEGIN}${YELLOW} ${BEGIN}${RED} \c" let j++ done fi echo -e "\e[0m" let i++ done ```

```csharp [root@localhost data]# cat chess3_while.sh

!/bin/bash

i=1 BEGIN='\033[1;' RED=41m YELLOW=43m flag=true while [ $i -le 8 ] ;do if $flag ;then j=1 while [ $j -le 4 ];do echo -e "${BEGIN}${RED} ${BEGIN}${YELLOW} \c" let j++ done flag=false else j=1 while [ $j -le 4 ];do echo -e "${BEGIN}${YELLOW} ${BEGIN}${RED} \c" let j++ done flag=true fi echo -e "\e[0m" let i++ done ```

【例19】监控httpd服务。

```csharp

安装、启动httpd服务

[root@localhost data]# yum install httpd -y [root@localhost data]# systemctl start httpd [root@localhost data]# pidof httpd 2968 2967 2966 2965 2964 2963

[root@localhost data]# vim monitorhttpdwhile.sh

!/bin/bash

SLEEPTIME=30 SERVICE=httpd LOG=/var/log/monitor_$SERVICE.log while true;do if killall -0 $SERVICE &>/dev/null;then true else systemctl restart $SERVICE echo "AT date +'%F %T' $SERVICE is restart" | tee -a $LOG | mail -s warning root fi sleep $SLEEPTIME done

[root@localhost ~]# bash monitorhttpdwhile.sh

打开workspace2,或者用xshell,再打开同一个主机。杀死进程,查看日志。

[root@localhost ~]# killall httpd [root@localhost ~]# tail -f /var/log/monitor_httpd.log AT 2019-05-20 09:47:12 httpd is restart AT 2019-05-20 09:47:46 httpd is restart AT 2019-05-20 09:48:46 httpd is restart ```


1.3、until循环

csharp until CONDITION; do 循环体 done

1.3.1、循环控制语句continue⽤于循环体中

```csharp

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

while CONDTIITON1; do CMD1 ... if CONDITION2; then continue fi CMDn ... done ```

【例20】continue.

```csharp [root@localhost data]# vim continue.sh

!/bin/bash

for ((i=0;i<10;i++));do if [ $i -eq 5 ];then continue;fi echo i=$i done

[root@localhost data]# bash continue.sh i=0 i=1 i=2 i=3 i=4 i=6 i=7 i=8 i=9 ``` 【例21】continue嵌套,循环第⼆层。

```csharp [root@localhost data]# vim continue2.sh

!/bin/bash

for ((i=0;i<3;i++));do for ((j=0;j<10;j++));do if [ $j -eq 5 ];then continue 2;fi echo j=$j done echo i=$i done

[root@localhost data]# bash continue2.sh j=0 j=1 j=2 j=3 j=4 j=0 j=1 j=2 j=3 j=4 j=0 j=1 j=2 j=3 j=4 ```

1.3.2、循环控制语句break

```csharp

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

while CONDTIITON1; do CMD1 ... if CONDITION2; then break fi CMDn ... done ```

【例22】break

```csharp [root@localhost data]# vim break.sh

!/bin/bash

for ((i=0;i<10;i++));do if [ $i -eq 5 ];then break ;fi echo i=$i done

[root@localhost data]# bash break.sh i=0 i=1 i=2 i=3 i=4 ``` 【例23】break嵌套,循环第⼆层。

```csharp [root@localhost data]# vim break2.sh

!/bin/bash

for ((i=0;i<3;i++));do for ((j=0;j<10;j++));do if [ $j -eq 5 ];then break 2;fi echo j=$j done echo i=$i done

[root@localhost data]# bash break2.sh j=0 j=1 j=2 j=3 j=4 ```

1.3.2、循环控制shift命令

csharp 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 【例24】shift,增加⽤户&删除⽤户。

```csharp [root@localhost data]# vim createuser_shift.sh

!/bin/bash

if [ -z "$1" ];then echo "Usage: basename $0 username ..." exit fi while [ "$1" ];do if id $1 &> /dev/null ;then echo $1 is exist else useradd $1 echo $1 is created fi shift done

[root@localhost data]# bash createuser_shift.sh a b c a is created #创建 b is created c is created

[root@localhost data]# bash createuser_shift.sh a b c a is exist #存在 b is exist c is exist

[root@localhost data]# getent passwd 查看用户 root:x:0:0:root:/root:/bin/bash ... 中间省略 apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin a:x:1005:1005::/home/a:/bin/bash b:x:1006:1006::/home/b:/bin/bash c:x:1007:1007::/home/c:/bin/bash

删除用户(a,b,c)

[root@localhost data]# for i in {a..c};do userdel -r $i;done

[root@localhost data]# getent passwd 查看用户 root:x:0:0:root:/root:/bin/bash ... 中间省略 apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin ```

【例25】读取⽂件,逐⾏处理。

```csharp [root@localhost data]# vim name.txt zhao qian sun li

[root@localhost data]# vim while_read1.sh

!/bin/bash

while read name;do useradd $name echo $name is created done < name.txt

[root@localhost data]# bash while_read1.sh zhao is created qian is created sun is created li is created

第二种形式:

[root@localhost data]# vim while_read2.sh

!/bin/bash

cat name.txt | while read name;do useradd $name echo $name is created done

[root@localhost data]# bash while_read2.sh useradd: user 'zhao' already exists zhao is created useradd: user 'qian' already exists qian is created useradd: user 'sun' already exists sun is created useradd: user 'li' already exists li is created

删除用户: [root@localhost data]# for i in cat name.txt;do userdel -r $i;done ``` 【例26】程序执⾏结果,逐⾏处理。每分钟检查磁盘利⽤率,超过10%的报警。

```csharp [root@localhost data]# vim diskcheckwhile.sh

!/bin/bash

df | while read line ;do DEVICE=echo $line | sed -rn '/^\/dev\/sd/s@^([^ ]+).* ([0-9]+)%.*$@\1@p' USED=echo $line | sed -rn '/^\/dev\/sd/s@^([^ ]+).* ([0-9]+)%.*$@\2@p' if [ $USED -gt 10 ];then wall $DEVICE will be full,USED:$USED% fi done

[root@localhost data]# chmod +x diskcheckwhile.sh [root@localhost data]# pwd /data [root@localhost data]# crontab -e * * * * * /data/diskcheckwhile.sh

[root@localhost data]# Broadcast message from root@localhost.localdomain (Mon May 20 11:29:01 2019):

/dev/sda1 will be full,USED:16%

Broadcast message from root@localhost.localdomain (Mon May 20 11:30:01 2019):

/dev/sda1 will be full,USED:16% ^C You have new mail in /var/spool/mail/root ```

【例27】⼤于10次的,丢⼊防⽕墙,拒绝访问。ss.log文件下载 ```csharp [root@localhost data]# vim deny_while.sh

!/bin/bashsed -nr '/^ESTAB/s#.* ([0-9.]+):[0-9]+.*$#\1#p' ss.log|sort |uniq -c |while read times ip

;do if [ $times -gt 10 ];then iptables -A INPUT -s $ip -j REJECT fi done

[root@localhost data]# iptables -F [root@localhost data]# iptables -vnL Chain INPUT (policy ACCEPT 22 packets, 1452 bytes) pkts bytes target prot opt in out source destination

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination

Chain OUTPUT (policy ACCEPT 12 packets, 1136 bytes) pkts bytes target prot opt in out source destination

[root@localhost data]# rz 导入ss.log文件

[root@localhost data]# bash deny_while.sh [root@localhost data]# iptables -vnL Chain INPUT (policy ACCEPT 6 packets, 396 bytes) pkts bytes target prot opt in out source destination
0 0 REJECT all -- * * 127.0.0.1 0.0.0.0/0 reject-with icmp-port-unreachable

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination

Chain OUTPUT (policy ACCEPT 4 packets, 448 bytes) pkts bytes target prot opt in out source destination ```

【例28】分析错误⽇志

csharp [root@localhost data]# rz 导入hack.log文件 [root@localhost data]# lastb -f hack.log |sed '/^$/d;$d'|sed -rn 's#.* ([0-9.]{7,15}) .*#\1#p' |sort |uniq -c |sort -nr|head 86294 58.218.92.37 43148 58.218.92.26 18036 112.85.42.201 10501 111.26.195.101 10501 111.231.235.49 10501 111.204.186.207 10501 111.11.29.199 10499 118.26.23.225 6288 42.7.26.142 4236 58.218.92.30


1.4、select循环与菜单

csharp select variable in list do 循环体命令 done

【例29】点菜。

```csharp [root@localhost data]# vim menu_select.sh

!/bin/bash

PS3="please choose a number: " select menu in suancaiyu kaoquanyang yangxiezi huoguo quit;do case $menu in suancaiyu) echo $menu price is ¥26 echo your input is $REPLY ;; kaoquanyang) echo $menu price is ¥600 echo your input is $REPLY ;; yangxiezi) echo $menu price is ¥150 echo your input is $REPLY ;; huoguo) echo $menu price is ¥100 echo your input is $REPLY ;; quit) break ;; *) echo your input is $RELPY echo input false esac done echo "点菜成功"

[root@localhost data]# bash menu_select.sh 1) suancaiyu 2) kaoquanyang 3) yangxiezi 4) huoguo 5) quit please choose a number: 2 kaoquanyang price is ¥600 your input is 2 please choose a number: 5 点菜成功 ```


1.5、定义函数

```csharp f_name () { ...函数体... }

删除shell函数 命令格式为:unset function_name

使子进程也可使用 声明:export -f function_name 查看:export -f 或 declare -xf ```

【例30】定义函数

```csharp [root@localhost data]# function func1 () {

ls hostname } [root@localhost data]# func1 9x9.sh continue.sh hack.log set.sh arg.sh correct.txt hello.sh shengdanshu.sh backup-script createuser_shift.sh history.sh son.sh backup-script2019-05-14 creatuser.sh issue.out ss.log localhost.localdomain ```

【例31】调⽤函数

```csharp [root@localhost data]# vim func1.sh

!/bin/bash

func1(){ echo func1 } func2(){ echo func2 } hostname

[root@localhost data]# bash func2.sh localhost.localdomain func1 ```

【例32】定义函数,脚本。

```csharp [root@localhost data]# vim functions

!/bin/bash

func1(){ echo func1 } func2(){ echo func2 }

[root@localhost data]# cat func2.sh

!/bin/bash

source functions func1

[root@localhost data]# bash func2.sh func1 ```

【例33】批量创建⽤户[要在文件夹下有name.txt文件]

```csharp [root@localhost data]# vim batch_users.sh

!/bin/bash

. /etc/init.d/functions if [ "$1" = '-c' ];then for USER in cat /data/name.txt;do if id $USER &> /dev/null;then action "$USER is exist" false else useradd $USER echo $USER | passwd --stdin $USER &>/dev/null action "$USER is create" true fi done elif [ "$1" = '-r' ];then for USER in cat /data/name.txt;do userdel -r $USER &> /dev/null echo $USER is removed done else echo "Usage: basename $0 -c | -r " fi

[root@localhost data]# bash batchusers.sh -r zhao is removed qian is removed sun is removed li is removed [root@localhost data]# bash batchusers.sh -c zhao is create [ OK ] qian is create [ OK ] sun is create [ OK ] li is create [ OK ] ```

【例34】return,返回值。

```csharp [root@localhost data]# vim functions

!/bin/bash

func1(){ local name=mage echo func1:$name return echo func1 } func2(){ echo func2 }

[root@localhost data]# vim func2.sh

!/bin/bash

source functions name=wang echo func3.sh:$name func1 echo return:$? echo func2.sh:$name

[root@localhost data]# bash func2.sh func3.sh:wang func1:mage return:0 func2.sh:wang ```

【例35】定义函数,⽤时调⽤。

```csharp [root@localhost data]# vim functions

!/bin/bash

func1(){ local name=mage echo func1:$name return 10 echo func1 } func2(){ echo 1st arg is $1 echo 2st arg is $2 echo all args are $* echo all args are $@ echo the number is $# echo func2 } isdigit(){ while [ "$1" ];do [[ ! "$1" =~ ^[0-9]+$ ]] && { echo input not a digit;return 1; } shift done return 0 } compare() { isdigit $* [ $? -eq 1 ] && return if [ "$1" -gt "$2" ];then echo $1 else echo $2 fi } fact(){ if [ $1 -eq 1 ];then echo 1 else echo $[fact $[$1-1]*$1] fi }

[root@localhost data]# vim func3.sh

!/bin/bash

. functions func2 a b c

[root@localhost data]# bash func3.sh 1st arg is a 2st arg is b all args are a b c all args are a b c the number is 3 func2 ```

【例36】定义函数,⽤时调⽤。

```csharp [root@localhost data]# vim functions

!/bin/bash

func1(){ local name=mage echo func1:$name return 10 echo func1 }

func2(){ echo 1st arg is $1 echo 2st arg is $2 echo all args are $* echo all args are $@ echo the number is $# echo func2 }

is_digit(){ while [ "$1" ];do [[ ! "$1" =~ ^[0-9]+$ ]] && { echo input not a digit;return 1; } shift done return 0 }

compare() { is_digit $* [ $? -eq 1 ] && return if [ "$1" -gt "$2" ];then echo $1 else echo $2 fi }

fact(){ if [ $1 -eq 1 ];then echo 1 else echo $[fact $[$1-1]*$1] fi }

[root@localhost data]# vim func4.sh

!/bin/bash

. functions compare $1 $2

[root@localhost data]# bash func4.sh 10 20 20 ```


1.6、函数递归:

函数直接或间接调用自身 注意递归层数

【例37】阶乘

```csharp [root@localhost data]# vim functions

!/bin/bash

func1(){ local name=mage echo func1:$name return 10 echo func1 } func2(){ echo 1st arg is $1 echo 2st arg is $2 echo all args are $* echo all args are $@ echo the number is $# echo func2 } isdigit(){ while [ "$1" ];do [[ ! "$1" =~ ^[0-9]+$ ]] && { echo input not a digit;return 1; } shift done return 0 } compare() { isdigit $* [ $? -eq 1 ] && return if [ "$1" -gt "$2" ];then echo $1 else echo $2 fi } fact(){ if [ $1 -eq 1 ];then echo 1 else echo $[fact $[$1-1]*$1] fi } [root@localhost data]# vim fact.sh

!/bin/bash

. functions fact $1 [root@localhost data]# bash fact.sh 4 24 [root@localhost data]# bash fact.sh 8 40320 ```

【例38】⾃⼰调⽤⾃⼰,死循环。

```csharp [root@localhost data]# vim f1.sh

!/bin/bash

echo $$ sleep 1 ./f1.sh [root@localhost data]# chmod +x f1.sh [root@localhost data]# bash f1.sh 9741 9743 9745 9747 ^C ```

【例39】国际象棋,棋盘

```csharp [root@localhost data]# vim chess6.sh

!/bin/bash

red(){ echo -e "\033[41m \033[0m\c" } yel(){ echo -e "\033[43m \033[0m\c" } redyel(){ for ((i=1;i<=4;i++));do for ((j=1;j<=4;j++));do red;yel done echo done } yelred(){ for ((i=1;i<=4;i++));do for ((j=1;j<=4;j++));do yel;red done echo done } for ((line=1;line<=8;line++));do [ $[$line%2] -eq 0 ] && redyel || yelred done ```

```csharp [root@localhost data]# vim chess7.sh

!/bin/bash

red(){ echo -e "\033[41m \033[0m\c" } yel(){ echo -e "\033[43m \033[0m\c" } redyel(){ for ((i=1;i<=4;i++));do for ((j=1;j<=4;j++));do [ "$1" = "-r" ] && { yel;red; } || { red;yel; } done echo done } for ((line=1;line<=8;line++));do [ $[$line%2] -eq 0 ] && redyel || redyel -r done ```


1.7、信号捕捉trap

csharp trap '触发指令' 信号 进程收到系统发出的指定信号后,将执行自定义指令,而不会执行原操作 trap '' 信号 忽略信号的操作 trap '-' 信号 恢复原信号的操作 trap -p 列出自定义信号操作 trap finish EXIT 当脚本退出时,执行finish函数

【例40】补捉,Ctrl + c:不退出。

csharp [root@localhost data]# 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

ctrl + c = 信号2

```csharp 终止sleep的方法: [root@localhost data]# sleep 1000 ^C (Ctrl + c) [root@localhost data]# sleep 1000 (用xshell打开相同的主机,发送信号:killall -2 sleep) [root@localhost data]# vim trap.sh

!/bin/bash

trap 'echo press ctrl+c' int (或者写成:2) for i in {1..10};do echo i=$i sleep 1 done

[root@localhost data]# bash trap.sh i=1 i=2 i=3 ^Cpress ctrl+c i=4 i=5 ^Cpress ctrl+c i=6 i=7 i=8 i=9 ^Cpress ctrl+c i=10 ```

【例41】补捉信号,忽略,恢复,终⽌。

```csharp [root@localhost data]# cat trap.sh

!/bin/bash

finish(){ echo finish run } trap 'echo press ctrl+c' int trap -p for i in {1..10};do echo i=$i sleep 1 done trap '' int trap -p for i in {11..20};do echo i=$i sleep 1 done trap '-' int trap finish EXIT trap -p

20-30之间Ctrl+c可以退出

for i in {21..30};do echo i=$i sleep 1 done

[root@localhost data]# bash trap.sh trap -- 'echo press ctrl+c' SIGINT i=1 i=2 ^Cpress ctrl+c i=3 i=4 i=5 i=6 ^Cpress ctrl+c i=7 i=8 i=9 i=10 trap -- '' SIGINT i=11 ^Ci=12 i=13 i=14 i=15 ^Ci=16 i=17 i=18 i=19 i=20 trap -- 'finish' EXIT i=21 ^Cfinish run ```


1.8、数组

cpp 变量:存储单个元素的内存空间 数组:存储多个元素的连续的内存空间,相当于多个变量的集合 数组名和索引 索引:编号从0开始,属于数值索引 注意:索引可支持使用自定义的格式,而不仅是数值格式,即为关联索引,bash4.0版本之后开始支持 bash的数组支持稀疏格式(索引不连续) 声明数组: declare -a ARRAY_NAME declare -A ARRAY_NAME 关联数组 注意:两者不可相互转换

【例42】数组,赋值。

csharp [root@localhost data]# title[0]=ceo [root@localhost data]# title[1]=coo [root@localhost data]# title[2]=cfo [root@localhost data]# echo ${title[0]} ceo [root@localhost data]# echo ${title[1]} coo [root@localhost data]# echo ${title[2]} cfo

【例43】数组,赋值。

csharp [root@localhost data]# read -a name zhao qian sun li [root@localhost data]# echo ${name[0]} zhao [root@localhost data]# echo ${name[1]} qian [root@localhost data]# echo ${name[2]} sun [root@localhost data]# echo ${name[3]} li

【例44】数组,赋值。

csharp [root@localhost data]# title=([0]=ceo [1]=coo [2]=cfo) [root@localhost data]# echo ${title[0]} ceo [root@localhost data]# echo ${title[1]} coo [root@localhost data]# echo ${title[2]} cfo [root@localhost data]# echo ${title[*]} ceo coo cfo [root@localhost data]# echo ${title[@]} ceo coo cfo [root@localhost data]# echo ${#title[@]} #显示个数 3 [root@localhost data]# echo ${title[*]} #显示全部 ceo coo cfo ceo coo cfo [root@localhost data]# title[${#title[@]}]=ofo #添加为新的数值 [root@localhost data]# echo ${title[*]} ceo coo cfo ofo

【例45】数组,赋值。

csharp [root@localhost data]# goods=(car plane ship) [root@localhost data]# echo ${goods[0]} car [root@localhost data]# echo ${goods[1]} plane [root@localhost data]# echo ${goods[2]} ship

【例46】数组,赋值。

csharp [root@localhost data]# alpha=({a..z}) [root@localhost data]# echo ${alpha[0]} a [root@localhost data]# echo ${alpha[25]} z

【例47】数组,赋值。

csharp [root@localhost data]# file=(*.sh) #赋值所有[*]以[.sh]结尾文件 [root@localhost data]# echo ${file[*]} #打印所有[*]以[.sh]结尾文件 9x9.sh arg.sh backup.sh batch_users.sh break2.sh break.sh busybox.sh chess1_while.sh chess2_while.sh chess3_while.sh chess6.sh chess7.sh chook_rabbit.sh continue2.sh continue.sh createuser_shift.sh creatuser.sh deny_while.sh disk_check_while.sh elsfk.sh exit.sh f1.sh fact.sh father.sh func1.sh func22.sh func2.sh func3.sh func4.sh hello.sh history.sh max_min_for.sh menu_select.sh menu.sh monitor_httpd_while.sh rename.sh scan_host.sh scan.sh score.sh sendfile.sh set.sh shengdanshu.sh son.sh star.sh sum_for.sh sum.sh sum_while.sh systeminfo.sh trap2.sh trap.sh triangleTree30.sh while_read1.sh while_read2.sh xing.sh yesorno.sh [root@localhost data]# echo ${file[1]} #打印第二个 arg.sh [root@localhost data]# echo ${file[10]} chess6.sh 【例48】关联数组,必须先声明才能使⽤。

csharp [root@localhost data]# student[a]='aaa' [root@localhost data]# student[b]='bbb' [root@localhost data]# student[c]='ccc' [root@localhost data]# echo ${student[a]} ccc [root@localhost data]# echo ${student[b]} ccc [root@localhost data]# echo ${student[c]} ccc [root@localhost data]# unset student #删除标准数组 [root@localhost data]# declare -A student #声明关联数组 [root@localhost data]# student[a]='aaa' [root@localhost data]# student[b]='bbb' [root@localhost data]# student[c]='ccc' [root@localhost data]# echo ${student[a]} aaa [root@localhost data]# echo ${student[b]} bbb [root@localhost data]# echo ${student[c]} ccc

【例49】声明。

```csharp [root@localhost data]# cat array.sh

!/bin/bash

declare -a ARR for((i=0;i<10;i++));do ARR[$i]=$RANDOM if [ $i -eq 0 ];then MAX=${ARR[$i]} MIN=${ARR[$i]} else [ ${ARR[$i]} -gt $MAX ] && MAX=${ARR[$i]} [ ${ARR[$i]} -lt $MIN ] && MIN=${ARR[$i]} fi done echo all random are ${ARR[@]} echo max=$MAX, min=$MIN [root@localhost data]# bash array.sh all random are 10879 4743 27808 32368 7586 3182 10149 18273 22520 26331 max=32368, min=3182 ```


1.9、字符串切⽚

csharp ${#var}:返回字符串变量var的长度 ${var:offset}:返回字符串变量var中从第offset个字符后(不包括第offset个字符)的字符开始,到最后的 部分,offset的取值在0 到 ${#var}-1 之间(bash4.2后,允许为负值) ${var:offset:number}:返回字符串变量var中从第offset个字符后(不包括第offset个字符)的字符开始, 长度为number的部分 ${var: -length}:取字符串的最右侧几个字符 注意:冒号后必须有一空白字符 ${var:offset:-length}:从最左侧跳过offset字符,一直向右取到距离最右侧lengh个字符之前的内容 ${var: -length:-offset}:先从最右侧向左取到length个字符开始,再向右取到距离最右侧offset个字符之 间的内容

【例50】字符串切⽚

csharp [root@localhost data]# echo {a..z} a b c d e f g h i j k l m n o p q r s t u v w x y z [root@localhost data]# echo {a..z}|tr -d ' ' abcdefghijklmnopqrstuvwxyz [root@localhost data]# str=`echo {a..z}|tr -d ' '` [root@localhost data]# echo ${#str} 26 [root@localhost data]# echo ${str:3} 从第三个开始 defghijklmnopqrstuvwxyz [root@localhost data]# echo ${str:3:4} 从第三个开始的4个 defg [root@localhost data]# echo ${str: -3} 倒数3个 xyz [root@localhost data]# echo ${str::4} 显示前四个 abcd [root@localhost data]# echo ${str::4 -3} 从第四个开始倒数三个 a


1.10、字符串处理

```csharp 基于模式取子串 ${var#word}:其中word可以是指定的任意字符 功能:自左而右,查找var变量所存储的字符串中,第一次出现的word, 删除字符串开头至第一次出现word字符串(含)之间的所有字符 ${var##word}:同上,贪婪模式,不同的是,删除的是字符串开头至最后一次由word指定的字符之间的所有内容 ${var%word}:其中word可以是指定的任意字符 功能:自右而左,查找var变量所存储的字符串中,第一次出现的word, 删除字符串最后一个字符向左至第一次出现word字符串(含)之间的所有字符 file="/var/log/messages" ${file%/}: /var/log ${var%%word*}:同上,只不过删除字符串最右侧的字符向左至最后一次出现word字符之间的所有字符

查找替换 ${var/pattern/substr}:查找var所表示的字符串中,第一次被pattern所匹配到的字符串,以substr替换之 ${var//pattern/substr}: 查找var所表示的字符串中,所有能被pattern所匹配到的字符串,以substr替换之 ${var/#pattern/substr}:查找var所表示的字符串中,行首被pattern所匹配到的字符串,以substr替换之 ${var/%pattern/substr}:查找var所表示的字符串中,行尾被pattern所匹配到的字符串,以substr替换之

查找并删除

${var/pattern}:删除var表示的字符串中第一次被pattern匹配到的字符串 ${var//pattern}:删除var表示的字符串中所有被pattern匹配到的字符串 ${var/#pattern}:删除var表示的字符串中所有以pattern为行首匹配到的字符串 ${var/%pattern}:删除var所表示的字符串中所有以pattern为行尾所匹配到的字符串

字符大小写转换

  1. ${var^^}:把var中的所有小写字母转换为大写
  2. ${var,,}:把var中的所有大写字母转换为小写

```

【例51】字符串处理,##贪婪模式。

csharp [root@localhost data]# getent passwd root root:x:0:0:root:/root:/bin/bash [root@localhost data]# line=`getent passwd root` [root@localhost data]# echo $line root:x:0:0:root:/root:/bin/bash [root@localhost data]# echo ${line#*root} :x:0:0:root:/root:/bin/bash [root@localhost data]# echo ${line##*root} :/bin/bash [root@localhost data]# echo ${line%root*} root:x:0:0:root:/ [root@localhost data]# echo ${line%%root*} (删除所有)

【例52】字符串处理,取值。

csharp [root@localhost data]# url=http://www.magedu.com:80 [root@localhost data]# echo ${url##*:} 80 [root@localhost data]# echo ${url%%:*} http


1.11、Shell变量⼀般是⽆类型的,但是bash Shell提供了declare和typeset两个命令⽤于指定变量的类型,两个命令是等价的

csharp declare [选项] 变量名 -r 声明或显示只读变量 -i 将变量定义为整型数 -a 将变量定义为数组 -A 将变量定义为关联数组 -f 显示已定义的所有函数名及其内容 -F 仅显示已定义的所有函数名 -x 声明或显示环境变量和函数 -l 声明变量为小写字母 declare –l var=UPPER -u 声明变量为大写字母 declare –u var=lower

【例53】声明变量,⼤⼩写问题。

csharp [root@localhost data]# declare -l aaa=HHH [root@localhost data]# echo $aaa hhh [root@localhost data]# declare -u bbb=ggg [root@localhost data]# echo $bbb GGG


1.12、eval命令

csharp eval命令将会首先扫描命令行进行所有的置换,然后再执行该命令。该命令适用于那些一次扫描无法实现其功能的变量.该命令对变量进行两次扫描

【例54】eval命令

csharp [root@localhost data]# n=10 [root@localhost data]# for i in {1..$n};do echo $i;done {1..10} [root@localhost data]# echo {1..$n} {1..10} [root@localhost data]# eval echo {1..$n} 1 2 3 4 5 6 7 8 9 10 [root@localhost data]# for i in `eval echo {1..$n}`;do echo $i;done 1 2 3 4 5 6 7 8 9 10

【例55】eval命令

csharp [root@localhost data]# title=ceo [root@localhost data]# ceo=mage [root@localhost data]# eval echo $title ceo [root@localhost data]# eval echo $$title 7699title [root@localhost data]# eval ${!title} bash: mage: command not found... [root@localhost data]# echo ${!title} mage


1.13、expect命令

```csharp expect 语法:expect [选项] [ -c cmds ] [ [ -[f|b] ] cmdfile ] [ args ]

选项 -c:从命令行执行expect脚本,默认expect是交互地执行的 示例:expect -c 'expect "\n" {send "pressed enter\n"} -d:可以输出输出调试信息 示例:expect -d ssh.exp

expect中相关命令

spawn 启动新的进程 send 用于向进程发送字符串 expect 从进程接收字符串 interact 允许用户交互 exp_continue 匹配多个字符串在执行动作后加此命令 ```

【例56】安装expect命令。

csharp 复制文件到另一台主机,交互式方式,需要输入yes和密码不方便。 [root@localhost data]# scp /etc/issue root@192.168.23.128:/data The authenticity of host '192.168.23.128 (192.168.23.128)' can't be established. ECDSA key fingerprint is SHA256:CpbUHLVMaIFixU/wVQODmdwYdlSkklNWagUjIMlpRPI. ECDSA key fingerprint is MD5:13:3f:da:8e:dd:ec:cd:25:32:b0:04:36:97:2b:d6:0c. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '192.168.23.128' (ECDSA) to the list of known hosts. root@192.168.23.128's password: issue 100% 35 10.3KB/s 00:00 [root@localhost data]# yum install expect -y 安装 ... Running transaction Installing : 1:tcl-8.5.13-8.el7.x86_64 1/2 Installing : expect-5.45-14.el7_1.x86_64 2/2 Verifying : 1:tcl-8.5.13-8.el7.x86_64 1/2 Verifying : expect-5.45-14.el7_1.x86_64 2/2 Installed: expect.x86_64 0:5.45-14.el7_1 Dependency Installed: tcl.x86_64 1:8.5.13-8.el7 Complete!

【例57】expect命令,⾮交互式命令,远程复制。

```csharp [root@localhost data]# vim expect1

!/bin/expect

spawn scp /etc/fstab root@192.168.23.128:/data expect { "yes/no" { send "yes\n";exp_continue } "password" { send "123456\n" } } expect eof

[root@localhost data]# chmod +x expect1

[root@localhost data]# ./expect1 spawn scp /etc/fstab root@192.168.23.128:/data root@192.168.23.128's password: fstab 100% 633 363.9KB/s 00:00

```

【例58】expect命令,⾮交互式命令,远程删除。

```csharp [root@localhost data]# vim expect2

!/bin/expect

spawn ssh 192.168.23.128 rm -f /data/fstab expect { "yes/no" { send "yes\n";exp_continue } "password" { send "123456\n" } } expect eof

[root@localhost data]# chmod +x expect2

[root@localhost data]# ./expect2 spawn ssh 192.168.23.128 rm -f /data/fstab root@192.168.23.128's password: ```

【例59】expect命令,⾮交互式命令,远程登录。

```csharp [root@localhost data]# vim expect3

!/usr/bin/expect

IP地址

set ip 192.168.23.128

用户名

set user root

密码

set password 123456 set timeout 10 spawn ssh $user@$ip expect { "yes/no" { send "yes\n";exp_continue } "password" { send "$password\n" } } interact [root@localhost data]# chmod +x expect3 [root@localhost data]# ./expect3 spawn ssh root@192.168.23.128 root@192.168.23.128's password: Last login: Mon May 20 17:22:31 2019 from 192.168.23.1

退出,远程登录的主机: [root@localhost data]# exit logout Connection to 192.168.23.128 closed. ``` 【例60】expect命令,⾮交互式命令,以变量⽅式远程登录。

```csharp [root@localhost data]# vim expect4

!/usr/bin/expect

set ip [lindex $argv 0] set user [lindex $argv 1] set password [lindex $argv 2] spawn ssh $user@$ip expect { "yes/no" { send "yes\n";exp_continue } "password" { send "$password\n" } } interact

[root@localhost data]# chmod +x expect4

[root@localhost data]# ./expect4 192.168.23.128 root 123456 spawn ssh root@192.168.23.128 root@192.168.23.128's password: Last failed login: Mon May 20 17:46:15 CST 2019 from 192.168.23.118 on ssh:notty There was 1 failed login attempt since the last successful login. Last login: Mon May 20 17:41:05 2019 from 192.168.23.118

[root@localhost ~]# exit logout Connection to 192.168.23.128 closed. ```

【例61】expect命令,⾮交互式命令,以变量⽅式远程登录,添加⽤户。

```csharp [root@localhost data]# vim expect5

!/usr/bin/expect

set ip [lindex $argv 0] set user [lindex $argv 1] set password [lindex $argv 2] set timeout 10 spawn ssh $user@$ip expect { "yes/no" { send "yes\n";exp_continue } "password" { send "$password\n" } } expect "]#" { send "useradd haha\n" } expect "]#" { send "echo magedu |passwd --stdin haha\n" } send "exit\n" expect eof

[root@localhost data]# chmod +x expect5

[root@localhost data]# ./expect5 192.168.23.128 root 123456 spawn ssh root@192.168.23.128 root@192.168.23.128's password: Last login: Mon May 20 17:46:26 2019 from 192.168.23.118 [root@localhost ~]# useradd haha [root@localhost ~]# echo magedu |passwd --stdin haha Changing password for user haha. passwd: all authentication tokens updated successfully. [root@localhost ~]# exit logout Connection to 192.168.23.128 closed. ```

【例62】以shell脚本模式,执⾏expect命令,⾮交互式命令,以变量⽅式远程登录,添加⽤户。

```csharp [root@localhost data]# vim expect6.sh

!/bin/bash

ip=$1 user=$2 password=$3 expect <

[root@localhost data]# chmod +x expect6.sh

[root@localhost data]# ./expect6.sh 192.168.23.128 root 123456 spawn ssh root@192.168.23.128 root@192.168.23.128's password: Last login: Mon May 20 17:52:13 2019 from 192.168.23.118 [root@localhost ~]# useradd hehe useradd: user 'hehe' already exists [root@localhost ~]# echo magedu |passwd --stdin hehe Changing password for user hehe. passwd: all authentication tokens updated successfully. [root@localhost ~]# exit logout Connection to 192.168.23.128 closed. ```

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/304548
推荐阅读
相关标签
  

闽ICP备14008679号