1 信号捕捉 trap

trap 命令可以捕捉信号,修改信号原来的功能,实现自定义功能
常用参数:

-l 让shell打印一个命令名称和其相对应的编号的列表
-p 打印与每一个信号有关联的命令的列表
缺省 每个接收到的sigspec信号都将会被重置为它们进入shell时的值
-f 阻止中断信号
  1. #查看信号列表
  2. trap -l
  3. 2) SIGINT :是Ctrl+C的按键信号
  4. ### 信号的值可以写成三种格式:
  5. ## 2(数字法表示) | SIGINT(全称) | INT(简称)
  6. #进程收到系统发出的指定信号后,将执行自定义指令,而不会执行原操作
  7. trap '触发指令' 信号
  8. #忽略信号的操作
  9. trap '' 信号
  10. #恢复原信号的操作
  11. trap '-' 信号
  12. #列出自定义信号操作
  13. trap -p
  14. #当前脚本退出时,执行finish函数(重要)
  15. trap finish EXIT

范例:

  1. #!/bin/bash
  2. #自定义指令信号
  3. trap "echo 'Please Ctrl+C or Ctlr+\'" SIGINT SIGQUIT
  4. trap -p
  5. for ((i=0;i<=10;i++))
  6. do
  7. sleep 1
  8. echo $i
  9. done
  10. #忽略原信号操作
  11. trap '' SIGINT
  12. trap -p
  13. for ((i=11;i<=20;i++))
  14. do
  15. sleep 1
  16. echo $i
  17. done
  18. #恢复原信号操作
  19. trap '-' SIGINT
  20. trap -p
  21. for ((i=21;i<=30;i++))
  22. do
  23. sleep 1
  24. echo $i
  25. done

范例:当脚本正常或者异常退出时,也会执行 finish 函数

  1. ~ vim trap-exit.sh
  2. #!/bin/bash
  3. function finish()
  4. {
  5. echo finish is at `date +%F_%T` | tee -a /root/finish.log
  6. }
  7. #捕获退出就执行finish函数
  8. trap finish exit
  9. while true ;do
  10. echo running
  11. sleep 1
  12. done

2 创建临时文件 mktemp

mktemp 命令用于创建并显示临时文件,可以避免冲突
格式:

  1. mktemp [OPTIONS]... [TEMPLATE]
  2. 说明:TEMPLATE: filenameXXXX至少要出现三个,三个以上随机字符

常用选项:

  1. -d #创建临时目录
  2. -p DIR或者--tmpdir=DIR #指明临时文件所存放目录位置

范例:

  1. ~ mktemp
  2. /tmp/tmp.lOLpKJ8nrB
  3. ~ mktemp /tmp/testXXX
  4. ~ tmpdir=`mktemp -d /tmp/testdirXXX`
  5. ~ mktemp --tmpdir=tmpdir testXXXXXX
  6. ~ mktemp -d tmpdirXXX -p /usr/local/src

范例:实现文件垃圾箱功能

  1. #方法1:脚本实现
  2. ~ vim /data/shell/mktemp-rm.sh
  3. #!/bin/bash
  4. DIR=$(mktemp -d /tmp/trash-$(date +%F_%T)XXX)
  5. mv $* $DIR
  6. echo $* is move to $DIR
  7. ~ chmod +x /data/shell/mktemp-rm.sh
  8. ~ alias rm=/data/shell/mktemp-rm.sh
  9. ~ rm finish.log
  10. finish.log is move to /tmp/trash-2022-06-14_17:35:45jX0
  11. #方法2:函数实现
  12. ~ function rm() { local trash=$(mktemp -d /tmp/trash-$(date +%F_%T)XXX);mv $* $trash; }

3 安装复制文件 install

install 功能相当于 cp,chmod,chown,chgrp,mkdir等相关工具的集合
install 命令格式:

  1. Usage: install [OPTION]... [-T] SOURCE DEST
  2. or: install [OPTION]... SOURCE... DIRECTORY
  3. or: install [OPTION]... -t DIRECTORY SOURCE...
  4. or: install [OPTION]... -d DIRECTORY...

选项:

  1. -m MODE 权限,默认755
  2. -o OWNER 用户
  3. -g GROUP 用户组
  4. -d DIRNAME 目录

范例:

~ install -m 700 -o wang -g admins srcfile dstfile
#-d:相当于mkdir -p
~ install -m 700 -d /testdir/installdir

~ install -m 600 -o wang -g bin reset.sh /data/set.sh
~ ls -l /data/set.sh

~ install -m 700 -o kubesphere -g daemon -d /data/testdir
~ ls -ld /data/testdir

4 交互式转换批处理工具 expect

expect是由Don Libes基于TCL ( Tool Command Language ) 语言开发的,主要应用于自动化交互式操作的场景,借助 expect 处理交互的命令,可以将交互过程如:ssh登录,ftp登录等写在一个脚本上,使之自动化完成。尤其适用于需要对多台服务懦执行相同操作的环境中,可以大大提高系统管理人员的工作效率。
范例:安装expect 及mkpasswd工具

➜  ~ yum install -y expect
➜  ~ rpm -ql expect | head
/usr/bin/autoexpect
/usr/bin/dislocate
/usr/bin/expect
/usr/bin/ftp-rfc
/usr/bin/kibitz
/usr/bin/lpunlock
/usr/bin/mkpasswd
/usr/bin/passmass
/usr/bin/rftp
/usr/bin/rlogin-cwd

➜  ~ mkpasswd
gBOlu87i<
➜  ~ mkpasswd -l 15 -d 3 -C 5
@k5FpJ9XRsPaj1i

expect 语法:

expect [选项] [ -c cmds ]  [[ -[flb] ] cmdfile ] [ args ]

常见选项:

-c:从命令行执行expect脚本,默认expect是交互地执行的
-d:可以调试信息

示例:

expect -c 'expect "\n" { send "pressed enter\n" }'
expect -d ssh.exp

expect 中的相关命令

  • spawn 启动新的进程
  • expect 从进程接收字符串
  • send 用于向进程发送字符串
  • interact 允许用户交互(将权限交给用户)
  • exp_continue 匹配多个字符串在执行动作后如此命令(在 expect 中多次匹配就需要用到)
  • eof export 执行结束退出
  • send_user 用来打印输出,相当于 shell 中的 echo
  • exit 退出expect脚本
  • set 定义变量
  • puts 输出变量
  • set timeout 设置超时时间

expect 最常用的语法:(TCL语言:模式-动作)
单一分支模式语法:

#直接执行expect则是交互式
~ expect
#一次性的。
expect1.1> expect "hi" {send "You said hi\n"}
hi
You said hi
expect1.2> expect "hi" {send "You said hi\n"}
123hihello
You said hi

匹配到 hi 后,会输出”You said hi”,并换行
多分支模式语法:

~ expect
expect1.1> expect "hi" { send "You said hi\n" } "hehe" { send "Hehe yourself\n" } "bye" { send "Good bye\n" }
hehe
Hehe yourself
expect1.2> expect "hi" { send "You said hi\n" } "hehe" { send "Hehe yourself\n" } "bye" { send "Good bye\n" }
bye
Good bye
expect1.3> expect "hi" { send "You said hi\n" } "hehe" { send "Hehe yourself\n" } "bye" { send "Good bye\n" }
hi
You said hi

匹配 hi,hello,bye 任意字符串时,执行相应输出。等同如下:

expect {
  "hi" { send "You said hi\n" }
  "hehe" { send "Hehe yourself\n" }
  "bye" { send "Good bye\n" }
}

~ expect1.1> expect {
+>  "hi" { send "You said hi\n" }
+>  "hehe" { send "Hehe yourself\n" }
+>  "bye" { send "Good bye\n" }
+> }
bye
Good bye
expect1.2>

范例1:非交互式复制文件

~ vim expect-scp
#!/usr/bin/expect
spawn scp /etc/redhat-release 10.0.0.170:/data
expect {
  "yes/no" { send "yes\n";exp_continue }
  "password" { send "magedu\n" }
}
expect eof

范例2:自动登录

~ vim expect-ssh
#!/usr/bin/expect
spawn ssh 10.0.0.170
expect {
    "yes/no" { send "yes\n";exp_continue }
    "password" { send "magedu\n" }
}
interact

范例3:expect 变量

~ vim expect-set-ssh
#!/usr/bin/expect
set ip 10.0.0.170
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

范例4:expect 位置参数

~ vim expect-arg
#!/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

~ chmod +x expect-args
~ ./expect-args 10.0.0.170 root magedu
spawn ssh root@10.0.0.170
root@10.0.0.170's password:
Last login: Tue Jun 14 21:42:04 2022 from 10.0.0.160
[root@kubesphere-mysql57 ~]#logout
Connection to 10.0.0.170 closed.

范例5:expect 执行多条命令

~ vim expect-command
#!/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" }
}
expect "]#" { send "useradd haha\n" }
expect "]#" { send "echo Admin@h3c | passwd --stdin haha\n"}
send "exit\n"
expect eof

~ ./expect-command 10.0.0.170 root magedu

范例6:shell 脚本调用 expect

~ vim shell-expect.sh
#!/bin/bash
#Shell ENV
ip=${1}
user=${2}
password=${3}

expect <<EOF
set timeout 20
spawn ssh $user@$ip
expect {
    "yes/no" { send "yes\n";exp_continue }
    "password" { send "$password\n" }
}
expect "]#" { send "useradd hehe\n"}
expect "]#" { send "echo Admin@h3c | passwd --stdin hehe\n" }
expect "]#" { send "exit\n" }
expect eof
EOF

~ chmod +x bash-expect.sh
~ ./bash-expect.sh 10.0.0.170 root magedu

范例7:shell脚本利用循环调用 expect 在 CentOS 和Ubuntu上批量创建用户

~ vim export-ubuntu-centos-useradd.sh
#!/bin/bash
#SHELL ENV
net=10.0.0
user=root
password=magedu
IPLIST="
51
52
53
"

for ID in $IPLIST ;do
ip=$net.$ID

expect <<EOF
set timeout 20
spawn ssh $user@$ip
expect {
  "yes/no" { send "yes\n";exp_continue }
  "password" { send "$password\m" }
}
expect "#" { send "useradd test\n" }
expect "#" { send "exit\n" }
expect eof
EOF
done

范例:修改配置文件 SELinux

~ vim expect-selinux.sh
#!/bin/bash
#SHELL ENV
net=10.0.0
user=root
password=magedu
IPLIST="
51
52
53
"

for ID in $IPLIST ;do
ip=$net.$ID

expect <<EOF
set timeout 20
spawn ssh $user@$ip
expect {
  "yes/no" { send "yes\n";exp_continue }
  "password" { send "$password\m" }
}
expect "#" { send "sed -i 's/^SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config\n" }
expect "#" { send "setenforce 0\n" }
expect "#" { send "exit\n" }
expect eof
EOF
done

范例:在指定主机执行批量操作

~ vim expect-scp.sh
#!/bin/bash

net=10.0.0
user=root
password=magedu

for i in {51..53} ;do
ip=$net.$i
expect <<EOF
set timeout 20
spawn scp /etc/selinux/config $user@$ip:/data
expect {
  "yes/no" { send "yes\n";exp_continue }
  "password" { send "$password\n" }
}
spawn ssh $user@$ip
expect {
  "yes/no" { send "yes\n";exp_continue }
  "password" { send "$password\n" }
}
expect "root" { send "useradd kubesphere\n" }
expect "root" { send "echo Admin@h3c | passwd --stdin kubesphere\n" }
expect "root" { send "exit\n" }
expect eof
EOF

done

~ chmod +x expect-scp.sh
~ ./expect-scp.sh