函数function是由若干条shell命令组成的语句块,实现代码重用和模块化编程,它与shell程序形式上相似,不同的是它不是一个单独的进程,不能独立运行,而是shell程序的一部分。
脚本函数三种写法
[root@rocky8 ~]# help function
function: function name { COMMANDS ; } or name () { COMMANDS ; }
Define shell function.
Create a shell function named NAME. When invoked as a simple command,
NAME runs COMMANDs in the calling shell's context. When NAME is invoked,
the arguments are passed to the function as $1...$n, and the function's
name is in $FUNCNAME.
Exit Status:
Returns success unless NAME is readonly.
#语法一:
function (){
...函数体...
}
#语法二:
function func_name{
...函数体...
}
#语法三:
function func_name(){
...函数体...
}
信号捕捉trap
在 Linux 系统中,信号是一种进程间通信的机制,允许进程通过信号来通知或中断其他进程的执行。信号捕捉(Signal Handling)是指进程对信号进行响应的机制,可以选择忽略、处理或终止信号。
trap命令可以捕捉信号,修改信号原来的功能,实现自定义功能。
[root@rocky ~]# help trap
trap: trap [-lp] [[arg] signal_spec ...]
Trap signals and other events.
Defines and activates handlers to be run when the shell receives signals or other conditions.
ARG is a command to be read and executed when the shell receives the signal(s) SIGNAL_SPEC.
If ARG is absent (and a single SIGNAL_SPEC is supplied) or `-',
each specified signal is reset to its original value.
If ARG is the null string each SIGNAL_SPEC is ignored by the shell and by the commands it invokes.
If a SIGNAL_SPEC is EXIT (0) ARG is executed on exit from the shell.
If a SIGNAL_SPEC is DEBUG, ARG is executed before every simple command.
If a SIGNAL_SPEC is RETURN, ARG is executed each time a shell function or a
script run by the . or source builtins finishes executing. A SIGNAL_SPEC
of ERR means to execute ARG each time a command's failure would cause the
shell to exit when the -e option is enabled.
If no arguments are supplied, trap prints the list of commands associated
with each signal.
Options:
-l print a list of signal names and their corresponding numbers
-p display the trap commands associated with each SIGNAL_SPEC
Each SIGNAL_SPEC is either a signal name in <signal.h> or a signal number.
Signal names are case insensitive and the SIG prefix is optional. A
signal may be sent to the shell with "kill -signal $$".
Exit Status:
Returns success unless a SIGSPEC is invalid or an invalid option is given.
为什么我们按下ctrl+c键就能结束linux当前正在运行的进程,比如ping命令默认是一直进行ping,当你按下ctrl+c时就结束了ping,为什么会这样?其实是ctrl+c向ping发送了一个停止的信号,可以使用“trap -l”查看所有的信号
#列出所有信号
trap -l
#进程收到系统发出的指定信号后,将执行自定义指令,而不会执行原操作。
trap '触发指令' 信号
#列出自定义信号操作
trap -p
#当脚本退出时,执行finish函数
trap finish EXIT
信号捕捉的应用:将来在程序执行时,不希望被ctrl+c这样的异常突然终止掉程序。信号捕捉工具就是trap,trap是内部命令,内部命令通过help查看帮助。外部命令则可以通过man查看。
#! /bin/bash
# 捕获2信号 2信号是: 2) SIGINT
trap 'echo 删除根系统,不能中断' 2
while true; do
echo "正在删除系统中,请稍后!"
sleep 1
done
安全退出
#! /bin/bash
finish(){
echo "Finish at `date +%F_%T`" | tee -a /root/finish.log
}
trap finish exit
while true ;do
echo running
sleep 1
done
创建临时文件mktemp
mktemp命令用于创建显示临时文件,可避免冲突。
mktemp [option]...[TEMPLATE]
#说明:template: filenameXXXX x至少要出现三个
编写"rm.sh"脚本实现手工制作垃圾箱
#! /bin/bash
DIR=`mktemp -d /tmp/trash-$(date +%F_%H-%M-%S)xxxxxx`
mv $* $DIR
echo $* is move to $DIR
定义一个rm的别名,将’'rm.sh"脚本赋值给rm这个别名。
安装复制文件install
install 功能相当于cp,chmod,chown,chgrp,mkdir等相关命令的集合
交互式转化批处理工具expect
expect是由Don Libes基于Tcl(Tool Command Language)语言开发的,主要应用于自动化交互式操作的场景,借助expect处理交互的命令,可以将交互过程如:ssh登录,ftp登录写在一个脚本上,使之自动化完成,尤其适用于需要多台服务器执行相同操作的环境中,可以大大提高系统管理人员的工作效率。expect需要安装 yum -y install except
交互式命令:需要你输入yes/no才能执行下一步的操作。
expect中相关命令
·spawn 启动新的进程
·expect 从进程接收字符串
·send 用于向进程发送字符串
·interact 运行用户交互
·exp_continue 匹配多个字符串在执行动作后加次命令
可以认为expect就是一种独立的脚本编程语言,则它的首行机制就是“/usr/bin/expect”
#!/usr/bin/expect
spawn scp /etc/redhat-release 10.0.0.201:/data
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send "123456\n"}
}
expect eof
#此脚本是将当前机器上的linux版本信息远程拷贝到10.0.0.201机器上,并在需要交互yes时,自动输入yes,并在需要输入201机器上的密码时,自动输入密码
因为不是/bin/bash了,所以expect1的执行就只能是赋予执行权限之后执行了。
回到交互式(interact)
#!/usr/bin/expect
spawn ssh 10.0.0.210
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send "123456\n" }
}
interact
expect 通过set赋值变量
#!/usr/bin/expect
set ip 10.0.0.201
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
expect 位置参数,(执行脚本实,后面的参数的位置得和脚本里定义的参数的位置保持一直)
#!/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_contiune }
"password" { send "$password\n"}
}
interact
shell脚本调用expect
#!/bin/bash
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 123456 | passwd --stdin hehe\n" }
expect "]#" { send "exit\n" }
expect eof
EOF
#一定记得expect和{之间有空格啊,不然就报invalid
#invalid command name "expect{"
# while executing
#"expect{"
在多个机器201,216,217上,批量创建test账号
#!/bin/bash
NET=10.0.0
user=root
password=123456
IPLIST="
201
216
217
"
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\n" }
}
expect "]#" { send "useradd test\n" }
expect "]#" { send "exit\n" }
#关闭selinux
#expect "]#" { send "sed -i ‘s/^SELINUX=enforcing/SELINUX=disabled/’ /etc/selinux/config\n" }
#expect "]#" { send "setenforce 0\n" }
expect eof
EOF
done
#批量创建test账号成功
[root@rocky8 scripts]# bash expect6.sh
spawn ssh root@10.0.0.201
root@10.0.0.201's password:
Activate the web console with: systemctl enable --now cockpit.socket
Last login: Tue Mar 14 14:39:27 2023 from 10.0.0.210
[root@centos8 ~]# useradd test
[root@centos8 ~]# exit
logout
Connection to 10.0.0.201 closed.
spawn ssh root@10.0.0.216
The authenticity of host '10.0.0.216 (10.0.0.216)' can't be established.
ECDSA key fingerprint is SHA256:mZPxf2BlCHWGFGOySe3SIqZz4cKNlqJZyBsl63kbGEg.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.0.0.216' (ECDSA) to the list of known hosts.
root@10.0.0.216's password:
Last login: Tue Mar 14 15:01:17 2023 from 10.0.0.1
[root@centos7 ~]# useradd test
[root@centos7 ~]# exit
logout
Connection to 10.0.0.216 closed.
spawn ssh root@10.0.0.217
The authenticity of host '10.0.0.217 (10.0.0.217)' can't be established.
ECDSA key fingerprint is SHA256:o4LXS6D+DywH8JOjcem8/f4wcRXkOMQ7TCUipw+9aeM.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.0.0.217' (ECDSA) to the list of known hosts.
root@10.0.0.217's password:
Last login: Tue Mar 14 15:01:28 2023 from 10.0.0.1
[root@rocky8 ~]# useradd test
[root@rocky8 ~]# exit
logout
Connection to 10.0.0.217 closed.
[root@rocky8 scripts]#
shell脚本数组array
变量:存储单个元素的内存空间
数组:存储多个元素的连续的内存空间,相当于多个变量的集合
数组名和索引
索引的编号从0开始,属于述职引用
索引可支持使用自定义的格式,而不仅是数值格式,即为关联索引。bash4.0版本之后开始支持。
#普通数组可以不事先声明,直接使用
declare -a array_name
#关联数组必须先声明,再使用
declare -A array_name
#注意两者不可相互转换
declare 声明和查看数组变量, unset:删除数组
范例:生产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 number are ${nums[*]}"
echo "Max is $max"
echo "Min is $min"
基于模式取子串
#其中word可以是指定的任意字符,自左而右,查找var变量所存储的字符串中第一次出现的word,删除字符串开头至第一次出现word字符串(含)之间的所有字符,即懒惰模式,以第一个word为界删左留右
${var#*word}
#从var变量的值中删除以word开头的部分
${var#word}
#同上,贪婪模式,不同的是,删除的是字符串开头至最后一次有word指定的字符之间的所有内容,即贪婪模式,以最后一个word为界删左留右
${var##*word}
${var##word}
#与上相反,从右侧的字符开始向左删,,即贪婪模式,以从右向左的最后一个word为界删右留左
${var%%*word}
${var%%word}
贪婪模式
贪婪模式的应用,将来编译安装nginx等软件时,可以直接获取软件下载链接(http://nginx.org/download/nginx-1.23.3.tar.gz)后面的包名(nginx-1.23.3.tar.gz),获取包名后就可以直接做解压等后续的操作了
从右往左删
查找替换
#查找var所表示的字符串中,第一被pattern所匹配到的字符串,以substr替换之
${var/parrern/substr}
#查找var所表示的字符串中,所有被pattern所匹配到的字符串,以substr替换之
${var//parrern/substr}
#查找var所表示的字符串中,行首被pattern所匹配到的字符串,以substr替换之
${var/#parrern/substr}
#查找var所表示的字符串中,行尾被pattern所匹配到的字符串,以substr替换之
${var/%parrern/substr}