目录
循环语句
for
while 与 until
sed
基本用法
sed脚本格式
函数
注意事项
定义函数和调用函数
脚本中函数的位置
查看函数
删除函数
函数返回值
函数的传参操作
使用函数文件
递归函数
数组
声明数组
数组切片
免交互expect
定义
基本命令
for循环需要知道循环的次数
格式1:
for 变量 in 变量范围
do
执行的命令
done
例如:计算1到100的和
#!/bin/bash
sum=0 # 定义和的变量
for i in {1..100} # 遍历1到100
do
sum=$[sum+i] # 计算1到100的和
done
echo $sum # 输出总和
格式2:
for (( 表达式1; 表达式2; 表达式3 )); do 命令; done
或
for (( 表达式1; 表达式2; 表达式3 ))
do 命令
done
例如:计算1到100的和
#!/bin/bash
sum=0
for ((i=0;i<=100;i++))
do
sum=$[sum+i]
done
echo $sum
for循环嵌套
例如:打印99乘法表
#!/bin/bash
for i in {1..9}
do
for ((j=1;j<=$i;j++))
do
echo -en "$i*$j=$[i*j]\t"
done
echo
done
for循环例子:
例1:批量添加用户
#!/bin/bash
ulist=$(cat /opt/user.txt)
for uname in $ulist
do
useradd $uname
echo "123123" |passwd --stdin $uname &>/dev/null
done
例2:批量修改后缀名
#!/bin/bash
cd /data
for file in *
do
name=`echo $file |cut -d "." -f1`
mv $file ${name}.bak
done
相对于for循环,while循环不需要知道循环次数,但是需要给循环结束的条件,否则就是死循环。
while与until的区别:
while
当命令判断为假时停止until
当命令判断为真时停止
例如:计算1-100所有偶数的和
#!/bin/bash
i=0
sum=0
while [ $i -le 100 ]
do
let sum+=$i
let i+=2
done
echo $sum
例如:猜数字游戏
#!/bin/bash
p=`echo $[RANDOM%1000+1]`
t=0
while true
do
read -p "请输入你猜的数字1-1000:" num
let t++
if [ $num -eq $p ]
then echo "恭喜你猜中了,随机数字是$p"
echo "您一共猜了${t}次";exit 0
elif [ $num -gt $p ]
then echo "您猜的数字高了"
else echo "您猜的数字低了"
fi
done
双重循环及跳出循环
break跳出单个循环后面加数字2则代表跳出两层循环
continue终止某次循环中的命令,但是不会完全终止命令
continue终止本次循环,继续下一次循环
如:
break结束当前循环,不在执行当前的循环
如:
Sed是从文件或管道中读取一行,处理一行,输出一行;再读取一行,再处理一行,再输出一行,直到最后一行。每当处理一行时,把当前处理的行存储在临时缓冲区中,称为模式空间(PatternSpace),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。
格式:
sed [option]... 'script;script;...' [input file...]
选项 自身脚本语法 支持标准输入管道
常用选项:
-n 不输出模式空间内容到屏幕,即不自动打印
-e 多点编辑[root@www data]#sed -n -e '/^r/p' -e'/^b/p' /etc/passwd
-f FILE 从指定文件中读取编辑脚本
-r, -E 使用扩展正则表达式
-i.bak 备份文件并原处编辑
-s 将多个文件视为独立文件,而不是单个连续的长文件流
-n 关闭自动打印功能
-r, -E 使用扩展正则表达式
格式:
sed '地址+命令' 文件
所谓的地址就是一些参数,或规定的条件,根据这些参数和条件进行打印或修改等操作
1. 不给地址:对全文进行处理(比如行号)
2. 单地址:
#(1,2,3...):指定的行,$:最后一行,需要结合选项和命令进行匹配
/pattern/:被此处模式所能够匹配到的每一行,正则表达式
3. 地址范围:
n,n 表示从n行到第n行,3,6 从第3行到第6行
n,+m 表示从n行到n+m行,3,+4 表示从3行到第7行
/pat1/,/pat2/ 表示从第一个正则表达式和第二个正则表达式之间的行
n,/pat/ 表示从n号行为开始找到 pat为止
/pat/,n 表示找到pat后n行为止
4. 步进:~
1~2 奇数行
2~2 偶数行
命令
p 打印当前模式空间内容,追加到默认输出之后(要与选项-n一起使用)
I (大写的 i ) 忽略大小写输出
d 删除模式空间匹配的行,并立即启用下一轮循环
a [\]text 在指定行后面追加文本,支持使用\n实现多行追加
i [\]text 在行前面插入文本
c [\]text 替换行为单行或多行文本
w file 保存模式匹配的行至指定文件
r file 读取指定文件的文本至模式空间中匹配到的行后
= 为模式空间中的行打印行号
! 模式空间中匹配行取反处理
面试题:查看几点到几点之间的日志
[root@heitui opt]#sed -n '/15:41/,/15:42/p' log #此处的log文件在opt下
搜索替代,类似于vim编辑器末行模式的s///g
s/pattern/string/修饰符 查找替换,支持使用其它分隔符,可以是其它形式:s@@@,s###
替换修饰符:
g 行内全局替换
p 显示替换成功的行
w /PATH/FILE 将替换成功的行保存至文件中
I,i 忽略大小写
格式1:
function 函数名 {
命令序列
}
格式2:
函数名(){
命令序列
}
格式3:
function 函数名 (){
命令序列
}
三种格式都是同样的效果,推荐使用格式2,格式2最为简单
函数调用,直接使用函数名即可,函数名就相当于命令
同名函数 后一个生效
调用函数一定要先定义,在调用,否则会报错
函数在调用时,不会在乎每个函数定义的顺序
[root@heitui ~]#fun1 () { hostname;date; } #定义函数
[root@heitui ~]#fun1 #调用函数
heitui
2023年 08月 19日 星期六 22:10:37 CST
脚本中使用函数,一定要在调用函数之前定义函数,否则会报错
如下:错误示范
正确示范:
[root@heitui ~]#declare -F # 查看函数列表
[root@heitui ~]#declare -f # 查看函数具体的内容
格式:unset 函数名
[root@heitui opt]#unset fun1
return表示退出函数并返回一个退出值,脚本中可以用$?变量表示该值
使用原则:
函数一结束就去返回值,应为$?变量只返回执行的最后一条命令的退出返回码
退出码必须是0-255,超出的值将为除以256取余
在调用函数的时候,直接在命令后面加上参数
格式:函数名 参数1 参数2 ...参数n
函数变量的作用范围:
创建专门存放函数的文件
计算阶乘
脚本如下:
#!/bin/bash
#
fact() {
if [ $1 -eq 0 -o $1 -eq 1 ]
then
echo 1
else
echo $[$1*$(fact $[$1-1])]
fi
}
fact $1
数组分为两种:
数组名和索引
索引的编号从0开始,属于数值索引
索引可支持使用自定义的格式,而不仅是数值格式,即为关联索引,bash 4.0版本之后开始支持
bash的数组支持稀疏格式(索引不连续)
#普通数组可以不事先声明,直接使用
declare -a ARRAY_NAME
#关联数组必须先声明,再使用
declare -A ARRAY_NAME
定义数组格式:
格式1:数组名=(value0 value1 value2 value3 ......)
格式2:数组名=([0]=value [1]=value1 [2]=value2 ....)
格式3:列表名="value0 value1 value2 value3 ...... "
数组名=($列表名)
格式4: 数组名[0]="value1"
数组名[1]="value2"
数组名[2]="value3"
查看普通数组下标:${!a[*]}
${a[*]} 与 ${a[@]}的区别
列出数组中有多少值 使用 ${#a[*]} 或者 ${#a[@]}
格式:${ARRAY[@]:offset:number}
# offset #要跳过的元素个数
# number #要取出的元素个数
# 取偏移量之后的所有元素
{ARRAY[@]:offset}
是建立在tcl(tool command language)语言基础上的一个工具,常被用于进行自动化控制和测试,解决shell脚本中交互的相关问题
expect默认是没有安装的,需要自己安装
[root@heitui ~]#yum install -y expect
expect使用格式:expect [选项] [ -c cmds ] [ [ -[f|b] ] cmdfile ] [ args ]
expect中相关命令
spawn 启动新的进程(监控,捕捉)
spawn passwd root
expect 从进程接收字符串
send 用于向进程发送字符串
exp_continue 匹配多个字符串在执行动作后加此命令
interact 允许用户交互expect eof
(1)脚本解释器
expect 脚本中首先引入文件,表明使用的事哪一种shell
#!/usr/bin/expect
(2)spawn
spawn 后面通常跟一个Linux执行命令,表示开启一个会话、进程,并跟踪后续交互信息
例: spawn passwd root
(3)expect
判断上次输出结果中是否包含指定的字符串,如果有则立即返回,否则就等待超时时间后返回;只能捕捉有swpan启动的进程输出;
用于接受命令执行后的输出,然后和期望的字符串匹配
(4)send
向进程发送字符串,用于模拟用户的输入:该命令不能自动回车换行,一般要加 \r (回车) 或者\ n
例子
方式一:
expect "密码" {send "abc123\r"} #同一行send部分要有{}
方式二:
expect "密码"
send "abc123\r" # 换行send部分不需要有{}
方式三:
expect 支持多个分支
expect #只要匹配了其中一个情况,执行相应的send 语句后退出该expect 语句
只匹配一次
expect
{
{"密码1" {send "abc123\r"}
{"密码2" {send "123123\r"}
{"密码3" {send "123456\r"}
}
(5) 结束符
expect eof
表示交互结束,等待执行结束,退回到原用户,与spawn对应
比如切换到root用户,expect 脚本默认的等待时间是10s,当执行王命令后,默认停留10s后,自动切回原用户.
interact
执行完成后保持交互状态, 把控制权交给控制台,会停留在目标终端而不是退回到原终端
需要注意的是,expect eof 与 interact 只能二选一。
(6)set
expect 默认的超时时间是10秒,通过set 命令可以设置会话超时时间,若不限制超时时间则应设置为-1
例子: set time out 30
(7) exp_continue
exp_continue 表示允许 expect 继续向下执行指令.
exp_continue附加于某个expect 判断选项之后,可以是该项被匹配后还能继续匹配expect 判断语句内的其他项。exp_continue类似于控制语句的continue语句。表示允许expect继续向下执行命令。
例如:
expect
{
"(yes/no)" {send "yes\r";exp_continue;}
"*password" {set timeout 300; send "abc123\r"}
}
注意:使用exp_continue时,如果跟踪像passwd这样输入密码后就结束进程的命令,expect {}外不要加上expect eof 因为spawn进程结束后悔默认向expect 发送eof,会导致后面的expect eof执行报错
(8)send_user
表示回显命令与echo相同
(9)接收参数(位置变量)
expect 脚本可以接受从bash命令行传递参数,使用 [lindex $argv n]获得。其中你从0开始,分别表示第一个,第二个,第三个.....参数
例子:
set hostname [lindex $argv 0] 相当于hostname=$1
set password [lindex $argv 1] 相当于passswd=$2
expect直接执行,需要expect命令去执行脚本
例子
#!/usr/bin/expect
spawn ssh 192.168.3.101 # ssh 远程登陆,使用spawn执行
expect {
"yes/no" { send "yes\n";exp_continue } # 捕捉yes/no,然后发送yes,\n起到回车的作用
"password" { send "123123\n" } # 继续捕捉password,然后发送magedu,\n起到回车的作用
}
interact # 结束符,结束后不返回原用户,停留在远程用户端上
脚本中使用参数的方式
set name [lindex $argv 0]
set pd [lindex $argv 1]