文章目录
shell脚本—实际上手
符号
双引号" ":允许通过$符号引用其他变量值
单引号' ':禁止引用其他变量值,$视为普通字符、`..`和$(..)作用相同
"$name" 弱引用,其中的变量引用会被替换为变量值
'$name' 强引用,其中的变量引用不会被替换为变量值,而保持原字符串
反撇号` `:命令替换,提取命令执行后的输出结果
感叹号!:表示历史替换
!!:上一个命令(会执行)
!n:表示历史中的第n个命令
小括号():在正则表达式中匹配并记住匹配的子串;在Shell脚本中创建子shell或定义数组
中括号[]:在正则表达式中定义字符集,匹配方括号中的任意一个字符;在Shell脚本中,用于数组索引和条件测试
双小括号(()):算术扩展和算术运算
双中括号[[]]:条件测试
—read 获取输入内容
-p prompt:指定提示符,用于提示用户输入数据
-a array:将输入数据存储到一个数组中。
方法-:
read -p "提示信息" 变量名
echo$变量名
方法二:
echo -n "提示信息”
read 变量名
echo$变量名
read -a #数组输入
运算
## 整数变量的运算
格式:expr 变量1 运算符 变量2 [运算符 变量3]
运算符
+ 加法
- 减法
\* 乘法
/ 除法
% 取余
常用的运算表达式:
i=$(expr 12 \* 5)
i=$((12*5))
i=$[12*5] #这种用法已弃用
let i=12*5
bc 将数学表达式计算结果输出到标准输出或保存到文件中
## 非整数运算
scale:保留几位小数
-a:&&
-o:||
常用的操作符:
-eq:等于 ==
-ne:不等于 !=
-gt:大于 \>
-lt:小于 \<
-le:小于等于 <=
-ge:大于等于 >=
$> /dev/null 放入null垃圾桶===不在前台显示
条件测试操作
Shell环境根据命令执行后的返回状态值($?)来判断是否执行成功,当返回值为0(真true)时表示成功,返回值为非0值(假false)时表示失败或异常。
—test
对特定条件进行测试,并根据返回值来判断条件是否成立
格式一:test 条件表达式
格式二:[ 条件表达式 ] #方括号“[”或“]”与条件表达式之间需要至少一个空格进行分隔
—文件测试
格式:[ 操作符 文件或目录 ]
常用的操作符:
-e:测试目录或文件是否存在(Exist)。
-d:测试是否为目录(Directory)。
-f:测试是否为文件(File)。
-r:测试当前用户是否有权限读取(Read)。
-w:测试当前用户是否有权限写入(Write)。
-x:测试是否设置有可执行(Excute)权限。
—字符串比较
格式1:
[ 字符串1 = 字符串2 ] 或 [ 字符串1 == 字符串2 ]
[ 字符串1 != 字符串2 ]
格式2:
[ -z 字符串 ] #检查字符串是否为空(Zero),对于未定义或赋予空值的变量将视为空串
[ -n 字符串 ] #检查是否有字符串存在
—逻辑测试
格式1:[ 表达式1 ] 操作符 [ 表达式2 ]
格式2:命令1 操作符 命令2
常用的操作符:
-a或&& :逻辑与,“而且”的意思,前后条件需都成立
-o或|| :逻辑或,“或者”的意思,只需前后条件中一个成立
! :逻辑否
常用转义字符
前置
echo -n 表示不换行输出
echo -e 输出转义字符,将转义后的内容输出到屏幕上 echo -ne
只有加了-e才能执行下面的转义符
常用的转义字符
\b 转义后相当于按退格键(backspace),但前提是"\b"后面存在字符;"\b"表示删除前一个字符,"\b\b"表示删除前两个字符。
\c 不换行输出,在"\c"后面不存在字符的情况下,作用相当于 echo -n; 但是当"\c"后面仍然存在字符时,"\c"后面的字符将不会被输出。
\n 换行,被输出的字符从"\n"处开始另起一行。
\f 换行,但是换行后的新行的开头位置连接着上一行的行尾;
\v 与\f相同;
\t 转以后表示插入tab,即横向制表符;
\r 光标移至行首,但不换行,相当于使用"\r"以后的字符覆盖"\r"之前同等长度的字符;但是当"\r"后面不存在任何字符时,"\r"前面的字符不会被覆盖
\\ 表示插入"\"本身;
条件
if语句
单分支 if 语句
if 条件测试操作
then
命令序列
fi
双分支 if 语句
if 条件测试操作
then
命令序列 1
else
命令序列 2
fi
多分支 if 语句
if 条件测试操作 1
then
命令序列 1
elif 条件测试操作 2
then
命令序列 2
[else]
[命令序列 3]
fi
case 语句
case 变量值 in
模式 1)
命令序列 1
;;
模式 2)
命令序列 2
;;
……
*)
默认命令序列
esac
注意特点
case 行尾必须为单词“in”,每一模式必须以右括号“)”结束。
双分号“;;”表示命令序列的结束。
模式字符串中,可以用方括号表示一个连续的范围,如“[0-9]”;还可以用竖杠符号“|”表示或,如“A|B”。
“*)”表示默认模式,其中的*相当于通配符。
循环
for
格式一
for i $()
do
done
格式二 (类C语言格式)
for ((i=0;i>=5;i++))
do
done
跳出循环
continue 在循环内部跳过本次循环并继续下一次循环
continue 2 跳过两层循环,并继续下一次循环
break 直接结束此次循环
break n 结束n次循环
====================
# 死循环(无限循环)
for ((;;))
do
done
while
while [ 判断条件]
do
执行动作
done
====================
# 死循环(无限循环)
第一种
while [1 -eq 1] 判断条件写一个永久为真的条件
do
done
第二种
while true 直接写判断条件为真
do
done
第三种
while : 判断条件为冒号也表示死循环
do
done
until
until [ 条件测试操作 ]
do
判断式/命令序列
done
function 函数
function 函数名() {
主体
return 返回值
}
函数返回值
return表示退出函数并返回一个退出值,脚本中可以用 $? 变量显示该值
使用原则:
1、函数一结束就取回返回值,因为 $? 变量只返回执行的最后一条命令的退出状态码
2、退出状态码必须是0-255,超出时值将为除以256取余 exit 0
数组
格式一
数组名=(value0 valuel value2 …)
例:
arr=(30 20 10 60) #数组中的元素值
其中:
30为索引0
20为索引1
10为索引2
60为索引3
以此类推
格式二
数组名=( [0]=value [1]=value [2]=value …)
例:
arr=([0]=1 [1]=2 [2]=3)
格式三
列表名=“value0 valuel value2 …”
数组名=($列表名)
例:
list="1 2 3 4"
arr=($list)
格式四
数组名[0]=“value0”
数组名[1]=“value1”
数组名[2]=“value2”
例:
arr3[0]="1
arr3[0]="2
arr3[0]="3
数组中总共多少个元素====长度
arr1=(1 2 3 4 5)
echo ${#arr1[*]}
-------5
读取某下标赋值
arr1=(1 2 3 4 5)
echo ${arr1[0]}
-------1
echo ${arr1[3]}
-------4
数组遍历
#!/bin/bash
arr5=(1 2 3 4 5)
for i in ${arr5[*]} 或 for i in ${arr5[@]} #使用*或者@表示都可以
do
echo $i
done
-----1
-----2
-----3
-----4
-----5
数组切片
取数组中的某一段的元素的值
${数组名[@或*]}:起始位置(起始索引):长度
arr1=(1 2 3 4 5)
echo ${arr1[*]:0:2}
-------1 2
echo ${arr1[*]:2:2}
--------3 4
数组替换
临时替换或者永久替换
$(数组名[@或*]/查找字符/替换字符}
arr1=(1 2 3 4 5)
#临时替换
echo ${arr1[*]/4/66} #将数组arr1中的元素4替换为66
-----1 2 3 66 5
echo ${arr1[*]} #原来的数组中的元素的值并不会改变
--------1 2 3 4 5
#永久替换
方法一:可通过重新赋值实现
arr1=(${arr1[*]/4/66})
echo ${arr1[*]}
--------1 2 3 66 5
方法二:直接修改
arr1[3]=44
echo ${arr1[*]}
--------1 2 3 44 5 6
删除数组
使用unset删除数组
unset arr1
echo ${arr1[*]}
删除数组中的某个索引对应的元素的值
arr1=(1 2 3 4 5)
echo ${arr1[*]}
-------1 2 3 4 5
unset arr1[2] #删除索引2的对应的元素值
echo ${arr1[*]}
--------1 2 4 5
追加数组中的元素
方法一:
arr1=(1 2 3 4 5)
echo ${arr1[*]}
-------1 2 3 4 5 #这是原始的数组中的各元素的值,一直到索引4结束
arr1[5]=6 #此时追加数组索引5对应的元素值为6
echo ${arr1[*]}
--------1 2 3 4 5 6 #发现数组的索引5位置上的元素已经追加成功
方法二:
arr1[${#arr1[*]}]=7
#当数组的元素非常多的时候,可以直接使用数组的长度作为自己将要追加的索引的值,这样就可以直接追加元素了。
因为原始数组的索引是从0开始的,所以用长度减去1就是原始数组的最后的以为索引值了,
那么自己将要添加的值应该是原始索引值的后一位,那显然就等于数组的长度值了。
echo ${arr1[*]}
-------1 2 3 4 5 6 7
方法三:
arr1=(1 2 3 4 5)
echo ${arr1[*]}
-------1 2 3 4 5
arr1=("${arr1[@]}" 6 7)
echo ${arr1[*]}
----------1 2 3 4 5 6 7
双引号不能省略,否则,当数组arr1中存在包含空格的元素时会按空格将元素拆分成多个。
不能将“@“替换为“*”,如果替换为"*",
不加双引号时与"@"的表现一致,加双引号时,会将数组arr1中的所有元素作为一个元素添加到数组中。
可以简单的理解为:用*号是作为一个整体,而用@还是单个的个体。
$*、$@不加双引号时表现一致;加双引号时,$*会将所有参数作为一个整体。
"$*" 为 “1 2 3” (作为一个整体使用)
"$@" 为“1” “2” “3” (分别作为单个的个体使用)
"$#" 为3 (表示参数的数量,也可以叫做长度)
方法四:
arr1=(1 2 3 4 5)
echo ${arr1[*]}
------1 2 3 4 5
arr1+=(11 22) #追加,待添加元素必须用“()"包围起来,并且多个元素用空格分隔
echo ${arr1[*]}
------1 2 3 4 5 11 22
调试
set -x 开启调试模式
set +x 关闭调试模式
脚本调试debug
bash -n 脚本名称--------检查语法错误
bash -x 脚本名称--------检查逻辑错误
免交互
EOF—标记
语法格式:
命令 <<标记
...
内容 #标记之间是传入内容
...
标记
注意事项:
标记可以使用任意合法字符(通常为EOF)
结尾的标记一定要顶格写,前面不能有任何字符
结尾的标记后面也不能有任何字符(包括空格)
开头标记前后的空格会被省略掉
例:
通过 read 命令接收输入并打印,输入值是两个 EOF 标记之间的部分,作为变量 i 的值
read i <<EOF
>Hi
>EOF
echo $i
通过 passwd 给用户设置密码
passwd lisi <<EOF
>abc1234 #这两行是输入的密码和确认密码
>abc1234
>EOF
cat <<EOF>test.txt
> hello world
> i im zhangsan
> EOF
[root@localhost ~]#cat test.txt
tee命令重定向输出加标准输出
[root@localhost ~]#tee test2.txt <<EOF
> this is tee test
> EOF
this is tee test
[root@localhost ~]#cat test2.txt
#tee命令有标准输出的作用,可以直接重定向输入到文件中
在写入文件时会先将变量替换成实际值,再结合 cat 命令完成写入
#!/bin/bash
file="test1.txt"
i="school"
cat > $file <<EOF
I am going to $i
EOF
cat EOF1.txt
整体赋值给变量,然后通过 echo 命令将变量值打印出来
#!/bin/bash
var="Great! I am going to school!"
myvar=$(cat <<EOF
This is Line 1.
Today is Monday.
$var
EOF
)
echo "$myvar"
关闭变量替换的功能,按照字符原本的样子输出,不做任何修改或替换
#!/bin/bash
var="Great! I am going to school!"
myvar=$(cat <<'EOF' #对标记加单引号,即可关闭变量替换
This is Line 1.
Today is Monday.
$var
EOF
)
echo $myvar #这是会输出什么呢?就是$var
去掉每行之前的 TAB 字符
#在标记前加“-”,即可抑制各行首TAB
cat <<-'EOF'
KY27
ky28
EOF
#注意一点,用空格无效
Expect
#!/usr/bin/expect expect 脚本中首先引入文件,表明使用的是哪一个 shell。
常见转义字符
\n:表示换行符。
\t:表示制表符。
\r:表示回车符。
\b:表示退格符。
spawn
spawn 后面通常跟一个Linux执行命令,表示开启一个会话、启动进程,并跟踪后续交互信息。
spawn 命令
expect
判断上次输出结果中是否包含指定的字符串
只能捕捉由spawn启动的进程的输出
send
模拟用户的输入
该命令不能自动回车换行,一般要加\r(回车)或者\n
组合
格式一
expect "关键字" {send "用户输入\r"} #\r是回车
格式二
expect "关键字"
send "用户输入\r"
格式三
expect #只要匹配了其中一个情况,执行相应的send语句后退出该expect语句
{
"关键字1" {send "用户输入\r"}
"关键字2" {send "用户输入\r"}
"关键字3" {send "用户输入\r"}
}
结束符
expect eof 表示交互结束,等待执行结束,退回到原用户,与spawn对应
interact 执行完成后保持交互状态,把控制权交给控制台,会停留在目标终端而不会退回到原终端
interact后的命令不起作用
expect eof 与 interact 只能二选一
附加
set
expect 默认的超时时间是 10 秒
若不限制超时时间则应设置为-1
例:set timeout 5
exp_continue
附加于某个 expect 判断项之后,可以使该项被匹配后,还能继续匹配该 expect 判断语句内的其他项
允许 expect 继续向下执行指令
分号;隔开
注意:使用exp_continue时,如果跟踪像 passwd 这样的输入密码后就结束进程的命令
expect{}外不要再加上expect eof
因为spawn进程结束后会默认向expect发送eof,会导致后面的 expect eof 执行报错
send_user
send_user 表示回显命令,相当于 echo打印的功能
接收参数
expect 脚本可以接受从bash命令行传递的参数
使用[lindex $argv n]获得。其中n从0开始,分别表示第一个,第二个,第三个....参数
类似与位置变量,用法相同
例:
set hostname [lindex $argv 0] 相当于 hostname=$1
set password [lindex $argv 1] 相当于 password=$2
注意:expect脚本不能通过bash、source、.
来执行(因为这三种方式是调用shell解释器),只能通过绝对路径或相对路径来执行。