马哥29-脚本进阶
程序员文章站
2024-01-29 17:56:28
...
文章目录
信号捕捉trap
创建1.txt 2.txt 内容分别为12345和abcde,将其合并且显示效果为1a2b3c4d5e
[aaa@qq.com scripts-exercise]# cat 1.txt
1
2
3
4
5
[aaa@qq.com scripts-exercise]# cat 2.txt
a
b
c
d
e
[aaa@qq.com scripts-exercise]# paste 1.txt 2.txt | tr '\t' '\n'
1
a
2
b
3
c
4
d
5
e
[aaa@qq.com scripts-exercise]# LINE=`cat 1.txt|wc -l`
[aaa@qq.com scripts-exercise]# for i in `seq 1 $LINE`;do INSERT=`sed -n "${i}p" 2.txt`;sed -i "$[2*i-1] a $INSERT" 1.txt ; done
[aaa@qq.com scripts-exercise]# cat 1.txt
1
a
2
b
3
c
4
d
5
e
trap 在shell中称之为陷阱,类似于mysql的触发器
trap '触发指令' 信号
进程收到系统发出的指定信号后,将执行自定义指令,而不会执行原操作
trap '' 信号
忽略信号的操作
trap '-' 信号
恢复原信号的操作
trap -p
列出自定义信号操作
trap finish EXIT
当脚本退出时,执行finish函数
注:trap无法捕获kill -9 信号
设置循环1到10,捕获在此期间的组合键ctrl+c,显示press ctrl+c
#!/bin/bash
trap 'echo press ctrl+c' int
trap -p
for ((i=0;i<10;i++)) ; do
echo $i
sleep 1
done
在此过程中我们按ctrl+c成功出发陷阱
[aaa@qq.com scripts-exercise]# bash trap.sh
trap -- 'echo press ctrl+c' SIGINT
0
1
2
^Cpress ctrl+c
3
^Cpress ctrl+c
4
^Cpress ctrl+c
5
6
7
^Cpress ctrl+c
8
9
在此前基础上设置循环10到20,并且忽略ctrl+c的操作
#!/bin/bash
trap 'echo press ctrl+c' int
trap -p
for ((i=0;i<10;i++)) ; do
echo $i
sleep 1
done
trap '' 2
trap -p
for ((i=10;i<20;i++));do
echo $i
sleep 1
done
前10秒触发了组合键的信号,但是10到20期间系统忽略了我们的组合键ctrl+c的信号
[aaa@qq.com scripts-exercise]# bash trap.sh
trap -- 'echo press ctrl+c' SIGINT
0
1
^Cpress ctrl+c
2
^Cpress ctrl+c
3
^Cpress ctrl+c
4
^Cpress ctrl+c
5
6
7
8
9
trap -- '' SIGINT
10
^C11
^C12
^C13
^C14
^C15
16
17
18
19
设置20到30的循环,恢复我们之前忽略的ctrl+c信号的操作
#!/bin/bash
trap 'echo press ctrl+c' int
trap -p
for ((i=0;i<10;i++)) ; do
echo $i
sleep 1
done
trap '' 2
trap -p
for ((i=10;i<20;i++));do
echo $i
sleep 1
done
trap '-' sigint
trap -p
for ((i=20;i<30;i++));do
echo $i
sleep 1
done
显示在20到30循环期间,ctrl+c组合键起作用了,并且成功退出循环
[aaa@qq.com scripts-exercise]# bash trap.sh
trap -- 'echo press ctrl+c' SIGINT
0
1
^Cpress ctrl+c
2
^Cpress ctrl+c
3
^Cpress ctrl+c
4
^Cpress ctrl+c
5
^Cpress ctrl+c
6
7
8
9
trap -- '' SIGINT
10
^C11
^C12
^C13
^C14
^C15
^C16
17
18
19
20
21
22
23
^C
设置while死循环,并且定义函数为显示excute finish,在trap退出是显示函数
#!/bin/bash
finish(){
echo excute finish
}
trap finish exit
i=0
while true ; do
echo $i
let i++
sleep 1
done
我们使用组合键ctrl+c退出脚本,成功打印了excute finish
[aaa@qq.com scripts-exercise]# bash trap_finish.sh
0
1
2
3
4
5
^Cexcute finish
数组
变量:存储单个元素的内存空间(如:mage、wang、zhang、tom)
索引:又称下标,一般使用数字表示,从0开始标识(如:0、1、2、3、)
数组:存储多个元素的连续的内存空间,相当于多个变量的集合(如:name)
注意:索引可支持使用自定义的格式,比如说字母字符,而不仅是数值格式,即为关联索引
bash的数组支持稀疏格式(索引不连续稀):文件的实际大小和磁盘上存储的真实大小不同
又称空洞文件(如下图)
申明数组 declare -a ARRAY_NAME 可以不申明,但建议申明
关联数组必须先申明再使用 declare -A ARRAY_NAME 关联数组
显示所有数组 declare -a
数组演示
创建数组title
[aaa@qq.com scripts-exercise]# title[0]=ceo
[aaa@qq.com scripts-exercise]# title[1]=coo
[aaa@qq.com scripts-exercise]# title[2]=cto
[aaa@qq.com scripts-exercise]# echo ${title[0]}
ceo
[aaa@qq.com scripts-exercise]# echo ${title[1]}
coo
[aaa@qq.com scripts-exercise]# echo ${title[2]}
cto
删除title数组中的索引2
[aaa@qq.com scripts-exercise]# unset title[2]
[aaa@qq.comcalhost scripts-exercise]# echo ${title[0]}
ceo
[aaa@qq.com scripts-exercise]# echo ${title[2]}
[aaa@qq.com scripts-exercise]# echo ${title[1]}
coo
给数组批量添加元素
[aaa@qq.com scripts-exercise]# name=(mage zhang wang sun)
[aaa@qq.com scripts-exercise]# echo ${name[0]}
mage
[aaa@qq.com scripts-exercise]# echo ${name[1]}
zhang
[aaa@qq.com scripts-exercise]# echo ${name[2]}
wang
[aaa@qq.com scripts-exercise]# echo ${name[3]}
sun
交互式创建数组,添加元素
[aaa@qq.com scripts-exercise]# read -a student
liu guan zhang
[aaa@qq.com scripts-exercise]# echo ${student[0]}
liu
[aaa@qq.com scripts-exercise]# echo ${student[1]}
guan
[aaa@qq.com scripts-exercise]# echo ${student[2]}
zhang
关联数组的下标是没有规律的
[aaa@qq.com scripts-exercise]# declare -A teacher
[aaa@qq.com scripts-exercise]# teacher[0]=mage
[aaa@qq.com scripts-exercise]# teacher[1]=xu
[aaa@qq.com scripts-exercise]# teacher[2]=wang
[aaa@qq.com scripts-exercise]# echo ${teacher[0]}
mage
[aaa@qq.com scripts-exercise]# echo ${teacher[1]}
xu
[aaa@qq.com scripts-exercise]# echo ${teacher[2]}
wang
字符串切片
1.前提:元素字符串起始偏移量编号为0,number代表结束位置时,截取内容不包括结束位对应的字符。
2.offset 元素字符串偏移量编号 Python中的起始位置
offset:为正数时代表从左向右截取,为负数时代表从右向左截取。
3.number 要截取元素字符串的长度 Python中的结束位置
number:为正数时代表截取长度,为负数则代表结束位置,当number为代表结束位置时截取内容不包括第m位
4.offset为正数时,从左向右截取:${ARRAY[@]:n:m},n为起终位置,m为截取长度
[aaa@qq.com scripts-exercise]# num=({1..10})
[aaa@qq.com scripts-exercise]# echo ${num[@]}
1 2 3 4 5 6 7 8 9 10
[aaa@qq.com scripts-exercise]# echo ${num[@]:2:3}
3 4 5
[aaa@qq.com scripts-exercise]# echo ${num[@]:2}
3 4 5 6 7 8 9 10
[aaa@qq.com scripts-exercise]# echo ${num[@]:-2}
1 2 3 4 5 6 7 8 9 10
[aaa@qq.com scripts-exercise]# echo ${num[@]: -2}
9 10
生成10个随机数保存于数组中,并找出其最大值最小值
#!/bin/bash
#生成10个随机数保存于数组中,并找出其最大值最小值
for((i=0;i<10;i++));do
NUM[$i]=$RANDOM
if [ $i -eq 0 ] ; then
MAX=${NUM[$i]}
MIN=$MAX
else
[ ${NUM[$i]} -gt $MAX ] && MAX=${NUM[$i]}
[ ${NUM[$i]} -lt $MIN ] && MIN=${MUN[$i]}
fi
done
echo ${MUN[*]}
echo MAX=$MIN
[aaa@qq.com scripts-exercise]# bash title_NUM.sh
318 7226 21905 21268 32217 15934 30686 5319 16922 15688
MAX=32217 MIN=318
字符串处理
[aaa@qq.com scripts-exercise]# string=`getent passwd root`
[aaa@qq.com scripts-exercise]# echo $string
root:x:0:0:root:/root:/bin/bash
#显示字符个数
[aaa@qq.com scripts-exercise]# echo ${#string}
31
[aaa@qq.com scripts-exercise]# str2="mage-linux"
#显示字符个数
[aaa@qq.com scripts-exercise]# echo ${#str2}
10
#左--->右,从前往后跳过五个字符取至结尾
[aaa@qq.com scripts-exercise]# echo ${str2:5}
linux
#左--->右,从前往后跳过四个字符取一个字符
[aaa@qq.com scripts-exercise]# echo ${str2:4:1}
-
#右--->左,取后五个字符
[aaa@qq.com scripts-exercise]# echo ${str2: -5}
linux
#前---><---后,从左往右取零个字符,从右往左跳过六个字符
[aaa@qq.com scripts-exercise]# echo ${str2: : -6}
mage
#左<---右,从右往左取五个字符,再从右往左跳过两个字符
[aaa@qq.com scripts-exercise]# echo ${str2: -5: -2}
lin
#左---><---右,从左往右跳过四个字符,从右往左跳过五个字符
[aaa@qq.com scripts-exercise]# echo ${str2:4: -5}
-
给数组赋值命令
[aaa@qq.com scripts-exercise]# string=`getent passwd root`
[aaa@qq.com scripts-exercise]# echo $string
root:x:0:0:root:/root:/bin/bash
#在数组前加#号,显示字符个数
[aaa@qq.com scripts-exercise]# echo ${#string}
31
#左--->右,找到字符串里的第一个:,删除包含:在内之前所有字符
[aaa@qq.com scripts-exercise]# echo ${string#*:}
x:0:0:root:/root:/bin/bash
#左--->右,贪婪模式,找到字符串里最后一个:,删除包含:在内之前所有的字符
[aaa@qq.com scripts-exercise]# echo ${string##*:}
/bin/bash
[aaa@qq.com scripts-exercise]# url="http://www.magedu.com:80"
[aaa@qq.com scripts-exercise]# echo ${url}
http://www.magedu.com:80
#左<---右,找到字符串里第一个:,删除包含:在内的所有字符
[aaa@qq.com scripts-exercise]# echo ${url%:*}
http://www.magedu.com
#左<---右,贪婪模式,找到字符串里最后一个:,删除包含:在内的所有字符
[aaa@qq.com scripts-exercise]# echo ${url%%:*}
http
替换数组中的字符
[aaa@qq.com scripts-exercise]# echo ${string}
root:x:0:0:root:/root:/bin/bash
#查找所有字符串,把第一次匹配到的root替换成admin
[aaa@qq.com scripts-exercise]# echo ${string/root/admin}
admin:x:0:0:root:/root:/bin/bash
#贪婪模式,查找所有字符串,把所有匹配到的root替换成admin
[aaa@qq.com scripts-exercise]# echo ${string//root/admin}
admin:x:0:0:admin:/admin:/bin/bash
#查找所有字符串,行首匹配到的root替换成admin
[aaa@qq.com scripts-exercise]# echo ${string/#root/admin}
admin:x:0:0:root:/root:/bin/bash
#查找所有字符串,行尾匹配到的root替换成admin,行尾并没有符合的字符,所以没变化
[aaa@qq.com scripts-exercise]# echo ${string/%root/admin}
root:x:0:0:root:/root:/bin/bash
#把string中的所有小写字母转换为大写
[aaa@qq.com scripts-exercise]# echo ${string^^}
ROOT:X:0:0:ROOT:/ROOT:/BIN/BASH
#把string中的所有大写字母转换为小写
[aaa@qq.com scripts-exercise]# echo ${string,,}
root:x:0:0:root:/root:/bin/bash
变量赋值
没有配置表示没这个变量
空字符串表示变量存在但是没有赋值
高级变量用法
declare [选项] 变量名
-r 声明或显示只读变量
-i 将变量定义为整型数
-a 将变量定义为数组
-A 将变量定义为关联数组
-f 显示已定义的所有函数名及其内容
-F 仅显示已定义的所有函数名
-x 声明或显示环境变量和函数
-l 声明变量为小写字母 declare –l var=UPPER
-u 声明变量为大写字母 declare –u var=lower
#申明变量为小写字母
[aaa@qq.com scripts-exercise]# declare -l name="MAGEDU"
[aaa@qq.com scripts-exercise]# echo $name
magedu
#申明变量为大写字母
[aaa@qq.com scripts-exercise]# declare -u name="mege"
[aaa@qq.com scripts-exercise]# echo $name
MEGE
eval命令
eval命令将会首先扫描命令行进行所有的置换,然后再执行该命令。
该命令适用于那些一次扫描无法实现其功能的变量.该命令对变量进行两次扫描
#我们想要实现的效果
[aaa@qq.com scripts-exercise]# n=10 ; echo {1..10}
1 2 3 4 5 6 7 8 9 10
#无法直接引用变量
[aaa@qq.com scripts-exercise]# n=10 ; echo {1..$n}
{1..10}
#使用eval可达到我们的预期,等于先替换了变量,再执行echo {1..10}
[aaa@qq.com scripts-exercise]# n=10 ; eval echo {1..$n}
1 2 3 4 5 6 7 8 9 10
[aaa@qq.com scripts-exercise]# n=10 ; for i in `eval echo {1..$n}` ; do echo $i ; done
1
2
3
4
5
6
7
8
9
10
间接变量引用
[aaa@qq.com scripts-exercise]# title=name
[aaa@qq.com scripts-exercise]# name=ceo
[aaa@qq.com scripts-exercise]# echo \$$title
$name
#通过eval间接引用变量$name
[aaa@qq.com scripts-exercise]# eval echo \$$title
ceo
[aaa@qq.com scripts-exercise]# echo ${title}
name
#除了ecal,用这种方法也可以实现
[aaa@qq.com scripts-exercise]# echo ${!title}
ceo
mktemp创建临时文件
mktemp命令:创建并显示临时文件,可避免冲突
mktemp [OPTION]... [TEMPLATE]
TEMPLATE: filenameXXX
X至少要出现三个
OPTION:
-d: 创建临时目录
-p DIR或--tmpdir=DIR:指明临时文件所存放目录位置
[aaa@qq.com scripts-exercise]# mktemp sunXXX #生成sun开头后面三个随机数的文件
sunanF
[aaa@qq.com scripts-exercise]# ls
1.txt 2.txt sunanF title_NUM.sh trap_finish.sh trap.sh
#生成wang开头后面三个随机数的文件,并将文件名赋值给file
[aaa@qq.com scripts-exercise]# file=`mktemp wangXXX`
[aaa@qq.com scripts-exercise]# echo $file
wang0hz
[aaa@qq.com scripts-exercise]# ls
1.txt 2.txt sunanF title_NUM.sh trap_finish.sh trap.sh wang0hz
#加-d生成mage开头后面三个随机数的文件夹
[aaa@qq.com scripts-exercise]# mktemp -d mageXXX
magelvT
[aaa@qq.com scripts-exercise]# ls
1.txt 2.txt magelvT sunanF title_NUM.sh trap_finish.sh trap.sh wang0hz
[aaa@qq.com scripts-exercise]# mktemp -p /data/scripts-exercise/ 111XXX
/data/scripts-exercise/111h2M
[aaa@qq.com scripts-exercise]# ls /data/scripts-exercise/
111h2M 1.txt 2.txt magelvT sunanF title_NUM.sh trap_finish.sh trap.sh wang0hz
[aaa@qq.com scripts-exercise]# mktemp /data/scripts-exercise/222XXX
/data/scripts-exercise/222czV
[aaa@qq.com scripts-exercise]# ls /data/scripts-exercise/
111h2M 222czV magelvT title_NUM.sh trap.sh
1.txt 2.txt sunanF trap_finish.sh wang0hz
install安装复制文件
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
[aaa@qq.com scripts-exercise]# ll
total 20
-rw------- 1 root root 0 Oct 31 10:39 111h2M
-rw-r--r-- 1 root root 20 Oct 30 19:46 1.txt
-rw------- 1 root root 0 Oct 31 10:40 222czV
-rw-r--r-- 1 root root 10 Oct 30 19:17 2.txt
drwx------ 2 root root 6 Oct 31 10:31 magelvT
-rw------- 1 root root 0 Oct 31 10:29 sunanF
-rw-r--r-- 1 root root 320 Oct 30 21:43 title_NUM.sh
-rw-r--r-- 1 root root 143 Oct 30 20:26 trap_finish.sh
-rw-r--r-- 1 root root 239 Oct 30 20:25 trap.sh
-rw------- 1 root root 0 Oct 31 10:30 wang0hz
#复制1.txt到/data/scripts-exercise/下改名为333.txt
#更改属主、属组为sun
#设置文件权限为777
[aaa@qq.com scripts-exercise]# install -o sun -g sun -m 777 1.txt /data/scripts-exercise/333.txt
[aaa@qq.com scripts-exercise]# ll
total 24
-rw------- 1 root root 0 Oct 31 10:39 111h2M
-rw-r--r-- 1 root root 20 Oct 30 19:46 1.txt
-rw------- 1 root root 0 Oct 31 10:40 222czV
-rw-r--r-- 1 root root 10 Oct 30 19:17 2.txt
-rwxrwxrwx 1 sun sun 20 Oct 31 10:50 333.txt
drwx------ 2 root root 6 Oct 31 10:31 magelvT
-rw------- 1 root root 0 Oct 31 10:29 sunanF
-rw-r--r-- 1 root root 320 Oct 30 21:43 title_NUM.sh
-rw-r--r-- 1 root root 143 Oct 30 20:26 trap_finish.sh
-rw-r--r-- 1 root root 239 Oct 30 20:25 trap.sh
-rw------- 1 root root 0 Oct 31 10:30 wang0hz
expect命令
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 允许用户交互
- xp_continue 匹配多个字符串在执行动作后加此命令
示例
#!/usr/bin/expect
spawn ssh 192.168.8.100
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send "magedu\n" }
}
interact
#expect eof
示例 变量
#!/usr/bin/expect
set ip 192.168.8.100
set user root
set password magedu
set timeout 10
spawn ssh aaa@qq.com$ip
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send "$password\n" }
}
interact
示例 位置参数
#!/usr/bin/expect
set ip [lindex $argv 0]
set user [lindex $argv 1]
set password [lindex $argv 2]
spawn ssh aaa@qq.com$ip
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send "$password\n" }
}
interact
#./ssh3.exp 192.168.8.100 root magedu
示例 执行多个命令
#!/usr/bin/expect
set ip [lindex $argv 0]
set user [lindex $argv 1]
set password [lindex $argv 2]
set timeout 10
spawn ssh aaa@qq.com$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 192.168.8.100 root magedu
shell脚本调用expect
#!/bin/bash
ip=$1
user=$2
password=$3
expect <<EOF
set timeout 20
spawn ssh aaa@qq.com$ip
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send "$password\n" }
}
expect "]#" { send "useradd hehe\n" }
expect "]#" { send "echo magedu |passwd --stdin hehe\n" }
expect "]#" { send "exit\n" }
expect eof
EOF
#./ssh5.sh 192.168.8.100 root magedu
下一篇: while的一个小陷阱
推荐阅读