一、脚本相关工具
①信号捕捉 trap
[root@cent7 ~]$ trap -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
trap ‘触发指令’ 信号 :进程收到系统发出的指定信号后,将执行自定义指令,而不会执行原操作
trap ‘ ‘ 信号 :忽略信号的操作
trap ‘-‘ 信号 :恢复原信号的操作
trap -p :列出自定义信号操作
trap finish EXIT :当脚本退出时,执行finish函数
#!/bin/bash
trap 'echo "Press ctrl+c or ctrl+\\"' int quit
trap -p
for((i=0;i<=10;i++))
do
sleep 1
echo $i
done
trap '' int (#忽略信号的操作)
trap -p
for((i=11;i<=20;i++))
do
sleep 1
echo $i
done
trap '-' int (#恢复原信号的操作)
trap -p
for((i=21;i<=30;i++))
do
sleep 1
echo $i
done
#当脚本退出时,执行finish函数
[root@centos8 ~]#cat trap_exit.sh
#!/bin/bash
finish(){
echo finish| tee -a /root/finish.log
}
trap finish exit
while true ;do
echo running
sleep 1
done
②创建临时文件mktemp
mktemp [OPTION]... [TEMPLATE]
用于创建并显示临时文件,可避免冲突 (TEMPLATE: filenameXXX,X至少要出现三个)
-d 创建临时目录
-p DIR或—tmpdir=DIR 指明临时文件所存放目录位置
[root@centos8 data]#mktemp
/tmp/tmp.UogGCumh8C
mktemp /tmp/testXXX
tmpdir=`mktemp -d /tmp/testdirXXX`
mktemp --tmpdir=/testdir testXXXXXX
[root@centos8 ~]#cat /data/scripts/rm.sh
#!/bin/bash
DIR=`mktemp -d /tmp/trash-$(date +%F_%H-%M-%S)XXXXXX`
mv $* $DIR
echo $* is move to $DIR
[root@centos8 ~]#alias rm=/data/scripts/rm.sh
③安装复制文件 install
install 功能相当于 cp,mkdir, chmod,chown,chgrp 等相关工具的集合
install -m 700 -o wang -g admins srcfile desfile
install -m 770 -d /testdir/installdir
[root@centos8 ~]#install -m 600 -o wang -g bin anaconda-ks.cfg /data/a.cfg
[root@centos8 ~]#ll /data/a.cfg
-rw------- 1 wang bin 1550 Jun 23 20:28 /data/a.cfg
[root@centos8 ~]#install -m 700 -o mage -g daemon -d /data/testdir
[root@centos8 ~]#ll -d /data/testdir
drwx------ 2 mage daemon 6 Apr 29 15:09 /data/testdir
④交互式转化批处理工具expect
expect 是由Don Libes基于 Tcl( Tool Command Language )语言开发的,主要应用于自动化交互式操作的场景,借助 expect 处理交互的命令,可以将交互过程如:ssh登录,ftp登录等写在一个脚本上,使之自动化完成。尤其适用于需要对多台服务器执行相同操作的环境中,可以大大提高系统管理人员的工作效率expect [选项] [** -c** cmds ] [ [ -[f|b] ] cmdfile ] [ **args** ]
-c:从命令行执行expect脚本,默认expect是交互地执行的
-d:可以输出输出调试信息
expect -c 'expect "\n" {send "pressed enter\n"}'
expect -d ssh.exp
单一分支模式语法:
[root@centos8 test]#expect
expect1.1> expect "hi" {send "You said hi\n"} (#匹配到hi后,会输出“you said hi”,并换行)
hahahixixi
You said hi
多分支模式语法:
[root@centos8 ~]#expect
expect1.1> expect "hi" { send "You said hi\n" } "hehe" { send "Hehe yourself\n"
} "bye" { send "Good bye\n" }
hehe
Hehe yourself
bye
Good bye
hi
You said hi
#匹配hi,hello,bye任意字符串时,执行相应输出。等同如下:
expect {
"hi" { send "You said hi\n"}
"hehe" { send "Hehe yourself\n"}
"bye" { send " Good bye\n"}
}
[root@centos8 ~]#expect
expect1.1> expect {
+> "hi" { send "You said hi\n"}
+> "hehe" { send "Hehe yourself\n"}
+> "bye" { send " Good bye\n"}
+> }
bye
Good bye
expect1.2>
相关命令
spawn 启动新的进程
expect 从进程接收字符串
send 用于向进程发送字符串
interact 允许用户交互
exp_continue 匹配多个字符串在执行动作后加此命令
#!/usr/bin/expect (这里用的是expect语法)
spawn scp /etc/fstab 10.0.0.7:/data
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send "magedu\n" }
}
expect eof
#!/usr/bin/expect
spawn ssh 10.0.0.7
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send "magedu\n" }
}
interact
expect变量
#!/usr/bin/expect
set ip 10.0.0.7
set user root
set password magedu
set timeout 10
spawn ssh $user@$ip
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send "$password\n" }
}
interact
expect位置参数
[root@centos8 ~]#cat 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@centos8 ~]#./expect4 10.0.0.7 root magedu
spawn ssh root@10.0.0.7
root@10.0.0.7's password:
Last login: Wed Apr 29 15:34:14 2020 from 10.0.0.8
[root@centos7 ~]#exit
logout
Connection to 10.0.0.7 closed.
expect执行多个命令
#!/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
#./ssh4.exp 10.0.0.7 root magedu
范例7: shell脚本利用循环调用expect在CentOS和Ubuntu上批量创建用户
#!/bin/bash
NET=10.0.0
user=root
password=magedu
for ID in 6 7 111;do
ip=$NET.$ID
expect <<EOF
set timeout 20
spawn ssh $user@$ip
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send "$password\n" }
}
expect "#" { send "useradd test\n" }
expect "#" { send "exit\n" }
expect eof
EOF
done
shell脚本调用expect
[root@centos8 scripts]#cat expect8.sh
#!/bin/bash
NET=10.0.0
user=root
password=centos
for ID in 6 7;do
ip=$NET.$ID
expect <<EOF
set timeout 20
spawn ssh $user@$ip
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send "$password\n" }
}
expect "#" { send "sed -i 's/^SELINUX=enforcing/SELINUX=disabled/'
/etc/selinux/config\n" }
expect "#" { send "setenforce 0\n" }
expect "#" { send "exit\n" }
expect eof
EOF
done
二、数组 array
变量:存储单个元素的内存空间
数组:存储多个元素的连续的内存空间,相当于多个变量的集合
数组名和索引(下标)
- 索引的编号从0开始,属于数值索引
- 索引可支持使用自定义的格式,而不仅是数值格式,即为关联索引,bash4.0版本之后开始支持
- bash的数组支持稀疏格式(索引不连续)
普通数组可以不事先声明,直接使用declare -a ARRAY_NAME
#关联数组必须先声明,再使用declare -A ARRAY_NAME
#显示所有数组:declare -a
# 删除数组 : unset ARRAY[INDEX]
( 删除数组中的某元素,会导致稀疏格式 )
[root@centos8 ~]#unset title
[root@centos8 ~]#echo ${title[*]}
数组赋值
(1) 一次只赋值一个元素: ARRAY_NAME[INDEX]=VALUE
weekdays[0]="Sunday"
weekdays[4]="Thursday"
(2) 一次赋值全部元素: ARRAY_NAME=("VAL1" "VAL2" "VAL3" ...)
title=("ceo" "coo" "cto")
num=({0..10})
alpha=({a..g})
file=( *.sh )
(3) 只赋值特定元素: ARRAY_NAME=([0]="VAL1" [3]="VAL2" ...)
(4) 交互式数组值对赋值:read -a ARRAY
引用数组
引用数组元素:${ARRAY_NAME[INDEX]}
(#如果省略[INDEX]表示引用下标为0的元素)
引用数组所有元素:${ARRAY_NAME[*]}
、${ARRAY_NAME[@]}
数组的长度,即数组中元素的个数 :${#ARRAY_NAME[*]}
、${#ARRAY_NAME[@]}
[root@centos8 ~]#declare -a title=([0]="ceo" [1]="coo" [2]="cto")
[root@centos8 ~]#echo ${title[1]}
coo
[root@centos8 ~]#echo ${title}
ceo
[root@centos8 ~]#echo ${title[2]}
cto
[root@centos8 ~]#echo ${title[@]}
ceo coo cto
[root@centos8 ~]#echo ${title[*]}
ceo coo cto
[root@centos8 ~]#echo ${#title[*]}
3
数组数据处理
[root@centos8 ~]#num=({0..10})
[root@centos8 ~]#echo ${num[*]:2:3}
2 3 4
[root@centos8 ~]#echo ${num[*]:6}
6 7 8 9 10
[root@centos8 ~]#num[${#num[@]}]=11
[root@centos8 ~]#echo ${#num[@]}
12
[root@centos8 ~]#echo ${num[@]}
0 1 2 3 4 5 6 7 8 9 10 11
关联数组
[root@centos8 ~]#declare -A student
[root@centos8 ~]#student[name1]=lijun
[root@centos8 ~]#student[name2]=ziqing
[root@centos8 ~]#student[age1]=18
[root@centos8 ~]#student[age2]=16
[root@centos8 ~]#student[gender1]=m
[root@centos8 ~]#student[city1]=nanjing
[root@centos8 ~]#student[gender2]=f
[root@centos8 ~]#student[city2]=anhui
[root@centos8 ~]#student[gender2]=m
[root@centos8 ~]#student[name50]=alice
[root@centos8 ~]#student[name3]=tom
[root@centos8 ~]#for i in {1..50};do echo student[name$i]=${student[name$i]};
done
范例:生成10个随机数保存于数组中,并找出其最大值和最小值
#!/bin/bash
declare -i min max
declare -a nums
for ((i=0;i<10;i++));do
nums[$i]=$RANDOM
[ $i -eq 0 ] && min=${nums[0]} && max=${nums[0]}&& continue
[ ${nums[$i]} -gt $max ] && max=${nums[$i]} && continue
[ ${nums[$i]} -lt $min ] && min=${nums[$i]}
done
echo "All numbers are ${nums[*]}"
echo Max is $max
echo Min is $min
范例:编写脚本,定义一个数组,数组中的元素对应的值是/var/log目录下所有以.log结尾的文件;统计出其下标为偶数的文件中行数之和
#!/bin/bash
declare -a files
files=(/var/log/*.log)
declare -i lines=0
for i in $(seq 0 $[${#files[*]}-1]); do
if [ $[$i%2] -eq 0 ];then
let lines+=$(wc -l ${files[$i]} | cut -d' ' -f1)
fi
done
echo "Lines: $lines"
练习
- 输入若干个数值存入数组中,采用冒泡算法进行升序或降序排序
2. 将下图所示,实现转置矩阵 matrix.sh
1 2 3 1 4 7
4 5 6 ===> 2 5 8
7 8 9 3 6 9
3. 打印杨辉三角形三、字符串处理
字符串切片
基于偏移量取字符串
基于模式取子串#返回字符串变量var的长度 ${#var} #返回字符串变量var中从第offset个字符后(不包括第offset个字符)的字符开始,到最后的部分,offset的取值在0 到 ${#var}-1 之间(bash4.2后,允许为负值) ${var:offset} #返回字符串变量var中从第offset个字符后(不包括第offset个字符)的字符开始,长度为number的部分 ${var:offset:number} #取字符串的最右侧几个字符,取字符串的最右侧几个字符, 注意:冒号后必须有一空白字符 ${var: -length} #从最左侧跳过offset字符,一直向右取到距离最右侧lengh个字符之前的内容,即:掐头去尾 ${var:offset:-length} #先从最右侧向左取到length个字符开始,再向右取到距离最右侧offset个字符之间的内容,注意:-length前空格 ${var: -length:-offset}
```bash其中word可以是指定的任意字符,自左而右,查找var变量所存储的字符串中,第一次出现的word, 删除字符串开头至第一次出现word字符串(含)之间的所有字符(删左留右)
${var#*word}:同上,贪婪模式,不同的是,删除的是字符串开头至最后一次由word指定的字符之间的所有内容
${var##*word}:
[root@centos8 ~]#file=”var/log/messages” [root@centos8 ~]#echo ${file#/} log/messages [root@centos8 ~]#echo ${file##/} messages
```bash
#其中word可以是指定的任意字符,功能:自右而左,查找var变量所存储的字符串中,第一次出现的word, 删除字符串最后一个字符向左(向前)至第一次出现word字符串(含)之间的所有字符(删右留左)
${var%word*}
#同上,只不过删除字符串最右侧的字符向左至最后一次出现word字符之间的所有字符
${var%%word*}
[root@centos8 ~]#file="var/log/messages"
[root@centos8 ~]#echo ${file%/*}
var/log
[root@centos8 ~]#echo ${file%%/*}
var
[root@centos8 ~]#url=http://www.magedu.com:8080
[root@centos8 ~]#echo ${url##*:}
8080
[root@centos8 ~]#echo ${url%%:*}
http
查找替换
#查找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}
字符大小写转换
#把var中的所有小写字母转换为大写
${var^^}
#把var中的所有大写字母转换为小写
${var,,}
四、高级变量
高级变量赋值
[root@centos8 ~]#title=ceo
[root@centos8 ~]#name=${title-mage}
[root@centos8 ~]#echo $name
ceo
[root@centos8 ~]#title=
[root@centos8 ~]#name=${title-mage}
[root@centos8 ~]#echo $name
[root@centos8 ~]#unset title
[root@centos8 ~]#name=${title-mage}
[root@centos8 ~]#echo $name
mage
[root@centos8 ~]#title=ceo
[root@centos8 ~]#name=${title:-mage}
[root@centos8 ~]#echo $name
ceo
[root@centos8 ~]#title=
[root@centos8 ~]#name=${title:-mage}
[root@centos8 ~]#echo $name
mage
[root@centos8 ~]#unset title
[root@centos8 ~]#name=${title:-mage}
[root@centos8 ~]#echo $name
mage
★Shell变量一般是无类型的,但是bash Shell提供了declare和typeset两个命令用于指定变量的类型,两个命令是等价的declare [选项] 变量名
-r 声明或显示只读变量
-i 将变量定义为整型数
-a 将变量定义为数组
-A 将变量定义为关联数组
-f 显示已定义的所有函数名及其内容
-F 仅显示已定义的所有函数名
-x 声明或显示环境变量和函数,相当于export
-l 声明变量为小写字母 declare -l var=UPPER
-u 声明变量为大写字母 declare -u var=lower
间接变量引用— eval
- eval命令将会首先扫描命令行进行所有的置换,然后再执行该命令。该命令适用于那些一次扫描无法实现其功能的变量,该命令对变量进行两次扫描 ```bash [root@centos8 ~]# CMD=whoami [root@centos8 ~]# echo $CMD whoami [root@centos8 ~]# eval $CMD root
[root@centos8 ~]# n=10
[root@centos8 ~]# echo {0..$n}
{0..10}
[root@centos8 ~]# eval echo {0..$n}
0 1 2 3 4 5 6 7 8 9 10
[root@centos8 ~]#i=1 [root@centos8 ~]#j=a [root@centos8 ~]#$j$i=hello -bash: a1=hello: command not found [root@centos8 ~]#eval $j$i=hello [root@centos8 ~]#echo $j$i a1 [root@centos8 ~]#echo $a1 hello
![image.png](https://cdn.nlark.com/yuque/0/2021/png/12467445/1633789801702-5dd162e9-43c4-4d32-879a-10b6b3a8c326.png#height=358&id=jIH4g&margin=%5Bobject%20Object%5D&name=image.png&originHeight=715&originWidth=1834&originalType=binary&ratio=1&size=432403&status=done&style=none&width=917)
2. 如果第一个变量的值是第二个变量的名字,从第一个变量引用第二个变量的值就称为间接变量引用 variable1的值是ariable2,而variable2又是变量名,variable2的值为value,间接变量引用是指通过 variable1获得变量值value的行为
```bash
variable1=variable2
variable2=value
bash Shell提供了两种格式实现间接变量引用
#方法1
变量赋值:eval tempvar=\$$variable1
显示值:eval echo \$$variable1
#方法2
变量赋值:tempvar=${!variable1}
显示值:echo ${!variable1}
[root@centos8 ~]#ceo=name
[root@centos8 ~]#name=mage
[root@centos8 ~]#echo $ceo
name
[root@centos8 ~]#echo $$ceo
33722ceo
[root@centos8 ~]#echo $$ ($$有特殊含义,表示当前进程编号)
33722
[root@centos8 ~]#echo \$$ceo
$name
[root@centos8 ~]#eval echo \$$ceo
mage
[root@centos8 ~]#eval tmp=\$$ceo
[root@centos8 ~]#echo $tmp
mage
[root@centos8 ~]#echo ${!ceo}
mage