第8章:shell编程:函数;bash/eval/mktemp/install;expect
函数

函数定义;自定义函数的基本语法;载入函数(source命令|.);检查载入函数(set命令);删除函数 ========================================================================= shell 编程和其它编程语言一样,有系统函数,也可以自定义函数。 函数function是由若干条shell命令组成的语句块,实现代码重用和模块化编程 函数与shell程序形式上是相似的,不同的是,函数不是一个单独的进程,不能独立运行,而是shell程序的一部分 函数与shell程序的区别: 1.shell程序在子shell中运行 2.函数在当前shell中运行。所以函数可以对当前shell的变量进行修改 ------------------------------------------------------------------------- 自定义函数 函数由两部分组成:函数名和函数体 基本语法: [ function ] funname[()] #function和()都是可以省略,但不能同时省略,所以相当于有3种定义函数的写法 { Action; [return int;] #使用return来退出函数,而不能使用exit,因为exit是退出脚本 } 调用直接写函数名:funname [值] ------------------------------------------------------------------------- 载入函数 source #加载文件,实现函数的复用;这个就是python的import吧。。。 示例: source filename #加载函数文件 . filename #加载函数文件 source functions #此处的functions为/etc/init.d/functions /etc/init.d/functions文件中有一些实用的系统函数 例如action函数 action "提示信息" ------------------------------------------------------------------------- 检查载入函数 set命令会显示在shell中的所有载入函数 declare -f #查看shell中定义的所有函数 declare -f func_name #查看shell中定义的指定函数 ------------------------------------------------------------------------- 删除函数 unset func_name #删除函数

函数内声明的变量;环境函数;递归函数(fork炸弹);函数使用注意事项 ================================================================== 函数内声明的变量 [root@yefeng ~]# func1 () { name=testname;echo "func1:$name"; } [root@yefeng ~]# func1 func1:testname [root@yefeng ~]# echo $name #函数是在当前shell中执行的,所以变量在本地也会有 testname ------------------------ [root@yefeng ~]# func1 () { local name1=testname;echo "func1:$name"; } [root@yefeng ~]# func1 func1:testname [root@yefeng ~]# echo $name1 #local定义的变量仅在函数内生效 ----------------------- [root@yefeng ~]# func2 () { declare -i number1=100;echo "func1:$number1"; } [root@yefeng ~]# func2 func1:100 [root@yefeng ~]# echo $number1 #declare在函数中使用时,相当于隐式声明local ----------------------- [root@yefeng ~]# func2 () { declare -ig number1=100;echo "func1:$number1"; } [root@yefeng ~]# func2 func1:100 [root@yefeng ~]# echo $number1 #declare在函数中使用时,-g则声明的是普通变量 100 ================================================================== 环境函数 定义的函数和普通变量是差不多的,只能在当前shell有效; 可以通过export -f 定义全局函数(环境函数) #函数定义归函数定义,声明环境函数归生命环境函数,不能写在一起,必须分开。 export -f 本质上是declare -fx ? ================================================================== 递归函数 递归函数,若无止境地进行递归,同时还有内存中需要保存上一级递归的状态,那么内存占用将会越来越大,导致系统崩溃 fork炸弹:实质就是一个简单的递归程序 :(){ :|:& };: bomb(){ bomb | bomb & };bomb ================================================================== 函数使用注意事项 某些敏感的时刻,一定要测试一下变量or函数是否存在,例如下面的例子,看起来逻辑没问题,但是系统正好复制失败,然后$path就是空;这个rm命令删除什么就可以想象了。。。 [root@yefeng ~]# path=/data [root@yefeng ~]# rm -rf $path/* #所以用rm时,这种方式还是的慎用!!!!! 判断方法么,就是用declare -f func_name、set variable,然后判断$?的值 ()和{}的区别,详见“shell中特殊符号” 大括号可以理解成匿名函数

bash命令;eval命令;mktemp命令;install命令 ========================================================================= bash命令 bash #默认开启一个新的bash进程 bash -n xx.sh #只读取shell脚本,但不实际执行;用于检测是否存在语法错误 bash -x xx.sh #调试脚本,进入跟踪方式,显示所执行的每一条命令 bash -c "string" #从strings中读取命令 ========================================================================= eval命令 eval命令将会首先扫描命令进行所有的置换,然后再执行该命令。该命令适用于那些一次扫描无法实现其功能的变量,该命令对变量进行两次扫描 for i in {1..$n};#错误! for i in `eval echo {1..$n}`; #这时才是要的写法;为什么需要这样?猜测:``内是不会识别变量的,这里通过eval来识别$n for i in `seq $n` ===================================================================== 创建临时文件命令 mktemp命令 安装复制文件 install命令
sudo bash -c bash #这个命令的效果和 "sudo bash" 不同
通常使用shell去运行脚本,两种方法 bash xxx.sh,另外一种就是bash -c “cmd string”
bash -c :shell有很多种,bash -c 可以确保使用bash shell执行命令
expect

expect expect是建立在tcl基础上的一个工具,它可以让一些需要交互的任务自动化地完成。相当于模拟了用户和命令行的交互操作。 一个具体的场景:远程登陆服务器,并执行命令 登录时输入密码需要交互,bash脚本无法完成,可以使用expect来完成。expect只适合几十台的设备的自动化运维 expect参数 -c 从命令行执行expect脚本,默认expect是交互地执行的 -d 可以输出调试信息 expect中的相关命令 spawn 启动新的进程 send 用于向进程发送字符串 expect 从进程接收字符串 interact 允许用户交互 exp_continue 匹配多个字符串在执行动作后加此命令 ========================================================== expect最重用的语法(tcl语言:模式-动作) 单一分支模式语法 expect "hi" {send "You said hi\n"} 多分支模式语法 expect "hi" {send "You said hi\n"} \ "hehe" {send "hehe yourself\n"} \ "bye" {send "goodbye\n"} \ 等同于如下 expect { "hi" {send "You said hi\n"} \ "hehe" {send "hehe yourself\n"} \ "bye" {send "goodbye\n"} \ } ========================================================== #!/usr/bin/expect set timeout 30 #设置会话超时时间为30s, 若不限制超时时间则应设置为-1 set param "param_str" #set设置变量 set param 1 spawn ${cmd} # for example : spawn su root; spawn 后面跟一个命令,开启一个会话 --------------------------------------------------------- expect 接收命令执行后的输出,然后和期望字符串匹配,若对应这执行相应的send来发送交互信息。 expect "$case1" {send "$respond1\r"} # 这一行等同于下面两行 expect "$case1" send "$response1\r" --------------------------------- expect 可以有多个分支,就像switch语句一样。 expect { "$case1" {send "$response1\r"} "$case2" {send "$response2\r"} "$case3" {send "$response3\r"} } --------------------------------- 结束符 expect eof :等待执行结束,若没有这一句,可能导致命令还没执行,脚本就结束了 interact : 执行完成后保持交互状态, 这时可以手动输入信息 注:expect eof 与 interact 二选一即可 --------------------------------- 接收参数 参数存在argv中,使用第一个参数如下: set param0 [lindex $argv 0]

expect实例 ================================================================ 实现远程登录服务器,并切换到root用户下执行关闭防火墙的命令,然后退出 #!/usr/bin/expect if {$argc < 4} { #do something send_user "usage: $argv0 <remote_user> <remote_host> <remote_pwd> <remote_root_pwd>" exit } set timeout -1 set remote_user [lindex $argv 0] # 远程服务器用户名 set remote_host [lindex $argv 1] # 远程服务器域名 set remote_pwd [lindex $argv 2] # 远程服务器密码 set remote_root_pwd [lindex $argv 3] # 远程服务器根用户密码 # 远程登录 spawn ssh ${remote_user}@${remote_host} expect "*assword:" {send "${remote_pwd}\r"} expect "Last login:" # 切换到 root send "su\r" expect "*assword:" {send "${remote_root_pwd}\r"} # 执行关闭防火墙命令 send "service iptables stop\r" send "exit\r" send "exit\r" expect eof
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!