欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

马哥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)

注意:索引可支持使用自定义的格式,比如说字母字符,而不仅是数值格式,即为关联索引

马哥29-脚本进阶

bash的数组支持稀疏格式(索引不连续稀):文件的实际大小和磁盘上存储的真实大小不同
又称空洞文件(如下图)

申明数组 declare -a ARRAY_NAME 可以不申明,但建议申明

关联数组必须先申明再使用 declare -A ARRAY_NAME 关联数组

显示所有数组 declare -a

马哥29-脚本进阶

数组演示

创建数组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

变量赋值

没有配置表示没这个变量
空字符串表示变量存在但是没有赋值

马哥29-脚本进阶

高级变量用法

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