基础正则表达式
正则表达式和通配符
正则表达式用来在文件中匹配符合条件的字符串,正则是包含匹配。grep、awk、sed等命令可以支持正则表达式
通配符用来匹配符合条件的文件名,通配符是完全匹配。ls、find、cp这些命令不支持正则表达式,所以只能用shell自己的通配符来进行匹配
基础正则表达式
* | 前一个字符匹配0次或任意多次 |
. | 匹配除了换行符外任意一个字符 |
^ | 匹配行首。如:^hello会匹配以hello开头的行 |
$ | 匹配行尾。如:hello$会匹配以hello结尾的行 |
[] | 匹配括号中指定的任意一个字符,只匹配一个字符。如:[0-9]匹配任意一位数字,[a-z][0-9]匹配小写字母和以为数字构成的两位字符 |
[^] | 匹配除括号中的字符以外的任意一个字符。如:^[^0-9]匹配任意一位非数字字符 |
\ | 转义符。用于取消特殊符号的含义 |
\{n\} | 表示前面的字符恰好出现n次。如:[0-9]\{4\}匹配4位数字 |
\{n,\} | 表示其前面的字符出校不下于n次。如:[0-9]\{2\}表示两位及以上的数字 |
\{n,m\} | 表示其前面的字符至少出现n次,最多出现m次。如:[a-z]\{6,8\}匹配6到8位的小写字母 |
例:
grep "a*" test_rule.txt
#匹配所有内容,包括空白行
grep "aa*" test_rule.txt
#匹配至少包含一个a的行
grep "a..f" test_rule.txt
#匹配在a和f之间有两个字符的单词
grep "a.*g" test_rule.txt
#匹配在a和g之间有任意字符
grep ".*" test_rule.txt
#匹配所有内容
grep -n "^$" test_rule.txt
#匹配空白行
grep "\.$" test_rule.txt
#转义符 匹配以”.“结尾
字符截取命令
cut字段提取
- -f: 提取第几列
- -d: 按照指定分隔符分割列
例:
cut -d ":" -f 1,3,6 /etc/passwd
#查看用户名、用户UID、家目录
cat /etc/passwd | grep /bin/bash | grep -v root |cut -d ":" -f 1
#提取出系统中能登录的用户。root除外
printf ‘输出类型输出格式’输出内容
输出类型:
%ns: 输出字符串。n是数字,指代几个字符
%ni: 输出整数。n是数字指代输出几个数字
%m.nf 输出浮点数,m和n是数字,指代输出的整数位数和小数位数。如%8.2f代表共输出8位数,其中两位是小数,6位是整数
输出格式:
- \a: 输出警告音
- \b: 输出退格键(backspace)
- \f: 清除屏幕
- \n: 换行
- \r: 回车
- \t: 水平输出退格键(tab)
- \v: 垂直输出退格键(tab)
例:
printf ‘%s‘$(cat userdel.txt) 输出文件内容
在awk命令的输出中支持print和printf命令
print:会在每个输出之后自动加入一个换行符(Linux默认没有print命令)
printf:标准格式输出命令,并不会自动加入换行符,如果需要换行,需要手工加入换行符
awk ‘条件1{动作1} 条件2 {动作2}。。。’ 文件名
条件(pattern)
一般使用关系表达式作为条件
X>10 判断变量X是否大于10
X>=10 大于等于
X<=10 小于等于
动作(action)
格式化输出
流程控制语句
例子:
awk ‘{printf $2 "\t" $4 "\n"}‘ student.txt
NAME GENDER
小明 男
小红 女
小亮 男
df -h | grep sda1 | awk ‘{print $5}‘|cut -d "%" -f 1
50
BEGIN
awk ‘BEGIN{ printf "student\n"}{printf $2 "\t" $4 "\n"}‘ student.txt
student
NAME GENDER
小明 男
小红 女
小亮 男
END
awk ‘END{ printf "student\n"}{printf $2 "\t" $4 "\n"}‘ student.txt
FS内置变量:指定分隔符
例:
awk ‘BEGIN{FS=":"}{print $1 "\t" $3}‘ /etc/passwd
cat /etc/passwd|grep /bin/bash |awk ‘{print $1 "\t" $3}‘
#显示所有可以登陆的用户
关系运算符
例:
cat student.txt |grep -v ID|awk ‘$3>=12 {print $2}‘
#筛选出第三列数字大于等于12 并把第二列的内容显示出来
sed:是一种几乎包括在所有Unix平台的轻量级流编辑器。sed主要用来将数据进行选取、替换、删除、新增的命令
sed [选项] ‘[动作]‘ 文件名
- -n: 一般sed命令会把所有数据都输出到屏幕,如果加入此选择,则只会把经过sed命令处理的行输出到屏幕
- -e: 允许对输入数据应用多条sed命令编辑
- -i: 用sed的修改结果直接修改读取数据的文件,而不是由屏幕输出
- 动作:
- a \:追加,在当前行后添加一行或多行。添加多行时,除最后一行外,每行末尾需要用“\”代表数据未完结
- c \:行替换,在c后面的字符替换原数据行,替换多行时,除最后一行外,每行末尾需用“\”代表数据未完结
- i \:插入,在行前插入一行或多行。插入多行时,除最后一行外,每行末尾需要用“\”代表数据未完结
- d \:删除,删除指定的行
- p \:打印,输出指定的行
- s \:字符替换,用一个字符串替换另外一个字符串。格式为“行范围s/旧字串/新字串/g”
例:
sed -n ‘1p‘ /etc/passwd #查看文件的第二行
sed ‘2,99d‘ /etc/passwd #删除2-99行的输出数据
sed ‘2a hello word‘ /etc/passwd #在第二行后追加数据
sed ‘2i hello word‘ student.txt #在第二行前插入数据
sed ‘s/14/99/g‘ student.txt #把student.txt中所有的14替换为99
sort 排序命令
-f 忽略大小写
-n 以数值型进行排序,默认使用字符串型排序
-r 反向排序
-t 指定分隔符,默认分隔符是制表符
-k n[,m] 按照指定字段范围排序。从第n字段开始,m字段结束(默认到行尾)
条件判断
两种判断格式:
[ -d /etc ]&&echo yes ||echo no
[ -e /etc/passwd ]
按文件类型进行判断
- -d 判断该文件是否存在,并且是否为目录文件(是目录为真)
- -e 判断该文件是否存在(存在为真)
- -f 判断该文件是否存在,并且是否为普通文件(是普通文件为真)
- -b 判断该文件是否存在,并且是否为块设备文件(是块设备文件为真)
- -c 判断该文件是否存在,并且是否为字符设备文件(是字符设备文件为真)
- -L 判断该文件是否存在,并且是否为符号链接文件(是符号链接文件为真)
- -p 判断该文件是否存在,并且是否为管道文件(是管道文件为真)
- -s 判断该文件是否存在,并且是否为空(非空为真)
- -S 判断该文件是否存在,并且是否为套接字文件(是套接字文件为真)
按照文件权限进行判断
- -r 判断该文件是否存在,并且该文件是否拥有读权限(有读权限为真)
- -w 判断该文件是否存在,并且该文件是否拥有写权限(有写权限为真)
- -x 判断该文件是否存在,并且该文件是否拥有执行权限(有执行权限为真)
- -u 判断该文件是否存在,并且该文件是否拥有SUID权限(有SUID权限为真)
- -g 判断该文件是否存在,并且该文件是否拥有SGID权限(有SGID权限为真)
- -k 判断该文件是否存在,并且该文件是否拥有SBit权限(有SBit权限为真)
两个文件之间进行比较
文件1 -nt 文件2 判断文件1的修改时间是否比文件2的新(如果新则为真)
文件1 -ot 文件2 判断文件1的修改时间是否比文件2的旧(如果旧则为真)
文件1 -ef 文件2 判断文件1是否和文件2的INode号一致,可以理解两个文件是否为同一个文件。用于判断硬链接(ln创建硬链接)
两个整数之间的比较
整数1 -eq 整数2 判断整数1是否和整数2相等(相等为真)
整数1 -ne 整数2 判断整数1是否和整数2不等(不等为真)
整数1 -gt 整数2 判断整数1是否大于整数2(大于为真)
整数1 -lt 整数2 判断整数1是否小宇整数2(小于为真)
整数1 -ge 整数2 判断整数1是否大于等于整数2(大于等于为真)
整数1 -le 整数2 判断整数1是否小于等于整数2(小于等于为真)
字符串判断
-z 判断字符串是否为空(为空返回真)
-n 判断字符串是否非空(非空返回真)
字符串1 == 字符串2 判断字符号1是否和字符串2相等(相等返回真)
字符号1!=字符串2 判断字符串1是否和字符串2不等(不等返回真)
多重条件判断
判断1 -a 判断2 逻辑与,判断1和判断2都成立,最终的结果才为真
判断1 -o 判断2 逻辑或,判断1和判断2有一个成立,最终结果为真
! 判断 逻辑非,使原始的判断式取反
例:
aa=22
[ -n "$aa" -a "$aa" -gt 23 ] && echo yes || echo no
#判断aa是否有值,同时判断aa是否大于23
#因为变量aa的值不大于23,所以虽然第一个判断值为真,返回的结果也是假
流程控制
单分支if条件语句
if [条件判断式]; then
程序
fi
或
if [条件判断式]
then
程序
fi
单分支条件语句需要注意几个点
if语句使用fi结尾,和一般语言使用大括号结尾不同
[条件判断式] 就是使用test命令判断,所以中括号和条件判断式之间必须有空格
then后面除符合条件之后执行的程序,可以放在[]之后,用“;”分割。也可以换行写入,就不需要“;”了
例:判断分区使用率
#!/bin/bash
diska=$(df -h | grep "/dev/sda3" | awk ‘{print $5}‘ | cut -d "%" -f1)
#把根分区使用率作为变量值赋予变量disk
if [ $diska -ge 80 ]
#判断变量diska是否大于80(大于等于为真)
then
echo "硬盘 /dev/sda3 剩余空间不足%20"
df -h | grep "/dev/sda3"
fi
双分支if条件语句
if [ 条件判断式 ]
then
条件成立时,执行的程序
else
条件不成立时,执行的另一个程序
fi
例:
#!/bin/bash
#mysql备份
#由于实验环境无mysql,则mysql路径/var/lib/mysql以/root代替
date=$(date +%y%m%d)
#把当前系统时间按年月日的格式赋予变量date
size=$(du -sh /root)
#统计MySQL大小并赋予变量size
if [ -d /tmp/backup ]
then
echo "$date" > /tmp/backup/backup-time.txt
echo "$size" >> /tmp/backup/backup-time.txt
cd /tmp/backup
tar czvf mysql-lib-$date.tar.gz /root backup-time.txt&>/dev/null
rm -rf backup-time.txt
else
mkdir /tmp/backup
echo "$date" > /tmp/backup/backup-time.txt
echo "$size" >> /tmp/backup/backup-time.txt
cd /tmp/backup
tar czvf mysql-lib-$date.tar.gz /root backup-time.txt&>/dev/null
rm -rf backup-time.txt
fi
例:判断apache是否启动
#!/bin/bash
port=$(nmap -sT 192.168.200.254 | grep tcp | grep http | awk ‘{print $2}‘)
#使用nmap扫描服务器端口,并截取apache服务的状态,赋予变量port
if [ "$port" == "open" ]
then
echo "$(date) running " >> /tmp/apache.log
else
systemctl start httpd.service
echo "$(date) restart " >> /tmp/apache.log
fi
多分支if条件语句
if [ 条件判断式1 ]
then
当条件判断式1成立,执行程序1
elif [ 条件判断式2 ]
then
当条件判断式2成立,执行程序2
.........................
else
当所有条件不成立,执行此程序
fi
判断用户输入文件类型
#!/bin/bash
#判断用户输入的文件类型
read -p "file name ?" file
#接受输入,并赋予变量file
if [ -z "$file" ]
#判断变量file是否为空
then
echo "ERROR 请输入文件名"
exit 1
elif [ ! -e "$file" ]
#判断file的值是否存在
then
echo "ERROR 请输入正确的文件名"
exit 2
elif [ -f "$file" ]
#判断file值是否为普通文件
then
echo "$file is ordinary file"
elif [ -d "file" ]
#判断file是否为目录文件
then
echo "$file is directory file"
else
echo "$file is other file"
fi
case语句
case $变量名 in
“值1”)
如果变量的值等于值1,则执行程序1
;;
“值2”)
如果变量的值等于值2,则执行程序2
;;
....................................
*)
如果变量的值都不是以上的值,则执行此程序
;;
esac
例:判断用户输入
#!/bin/bash
#判断用户输入
read -p "please choose yes/no:" -t 30 import
#如果30s未输入,则执行最后的 *)
case $import in
"yes")
echo "yes"
;;
"no")
echo "no"
;;
*)
echo "ERROR"
;;
esac
for循环
语法一
for 变量 in 值1 值2 值3...........
do
程序
done
例:
#!/bin/bash
for number in 1 2 3 4 5
do
echo "number is $number"
done
例2:
#!/bin/bash
#批量备份脚本
cd /tar
ls *.tar.gz>tar.log
for t in $(cat tar.log)
do
tar xzvf $t &>/dev/null
done
rm -rf /tar/tar.log
for循环语法二
for ((初始值; 循环控制条件; 变量变化))
do
程序
done
例:
#!/bin/bash
#从1加到100
s=0
for ((i=1; i<=100;i=i+1))
do
s=$(($s+$i))
done
echo "$s"
例二:批量添加用户
#!/bin/bash
read -p " user name:" -t 30 name
read -p " user number:" -t 30 num
read -p " passwd:" -t 30 pass
if [ ! -z "$name" -a ! -z "$num" -a ! -z "$pass" ]
then
y=$(echo $num | sed ‘s/^[0-9]*[0-9]‘//g)
if [ -z "$y" ]
#判断$num是不是数字
then
for (( i=1; i <= $num;i=i+1 ))
do
useradd $name$i &>/dev/null
echo $pass | passwd --stdin "$name$i" &>/dev/null
done
fi
fi
while循环
while循环是不定循环,也称作条件循环。只要条件判断式成立,循环就会一直继续,直到条件判断式不成立,循环才会停止。这就和for的固定循环不太一样
while [条件判断式]
do
程序
done
例:从1加到100
#!/bin/bash
#从1加到100
i=1
s=0
while [ $i -le 100 ]
#如果变凉i的值小于等于100,则执行循环
do
s=$(( $s+$i ))
i=$(( $i+1 ))
done
echo "$s"
until循环
until循环,和while循环相反,until循环时只要条件判断式不成立则进行循环,并执行循环程序。一旦循环条件成立,则终止循环
例:
#!/bin/bash
#从1加到100
i=1
s=0
until [ $i -gt 100 ]
#循环到变量的值大雨100,就停止循环
do
s=$(( $s+$i ))
i=$(( $i+1 ))
done
echo "$s"