bash语言笔记
测试开发的shell水平
-
linux
- 文件操作
- 网络操作 netstat
- 系统数据分析 ps、top
- 数据分析能力(linux 三剑客)
-
shell语法、脚本、管道、环境变量
-
编写各种自动化脚本
- 环境部署自动化
- 测试用例调度自动化
- jenkins持续集成中辅助脚本
bash语言总览
-
变量
-
逻辑控制
-
shell环境
-
脚本应用
-
自动化
变量
变量的定义
a=1
b=daybreak
c="hello world"
d='你玩过"吃鸡"游戏吗'
e=`pwd`
- =左右两边不要有空格
- 双引号支持转义
- $ 开头的变量会被自动替换
变量的使用
echo $a
echo ${b}
echo "${a}"
- 使用
$var
或${var}
来访问变量。后者更严谨。$var_x
、${var_x}
是不同的 - 变量未定义也可以使用。引用未定义的变量 ,默认为空值
预定义变量
echo $PWD
echo $USER
echo $HOME
echo $PATH
数组变量
- 定义数组变量
array=(1,2,3)
array=(`ls`)
- 使用数组变量
echo ${array[index]}
echo ${array[*]} //获取数组中的所有元素
echo ${#array[*]} //获取数组的长度
变量类型
- 字符串 a="hello"
- 数字 b=1
- 布尔 c=true
数字型变量操作
- 计算
i=1;
echo $i
echo $(i+1)
- 更新
i=i+1;
echo $i
- 注意
- 只能进行整数运算
- 浮点数计算请使用
awk 'BEGIN{print 1/3}'
- 格式化显示可以换用
awk'BEGIN{print("%.2f\n,1/3")}'
字符串操作
-
取值
${string:start:lenght}
从变量中提取字串a="hello" echo ${a:0:3} #结果为hel
${#string}
获取字符串长度 -
掐头去尾与内容替换
${string#pattern}
${string##pattern}
#表示掐头
${string%pattern}
${string%%pattern}
%表示去尾
${string/pattern/替换的string}
${string//pattern/替换的string}
/表示替换
使用#或##、%或%%、/或//的区别:最短匹配或最长匹配模式
布尔变量
- true
- false
- 命令执行返回值
$?
命令
echo $?
#任何命令执行都有一个返回值,0表示正确,非0表示错误
判断类型
-
算术判断
-eq
等于[2 -eq 2]
-ne
不等于
-gt
大于
-ge
大于等于
-lt
小于
-le
小于等于 -
字符串判断
[string1=string2]
两字符串相同,则结果为真
[string1!=string2]
两字符串不相同,则结果为真
[-n "$var" ]
如字符串不是空,则结果为真
[-z "$var" ]
如字符串是空,则结果为真
[["xxxx"==x*] ]
在表达式中表示0或者多个字符
[[xxx==x??]]
在表达式中表示单个字符- 在引用变量的时候要记得加双引号
[-z "$var" ]
否则当a未定义时会语法报错
- 在引用变量的时候要记得加双引号
-
逻辑判断
[2 -ge 1 -a 3 -ge 4];echo $?
-a and 与
[2 -ge 1 -o 3 -ge 4];echo $?
-o or 或
[2 -ge 1 && 3 -ge 4];echo $?
与
[2 -ge 1 || 3 -ge 4];echo $?
或
[!2 -ge 1 ];echo $?
非 -
shell内置判断
-e file
如果文件存在,则结果为真
-d file
如果文件是一个子目录,则结果为真
-f file
如果文件是一个普通文件,则结果为真
-r file
如果文件可读,则结果为真
-s file
如果文件的长度不为0,则结果为真
-w file
如果文件可写,则结果为真
-x file
如果文件可执行,则结果为真-
[[]]
是[]
的拓展语法,在老的sh里并不支持。推荐用[]
-
逻辑控制
If结构
-
if [condition];then...;fi
-
if [condition];then...;else...;fi
-
if [condition];then...;elif...;fi
-
简单的逻辑可以使用&& ||去替代
-
条件可以用命令返回值代替
for 循环
- 语法
for((i=0;i<10;i++));do echo $i;done
- for遍历循环
用于递归数组和递归以空格隔开的字符串,或者某个命令的返回值for f in $array[*]; do ...; done
ss="aa bb cc dd";for x in $ss;do echo $x;done for x in `ls`;do echo $x;done ss=(aa bb cc "sss dd");for x in "${ss[@]}";do echo $x;done
while循环
- 语法
i=0;
while [$i -lt 3];
do echo $i;
((i=i+1));
done
- 一行行读取文件
while read line;
do echo $line;
done<tmp/tmp
退出控制
- return 函数返回
- exit 脚本进程退出
- break 退出当前循环
- continue 跳过当前的循环,进入下一个循环
shell环境
shell环境概念
- bash下还可以再重新启动一个shell,这个shell是sub shell,原shell会复制自身给他。在sub shell中定义的变量,会随着sub shell的消亡而消亡。
- () 子shell中运行
- $(ls) 表示执行ls后的结果,与``作用一致,不过可以嵌套
- {} 当前shell中执行
- $$ 当前脚本执行的pid
- & 后台执行
- $! 运行在后台的最后一个作业的pid(进程id)
shell环境变量
- shell首先是一个工作环境,有很多变量可以提供我们使用
- set可以获得当前的所有变量
- env可以获得可以传递给子进程的变量
- export aa=bbb 把私有变量导出
shell输入输出
- read用来读取输入,并赋值给变量
- echo print可以输出简单变量
- >file 将输出重定向到另一个文件
- >>表示追加 等价于tee -a
- | 表示管道,也就是前一个命令的输出传入下一个命令的输入
文件描述符
- 输入文件-标准输入0
- 输出文件-标准输出1
- 错误输出文件-标准错误2
- curl
- 使用2>&1>/tmp/tmp</tmp/tmp
脚本编写
-
注释
#
以后的语句,shell不会解析
多行注释可以采用:<<
-
传入参数
-
$0
表示执行的程序,是相对于执行目录的路径 -
$1,$2,$3
分别表示第几个参数,默认shell只支持9个参数,使用shift可以传递更多的参数 -
$@,$*
表示所有参数,不含$0
-
${#*}
和${#@}
表示位置参数的个数 - 通过
${*:1:3},${*:$#}
来表示多个参数
-
-
函数
- 语法
[function] name() { .. }
- function 可以省略。除了可以在脚本文件中使用函数外,还可以shell中定义。这些定义在本次shell结束后消失
- 如果没有return,返回值是最后一句指令的返回值
-
执行
方式一:
chmod u+x xxx.sh;
./xxx.sh
方式二:
bash xxx.sh #这种方式会开启一个sub shell
方式三:
source xxx.sh #在当前shell中执行
- eval 可以执行shell原义语句
- exec 尽量不要使用,这会破坏当前的shell
- 调试
-
bash -x
读取每一句并执行,可以方便的看到执行的语句 -
set -x
在当前shell中调试,set+x还原 - trap 相关的信号,包括ERR DEBUG等
- trap
cmd
ERR
-
三剑客
-
grep 数据查找定位(检索)
-
awk 数据切片
-
sed 数据修改
bash自动化
自动化交互
- 批处理并不等于自动化
- 让交互程序实现非交互执行
- 借用第三方工具expect
自动输入方法
-
<<
文档字符串。可以实现对序列化输入的操作自动化 - 管道方式 echo 'password' |passwd
- 去掉sudo密码提示,也可以通过修改sudoer文件
- 去掉ssh密码,也可以通过添加认证
- except
linux命令
测试开发应该达到的水平:
- 文件操作
- 网络操作 netstat
- 系统数据分析 ps、top
- 数据分析能力(linux 三剑客)
一键搭建web网站
python -m CGIHTTPServer 8080
python3 -m http.server
gnuplot 绘图
- 通过管道读取数据并绘图
更多工具
-
文件系统
- find、ls、chmod、chown
-
系统性能统计命令
- ps netstat top vmstat free
- netstat -tlnp
- netstat -tnp
- /proc 目录保存了所有进程的性能数据
Andriod常用命令
-
adb
- adb devices
- adb kill-server
- adb tcpip
- adb connect
- adb logcat
- adb bugreport
-
模拟器的命令
- 进入emulator所在目录
- emulator -list-avds
- emulator@avd
-
adb shell
adb shell本身就是一个linux shell,可以调用所有的Android内置命令
adb shell- adb shell dumpsys
- adb shell pm
- adb shell am
- adb shell ps
- adb shell monkey
iOS命令
(以后讲)
快速搜索历史输入
ctrl+r
bck-i-search:
ctrl+a 行首
ctrl+e 行尾
实战
提取对外连接的ip数量
-
题目解析
- 目标对象是对外连接的ip,从ngnix上提取
- netstat命令用于显示与IP、TCP、UDP和ICMP协议相关的统计数据,一般用于检验本机各端口的网络连接情况。
-
bash
#使用命令netstat 参数-ntp
netstat -ntp
#删掉多余的数据行第一行、第二行, 使用sed 1,2d
netstat -ntp | sed 1,2d
#提取内容第五部分,使用awk '{print $5}'
netstat -ntp | sed 1,2d | awk '{print $5}'
#去掉端口号,使用awk -F ':' '{print $1}'
netstat -ntp | sed 1,2d | awk '{print $5}' | awk -F ':' '{print $1}'
#使用sort进行排序,使数据看上去规整一些
netstat -ntp | sed 1,2d | awk '{print $5}' | awk -F ':' '{print $1}' | sort
#去除重复的ip,使用uniq 命令删除重复的行,参数-c显示每个ip出现的次数
netstat -ntp | sed 1,2d | awk '{print $5}' | awk -F ':' '{print $1}' | sort | uniq -c
#使用wc获取ip的数量,参数-l统计行数
netstat -ntp | sed 1,2d | awk '{print $5}' | awk -F ':' '{print $1}' | sort | uniq -c | wc -l
提取testhome首页精华帖的点赞数
-
题目解析
- 目标对象是testhome首页所有精华帖的点赞数量
- 使用curl命令可以模拟http请求
-
bash
#使用curl命令模拟http请求
curl https://testerhome.com
#讲请求返回的错误信息仍进黑洞/dev/null
curl https://testerhome.com 2>/dev/null
#通过开发者工具-检查元素可以查看到精华帖后面的一个钻石icon属于class="fa fa-diamond"
curl https://testerhome.com 2>/dev/null | grep "fa fa-diamond"
#精华帖的list在钻石icon的上一行,使用参数-b1,代表before1行
curl https://testerhome.com 2>/dev/null | grep -b1 "fa fa-diamond"
#实际需要的是精华帖列表那一行,通过该行的关键字筛选
curl https://testerhome.com 2>/dev/null | grep -b1 "fa fa-diamond" | grep "href"
#每个精华帖的href不一样,同时也是每个精华帖的路径,使用awk进行切割
curl https://testerhome.com 2>/dev/null | grep -b1 "fa fa-diamond" | grep "href" | awk -F '\"' '{print $4}'
#因为article是文章集,所以只要topic开头的
curl https://testerhome.com 2>/dev/null | grep -b1 "fa fa-diamond" | grep "href" | awk -F '\"' '{print $4}' | grep "topics"
#进入精华帖详情页去获取点赞数,精华帖详情页的路径https://testerhome.com+上面获取的路径列表
#一行行读取列表,使用while read line;do echo $line;done
curl https://testerhome.com 2>/dev/null | grep -b1 "fa fa-diamond" |grep "href"|awk -F '\"' '{print $4}'| grep "topics"| while read line;do curl https://testerhome.com$line 2>/dev/null;done
#进入了精华帖详情页,根据开发者工具-检查元素可以发现记录点赞数的class是 "fa fa-heart"
curl https://testerhome.com 2>/dev/null | grep -b1 "fa fa-diamond" |grep "href"|awk -F '\"' '{print $4}'| grep "topics"| while read line;do curl https://testerhome.com$line 2>/dev/null;done |grep "fa fa-heart"
#除了话题点赞数之外,还有回复的点赞数,使用 grep "data-type=\"Topic\""去掉回复的点赞数的行
curl https://testerhome.com 2>/dev/null | grep -b1 "fa fa-diamond" |grep "href"|awk -F '\"' '{print $4}'| grep "topics"| while read line;do curl https://testerhome.com$line 2>/dev/null;done |grep "fa fa-heart" |grep "data-type=\"Topic\""
#通过awk分割后展示topic、topicid 、点赞数
curl https://testerhome.com 2>/dev/null | grep -b1 "fa fa-diamond" |grep "href"|awk -F '\"' '{print $4}'| grep "topics"| while read line;do curl https://testerhome.com$line 2>/dev/null;done |grep "fa fa-heart" |grep "data-type=\"Topic\""|awk -F '\"' '{print $8,$10,$4}'
#另一种显示:在curl详情页时把点赞数记为一个变量
curl https://testerhome.com 2>/dev/null | grep -b1 "fa fa-diamond" |grep "href"|awk -F '\"' '{print $4}'| grep "topics"| while read line;do count=$(curl https://testerhome.com$line 2>/dev/null |grep "fa fa-heart" |grep "data-type=\"Topic\""|head -1|awk -F '\"' '{print $4}');echo "$line 点赞数是: $count";done
从nginx log中提取数据并可视化
- nginx log在/tmp目录下
- ls -l *.log搜索日志
- bash
#确定目标日志是1206_2.log
cat 1206_2.log
#使用sed提取某个时间段的日志
#-n选项:只显示匹配处理的行(否则会输出所有)
cat 1206_2.log | sed -n '/07:48:00/,/07:52:00/p'
#使用gnuplot插件进行数据展示(gnuplot不会,随便看看吧)
cat 1206_2.log | sed -n '/07:48:00/,/07:52:00/p' | gnuplot -e "set terminal dumb;set datafile |separator ' ';set timefmt '[%d/%b/%Y:%H%:%M:%S]';set ydata time;set format y '%H%M'%S;|plot '<cat' using 8:4 with lines"