第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         #删除函数
函数定义;自定义函数的基本语法;载入函数(source命令|.);检查载入函数(set命令);删除函数
复制代码
复制代码
函数内声明的变量;环境函数;递归函数(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中特殊符号”
大括号可以理解成匿名函数
函数内声明的变量;环境函数;递归函数(fork炸弹);函数使用注意事项
复制代码

 

 

 

复制代码
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命令
bash命令;eval命令;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
复制代码

 

复制代码
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
expect实例
复制代码

 

posted @   雲淡風輕333  阅读(86)  评论(0编辑  收藏  举报
(评论功能已被禁用)
编辑推荐:
· 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框架的用法!
点击右上角即可分享
微信分享提示