变量
$1 执行脚本后跟的第一个位置参数
$2 执行脚本后跟的第二个位置参数
$3 执行脚本后跟的第三个位置参数
$* 所有位置参数
$0 当前所在的脚本名或进程
$# 所有位置参数的个数
$$ 随机的进程号PID号,保存当前运行进程号
$? 判断上一条指令是否执行成功,成功显示0,失败显示非0
局部变量 ,仅当前解释器进程中可以使用的变量
全局变量,解释器进程产生的子进程也可以使用的变量
export b=20 #定义一个 全局变量
export -n a #取消变量的全局效果
表达式
[root@test ~]# a=1
[root@test ~]# b=2
[root@test ~]# [ $a == $b ] #变量前后两边都有空格
[root@test ~]# echo $?
1
$[ ] 计算
]# echo $[a+b] #不需要空格
2.数字的条件判断 equal greater lesser than
-eq 是否相等 -ne 是否不等 -gt 是否大于
-ge 是否大于等于 -lt 是否小于 -le 是否小于等于
3.文件的条件、权限判断 加 ! 取反,带空格 ! -e
-e 判断文件是否存在,不关心文件类型
-f 判断文件是否存在且必须为文件
-d 判断文件是否存在且必须为目录
-r -w判断当前用户对文件是否有读、写权限
-x 判断当前用户对文件执行,目录是否能进入的权限
4.逻辑符号&& ||
&& 之前指令成功才执行之后的指令
|| 之前指令失败才执行之后的指令
; 之前指令前后没有关系
单分支 if ;then fi
#!/bin/bash
if [ ! -d /opt/xyz ] ;then
mkdir /opt/xyz
fi
双分支 if ;then else fi
#!/bin/bash
if [ ! -d /opt/xyz ] ;then
mkdir /opt/xyz
else
mkdir /opt/abc
fi
多分支 elif… else
read -p "请输入你的成绩" n
if [ $n -ge 90 ];then
echo "优秀"
elif [ $n -ge 80 ];then
echo "良好"
elif [ $n -ge 60 ];then
echo "及格"
else
echo "hehe"
fi
for 循环
#!/bin/bash
a=0
b=0
for i in {1..10}
do
ping -c 3 -i 0.5 -W 1 192.168.4.$i &>/dev/null
if [ 0 -eq $? ];then
echo "192.168.4.$i tong"
let a++
else
echo "192.168.4.$i bu tong"
let b++
fi
done
echo "$a台ok,$b台not ok"
for循环嵌套
#!/bin/bash
for i in a b
do
for j in x y
do
echo $i $j
done
done
##echo 四次 a x,a y,b x,b y
while循环,可以实现无限循环
#!/bin/bash
while [ 1 -eq 1 ] #永远正确,while ture
do
echo abc
sleep 1 #休息1秒
done
#!/bin/bash
x=1
while [ $x -le 5 ] #通过条件测试决定执行任务的次数
do
echo abc
sleep 1
let x++ #增长+1
done
exit 可以终止循环,但同时也终止整个脚本
break 可以终止循环,继续循环之后的任务
continue 可以终止当前循环,继续下一次循环
#!/bin/bash
x=0
while :
do
read -p "求和,结束输入0 " n
[ -z $n ] && echo "error" && continue #空值时,要求重新输入
[ $n -eq 0 ] && break #0时,终止输入
let x+=n
done
echo "和为:$x"
3.case 分支
功能类似if,不如if强大 语句比较精简。适合用来编写控制服务的工具
#!/bin/bash
case $1 in
a)
echo aaa;;
b)
echo bbb;;
*)
echo "请输入a或b"
esac
]# bash case.sh b
bbb
shell函数
#!/bin/bash
colour(){
echo -e "\033[$1m$2\033[0m"
}
colour 31 abcd
colour 32 hehe
colour 33 xixi #调用函数colour,$1 颜色 $2 内容,输出有颜色的内容
]# bash colour.sh
字符串处理
${变量名 : 截取的起始位 : 长度}
[root@test ~]# a=123456
[root@test ~]# echo ${a:2:2}
34
[root@test ~]# echo ${a:2:1}
3
[root@test ~]# echo ${a::1}
1
字符串的替换 ${变量名/old/new}
]# a=123123
]# echo ${a/2/6} #替换第一个2
163123
]# echo ${a//2/6} #全部2替换
163163
]# echo ${a/2/} #新内容不写时有删除作用
13123
]# echo ${a//2/} #删除所有2
1313
字符串的删除
${ # } 从左往右掐头删除 ${ % } 从右往左去尾删除
]# a=123456
]# echo ${a#123}
456
]# a=abcdefghfd
]# echo ${a#*f} # *f 任意字符到第一个f的字符串
ghfd
]# echo ${a##*f} # ##*f 删除到最后一个f
d
]# a=abcdefghfd
]# echo ${a%f*} # 删除尾部的f及后面所有
abcdefgh
[root@svr7 opt]# echo ${a%%f*} # %%*f 删除所有f
abcde
正则
^ 匹配行首
$ 匹配行尾
[] 集合,匹配集合中的任意单个亨符
[^] 对集合取反
. 匹配任意单个字符
\* 匹配前一个字符任意次数〔[*不允许单独使用]
\\{n,m\\ } 匹配前一个字符n到m次
\\{n\\} 匹配前一个字符n次
\\{n, \\ } 匹配前一个字符n次及以上
\\(\\) 保留
grep "root" user #找root 标准 带上" "
grep "[root]" user #找rot任意一个字符
grep "[rot]" user #效果同上
grep "[a-z]" user #找所有小写字母
grep "[A-Z]" user #找所有大写字母
grep "[a-Z]" user #找所有字母
grep "[0-9]" user #找所有数字
grep "[^0-9]" user #找除了数字的内容,集合中[ ]的^代表取反
grep "[^a-Z0-9]" user #找特殊符号,非字母数字
grep "r..t" user #找rt之间有2个任意字符的行
grep "r...t" user #找rt之间有3个任意字符的行,没有匹配内容,就无输出
grep "*" user #错误用法,*号是匹配前一个字符任意次,不能单独使用
grep "ro*t" user #找rt,中间的o有没有都行,有几次都行
grep "." user #找任意单个字符,文档中每个字符都可以理解为任意字符
grep ".*" user #找任意,包括空行 相当于通配符*仅在正则表达式中这样写 .*
grep "ro\{1,2\}t" user #找rt,中间的o可以有1~2个
grep "ro\{2,4\}t" user #找rt,中间的o可以有2~4个
grep "ro\{2\}t" user #找rt,中间的o只有2个
grep "ro\{3\}t" user #找rt,中间的o只有3个
grep "ro\{3,\}t" user #找rt,中间的o可以有3个以及3个以上
grep "ro\{1,\}t" user #找rt,中间的o可以有1个以及1个以上
扩展正则列表 grep -E 、或 egrep
\+ 最少匹配一次
? 最多匹配一次
{n,m} 匹配n到m次
() 组合为整体,保留或者
\\b 单词边界
egrep "ro{1,}t" user #egrep支持扩展正则,或者grep -E
egrep "ro+t" user #效果同上,最精简
grep "roo\{0,1\}t" user #第二个o要出现0~1次
egrep "roo{0,1}t" user #效果同上
egrep "roo?t" user #效果同上,最精简
grep "ro\{2\}t" user #找o出现2次的
egrep "ro{2}t" user #效果同上
egrep "^root|^bin" user #找root或者以bin开头的行
egrep "^(root|bin)" user #效果同上
sed
选项: -n 屏蔽默认输出 -r 支持扩展正则 -i 写入文件
参数: p输出 d删除行 s替换 三个同符号# $ % ^即可做替换符
sed -n '1p' user #输出第1行
sed -n '2p' user #输出第2行
sed -n '3p' user #输出第3行
sed -n '2,4p' user #输出第2~4行
sed -n '2,+1p' user #输出第2行以及后面1行
sed -n '2p;4p' user #输出第2行,第4行
sed -n '/^root/p' user #在sed中使用/正则表达式/输出以root开头的行
sed -n 's/root/test/p' user #替换每行的第一个root
sed -n 's/root/test/gp' /etc/passwd #替换每行的所有root
sed 's#/bin/bash#/sbin/sh#' user #更换替换符号,三个同符号# $ % ^
高级使用
sed -n 's/.//p' test #替换第1个字符为空
sed -n 's/.//2p' test #替换第2个字符为空
sed -n 's/.//2; s/.$//p' test #替换第2个、最后一个字符为空
sed -n 's/[0-9]//g' test # 找到任意数字,然后都替换为空
( ) 保留,相当于复制 \1 代表粘贴
sed -r 's/([A-Z])/copy\1/g' test #找到文档中所有行的所有大写字母,并在前面添加copy
a行下追加 i行上添加 c替换整行
sed 'a 666' test #所有行的下面追加666
sed '1a 666' test #第1行的下面追加666
sed '/root/a 666' test #有root的行的下面追加666
sed 'i 666' test #所有行的上面添加666
sed '1i 666' test #第1行的上面添加666
sed '2i 666' test #第2行的上面添加666
sed '/root/i 666' test #有root的行的上面添加666
sed 'c 666' test #替换所有行为666
sed '1c 666' test #替换第1行为666
sed '/^bin/c 666' test #替换以bin开头的行为666
awk常规使用
选项 -F 定义分隔符 指令 print
内置变量 $1第一列 $2第二列 $3 …. $0所有列 NR 行号 NF列号
awk '{print}' test.txt #输出所有行的内容
awk '/beijing/{print}' test.txt #输出有beijing的行的内容
awk '/beijing$/{print}' test.txt #输出以beijing结尾的行的内容
awk '{print $1}' test.txt #输出所有行的第1列
awk '{print $3}' test.txt #输出所有行的第3列
awk '/the/{print $3}' test.txt #输出有the的行的第3列
awk '/the/{print NR}' test.txt #输出有the的行的行号
awk '{print NR}' test.txt #输出所有行的行号
awk '{print NF}' test.txt #输出所有行的列号
awk '{print $0,NR}' test.txt #输出所有列然后空格,输出行号
awk -F: '{print $1}' user #使用-F:定义分隔符为冒号,输出第1列
awk -F: '{print $3}' user
awk -F: '{print $1" 的解释器是 "$7}' user #输出常量用""
awk 过滤时机: BEGIN{ } { } END{ }
awk 'BEGIN{print "User\tUID\tHome"}' #BEGIN任务,其中\t是可以实现tab键(空格、对其)的效果
awk -F: '{print $1"\t"$3"\t"$6}' user #逐行任务
awk 'END{print "总计"NR"行"}' user #END任务
将3个任务整合在一起
awk -F: 'BEGIN{print "User\tUID\tHome"}{print $1"\t"$3"\t"$6}END{print "总计"NR"行"}' user
2.awk中的条件
1)使用正则作为条件
/ ^ / 为首 / $/ 结尾 ~ 包含 !~ 不包含
awk -F: '/bin/{print}' user #输出含有bin的行,无论bin在第几列
awk -F: '$6~/bin/{print}' user #输出第6列包含bin的行
awk -F: '$6!~/bin/{print}' user #输出第6列不包含bin的行
awk -F: '$7=="/bin/bash"{print}' /etc/passwd #对比内容不是变量,用双引号
awk -F: '$7!="/bin/bash"{print}' /etc/passwd #上述情况的取反搜索
2)使用数字和字串作为条件
==相等 !=不相等 >大于 >=大于等于 <小于 <=小于等于
awk -F: 'NR==3{print}' /etc/passwd #输出第3行
awk -F: 'NR<3{print}' /etc/passwd #输出第1~2行
awk -F: '$3<10{print}' /etc/passwd #输出id号是0~9的行
awk -F: '$3>=1000{print}' /etc/passwd #输出普通用户的行
3)逻辑组合 && ||
awk -F: '$3>=10&&$3<=20' /etc/passwd #找id号范围是10~20的行
awk -F: 'NR>=2&&NR<=10' /etc/passwd #找2~10行
awk -F: '$3<5||$3>1000' /etc/passwd #找id号是0~4或者1001以上的行
awk 'NR<5||NR>10{print NR}' /etc/passwd #找1~4行或者11以上的行输出行号
awk -F: '$1=="root"||$1=="bin"' /etc/passwd #找第1列是root或者bin的
awk -F: 'NR>5||NR<100' /etc/passwd #找所有行
awk -F: 'NR<5&&NR>100' /etc/passwd #逻辑错误,没有输出
4)使用运算±*/% ‘{print 1+1}’
awk 'BEGIN{print 1+1}' #常规运算awk 'BEGIN{print 2-1}'
seq 200 | awk '$1%7==0' #找到能被7整除的行 seq 10设置10行
seq 200 | awk '$1~/7/||$1%7==0' #找被7整除或包含7的行
seq 200 | awk '$1~/7/&&$1%7==0' #找被7整除并且包含7的行
awk中使用if
1)单分支awk ‘{if(条件){指令}}’ #格式,满足条件就执行
awk -F: '{if($7~/bash/){print}}' user #逐行处理,第7列包含bash,就输出该行
2)双分支,awk -F: ‘{if( ){ }else{ }}’
awk ‘{if(条件){指令}else{指令}}’ #基本格式
awk ‘{if( ){ }else{ }}END{ }’ #先写框架,多增加END任务
awk -F: '{if($7~/bash/){x++}else{y++}}END{print x,y}' /etc/passwd #统计系统中使用bash和没有使用bash作为解释器的用户,的用户数量, 判断如果每找到一行的$7包含bash,就把x+1,否则y+1,最后使用end输出x与y的值
3)多分支,awk -F: ‘{if( ){ }else if( ){ }else{ }}’
awk ‘{if(条件){指令}else if(条件){指令}else{指令}}’ #基本格式
awk -F: ‘{if( ){ }else if( ){ }else{ }}END{ }’ #多增加END任务输出最终结果
awk -F: '{if($7~/bash/){x++}else if($7~/nologin/){y++}else{z++}}END{print x,y,z}' /etc/passwd #找使用bash或者nologin作为解释器的账户数量,分别用变量x与y显示,其他解释器用z显示
4.awk中的for循环与数组,数组名[下标]
awk中的for循环:可以遍历数组(查看数组所有内容)for(变量名 in 需要遍历的数组名){执行任务} #变量在每次循环时,代表数组的不同下标
数组:相当于可以存储多个值的变量,数组名[下标]=某下标对应的值
awk 'BEGIN{a[1]=10;a[2]=20;print a[1]}' #定义多个值,print a[1]输出该数组对应下标是1的值10
awk 'BEGIN{a[1]=10;a[2]=20;print a[2]}' #20
awk 'BEGIN{a[1]=10;a[2]=20;a[3]=30;print a[1],a[2],a[3]}' #创建数组a,然后逐个输出
awk 'BEGIN{a[1]=10;a[2]=20;a[3]=30;for(i in a){print a[i]}}' #使用for循环显示数组a的所有下标的值
awk 'BEGIN{a[1]=10;a[2]=20;a[3]=30;for(i in a){print i,a[i]}}' #for循环遍历a数组下标与对应的值
1 10
2 20
3 30
使用awk的数组{a[$1]++}收集数据
[root@svr7 opt]# cat abc.txt0
abc
xyz
opq
abc
abc
xyz
awk '{a[$1]++}END{for(i in a){print a[i],i}}' abc.txt #将$1收集到数组a中,累计次数,for循环显示所有内容
使用awk统计网站访问量:
tail -1 /var/log/httpd/access_log #查看最后一条httpd访问日志
awk '{print $1}' /var/log/httpd/access_log # ip 第一列
awk '{ip[$1]++}END{for(i in ip){print ip[i],i}}' /var/log/httpd/access_log | sort -nr
#使用sort实现排序功能,-n是以数字作为排序对象,-r是降序
使用awk统计多少ip曾经尝试登陆你的服务器
tail -3 /var/log/secure #查看安全日志,找到Failed password字样的行
awk '/Failed password/{ip[$11]++}END{for(i in ip){print ip[i],i}}' /var/log/secure