Shell学习(六)

shell脚本开发之文本操作

系列学完了,这是第二期。(其实应该这个先学的) bash 基础
接下来是有名的第三方工具 (正则表达式 awk sed grep等等)

bash 快捷键

快捷键 英文 功能
Ctrl + A ahead 行首
Ctrl + E end 行尾
Ctrl + U 删除光标之前的 所有 字符
Ctrl + K 删除光标之后的 所有 字符
Ctrl + L clear 清空屏幕
Tab 补全 $PATH 命令,补全文件名

RegExp

正则表达式分两类:

  • 基本正则表达式,BRE对应的字符有:^$.[]*
  • 扩展正则表达式,ERE在BRE基础上,加上:(){}?+| 等字符

正则表达式仅支持 (sed, awk, grep)

工具 描述
grep 文本过滤工具 (模式 pattern) 工具
sed 流编辑器 (stream editor) 文本编辑工具
awk Linux 文本报告生成器 (格式化文本) gawk

BRE 集合

字符 描述
^ 尖角号,用于模式的最左侧 --> "^yu" 匹配以 yu 单词开头的行
$ 美元符,用于模式的最右侧 --> "yu$" 匹配以 yu 单词结尾的行
^$ 组合符,表示空行( ^ 后面什么也没写,为空。$ 前面什么也没写,为空。开头结尾什么都没有)
. 匹配任意一个且只有一个字符,不能匹配空行
\ 转义字符,让特殊含义的字符,现出圆形,还原本意。例如 \. 代表小数点
* 匹配前一个字符(连续出现)0次或1次以上,重复0次代表空,即匹配所有内容 --> a* 匹配 a 0次或多次
.* 组合符,匹配所有内容
^.* 组合符,匹配任意多个字符开头的内容
.*$ 组合符,匹配以任意多个字符结尾的内容
[abc] 匹配 [] 集合内的任意一个字符,abc,可以写成 [a-c]
[^abc] 匹配除了 ^ 后面的任意字符,abc^ 表示对 [abc] 的取反

ERE 集合

  • grep 命令需要使用参数 -E 才生效
  • egrep 不推荐使用,用 grep -E 替代
  • grep 不加参数,得在特殊字符前面加 \ 反斜杠,识别为正则
字符 描述
+ 匹配前一个字符1次或多次,前面字符至少出现1次
[:/]+ 匹配括号内的 : 或者 / 字符1次或者多次
? 匹配前一个字符0次或1次,前面字符可有可无
| 表示或者,同时过滤多个字符串
() 分组过滤,被括起来的内容表示一个整体
a{n,m} 匹配前一个字符最少n次,最多m次
a{n,} 匹配前一个字符最少n次
a{n} 匹配前一个字符正好n次
a{,m} 匹配前一个字符最多m次

grep

全拼:Global search REgular expression and Print out the line

作用:文本搜索工具,根据用户指定得模式(过滤条件)对目标文本逐行进行匹配检查,打印匹配到的行

模式:由正则表达式的元字符及文本字符所编写出的过滤条件

1
2
3
4
5
6
7
8
语法:
grep [options] [pattern] file
命令 参数 匹配模式 文件数据
-i:ignorecase,忽略大小写
-o:仅显示匹配到的字符本身
-v:--invert-match,显示不能被模式匹配到的行
-E:支持使用扩展的正则表达式元字符
-q:--quiet,--silent 静默模式,即不输出任何信息

grep命令是linux系统中最重要的命令之一,功能是从文本文件或管道数据流中筛选匹配的行和数据,如果再配合正则表达式,功能十分强大,是Linux运维人员必备的命令

参数选项 解释说明
-v 排除匹配结果
-n 显示匹配行与行号
-i 不区分大小写
-c 只统计匹配的行数
-E 使用egrep命令
–color=auto 为grep过滤结果添加颜色
-w 只匹配过滤的单词
-o 只输出匹配的内容
1
2
3
4
5
6
7
cat /etc/passwd > pwd.txt
grep -i "root" pwd.txt
grep -i -n "root" pwd.txt
grep -i -c "root" pwd.txt
echo -e "\n\n" >> pwd.txt
grep -i -n "^$" pwd.txt
grep -i -v "^$" pwd.txt

1
2
3
4
5
6
7
grep -i "^s" pwd.txt
grep -n "bash$" pwd.txt
grep -n "bash$" pwd.txt -o
grep -n ".apt" pwd.txt
grep -n ".apt" pwd.txt --color=auto
# 后面为了方便直接 alias
alias grep='grep --color=auto'

1
2
3
4
grep "[a-z]" /etc/lsb-release
grep "[A-Z]" /etc/lsb-release
grep "[0-9]" /etc/crontab
grep "[^a-zA-Z]" /etc/lsb-release

1
2
3
4
grep -E "l+" /etc/lsb-release
grep -E "go?d" aa.txt
find . -name "*.txt" | grep -E "a|w"
grep -E "g(o|)d" aa.txt

1
2
3
4
5
grep -E "(r..t).*\1" /etc/passwd
grep -E "o{1,4}" aa.txt
grep -E "o{5,}" aa.txt
grep -E "o{2}" aa.txt -o
grep -E "o{,4}" aa.txt -o

sed

对文件,数据流进行处理,操作,过滤替换转换文本内容。

工作流程:每次一行,放入模式空间(读入内存),然后模式匹配,匹配成功,进行编辑,后输出屏幕,匹配失败输出屏幕。

1
2
# 语法
sed [选项] (sed 内置命令字符) [输入文件]

选项:

参数选项 解释
-n 取消默认 sed 输出,常与 p 命令一起用
-i 直接将修改结果写入文件中,不加参数就是修改内存数据,输出
-e 多次编辑,不需要管道符了
-r 支持正则扩展

常用的内置命令字符

sed 内置命令字符 解释
a append, 对文本追加,指定行后面添加一行/多行文本
d Delete, 删除匹配行
i insert, 表示插入文本,指定行前添加一行/多行文本
p Print, 打印匹配行内容,与 -n 一起使用
s/exp/xxx/g 匹配正则内容,然后替换内容(支持正则),结尾 g 代表全局匹配

sed 匹配范围

范围 解释
空地址 全文处理
单地址 指定文件某一行
/pattern/ 被模式匹配的某一行
范围区间 10,20 十到二十行 10,+5 第十行向下5行。/pattern1/,/pattern2/
步长 1~2 1,3,5,7,9。2~2两个步长,表示2,4,6,8,10 偶数行
1
2
3
4
5
6
7
8
9
# 忽略准备数据
sed -n "2,3p" 2.txt
sed -n "1~2p" 2.txt
sed -n "2,+2p" 2.txt
sed "1a=======" 2.txt
sed "1i=======" 2.txt
sed "1d" 2.txt
sed "s/I/Your/g" 2.txt
sed "2s/I/Your/g" 2.txt

1
2
3
4
5
sed -n "/linux/p" 2.txt
sed -i "/qq/d" 2.txt
cat -n 2.txt
sed "s@I@Hers@g" 2.txt
sed "s#I#His#g" 2.txt

1
2
3
4
5
6
7
8
9
10
11
sed -i "2iMy qq is 123453453" 2.txt
cat -n 2.txt
sed -e "s/I/My/g" -e "s/123453453/110/g" 2.txt
# 提取 IP 地址
ifconfig eth0
ifconfig eth0 | sed -n "2p"
ifconfig eth0 | sed -n "2p" | sed "s/^.*inet//"
ifconfig eth0 | sed -n "2p" | sed "s/^.*inet//" | sed "s/net.*$//g"
ifconfig eth0 | sed -e "2s/^.*inet//g" -e "2s/net.*$//gp" -n
# 去掉空格
ifconfig eth0 | sed -e "2s/^.*inet//g" -e "2s/net.*$//g" -e "2s/ //gp" -n

awk

有强大的文本格式化能力,处理成专业表格形式。awk最早是在 Unix 上实现。我们用的 awkGUN awkgawk。awk 更是一门编程语言,支持条件判断,数组,循环等功能。

1
2
3
# 语法
sed [选项] '模式[动作]' 文件
sed options pattern {action} file
  • Action 指的是动作,awk擅长文本格式化,且输出格式化的结果,因此最常用的动作是 printprintf
1
2
3
4
for i in {1..10};do for j in {1..5};do echo -n "hello$((i*j)) " >> 3.txt;done && echo '' >> 3.txt;done;
cat 3.txt
# 取出第二列
cat 3.txt | awk '{print $2}'

  • 我们执行的命令是 awk '{print $2}',并没有使用参数和模式,$2 表示输出文本的第二列信息
  • awk默认以空格为分隔符,且多个空格也识别为一个空格,作为分隔符
  • awk是按行处理文件,一行处理完毕,处理下一行,根据用户指定的分隔符去工作,没有指定则默认空格
  • 指定分隔符后,awk 把每一行切割后的数据对应到内置变量
1
2
3
$0      表示整行
$NF 表示当前分割后的最后一列
$(NF-1) 倒数第二列

常用内置变量

内置变量 解释
$n 指定分隔符后,当前记录的第N个字段
$0 完整的输入记录
NF (number of fiels) 分割后,当前行一共有多少个字段
NR (number of records) 当前记录数,行数
FS 输入分隔符,默认是空格
OFS 输出分隔符,默认是空格
RS 输入换行符,默认是换行符,指定输入的换行符
ORS 输出换行符,默认是换行符,指定输出的换行符
FNR 各文件分别计数的行号
FILENAME 当前文件名
ARGC 命令行参数的个数
ARGV 数组,保存的是命令行给定的参数
1
2
3
4
awk '{print $0}' 3.txt
awk '{print $3}' 3.txt
awk '{print $NF}' 3.txt
awk '{print $1$3$NF}' 3.txt

1
2
3
awk '{print $1,$3,$NF}' 3.txt
awk '{print "第一列:"$1,"第三列:"$3,"最后一列:"$NF}' 3.txt
awk '{print}' 3.txt

参数

参数 解释
-F 指定分割字符
-v 定义或修改一个 awk 内部变量
-f 从脚本文件中读取 awk 命令
1
2
3
4
5
6
7
8
9
cat /etc/passwd -n | head -n 5
awk 'NR==3' /etc/passwd
awk 'NR==3{print $0}' /etc/passwd
awk 'NR==3,NR==5{print $0}' /etc/passwd
awk '{print NR,$1}' 3.txt
awk 'NR==20,NR==23{print NR,$0}' /etc/passwd
awk -F ':' 'NR==20,NR==23{print NR,$1}' /etc/passwd
# 查看 IP
ifconfig eth0 | awk 'NR==2{print $2}'

分隔符有两种

  • 输入分隔符,默认空格。变量名是 FS (field separator)
  • 输出分隔符,OFS (output field separator)
1
2
3
4
awk -F ':' 'NR==1,NR==4{print $1}' /etc/passwd
awk -v FS=":" 'NR==1,NR==4{print $NF}' /etc/passwd
awk -v FS=":" -v OFS=" | " 'NR==1,NR==4{print $1,$NF}' /etc/passwd
awk -F ":" -v OFS=" | " 'NR==1,NR==4{print $1,$NF}' /etc/passwd

1
2
3
4
awk '{print NR,FNR,$0}' 2.txt 3.txt
awk -v RS="." '{print NR,$0}' 2.txt
awk -v OFS="---|---" '{print NR,$0}' 2.txt
awk -v ORS="---|---" '{print NR,$0}' 2.txt

1
2
3
4
5
6
7
8
awk '{print NR,FILENAME,$0}' 2.txt 3.txt
awk 'BEGIN{print "Start AWK !!"} {print ARGV[0],$0}' 2.txt
awk 'BEGIN{print "Start AWK !!"} {print ARGV[1],$0}' 2.txt
awk -v name="feng" 'BEGIN{print "Start AWK !!"} {print ARGV[0],ARGV[1],ARGV[2],ARGV[3]}' 1.txt 2.txt
awk -v name="feng" 'BEGIN{print "Start AWK !!"} {print ARGV[0],ARGV[1],ARGV[2],name}' 1.txt 2.txt
# 引用 shell 变量
a="shell args"
awk -v a="$a" 'BEGIN{print a}'

格式化输出

前面我们接触到的awk的输出功能,是print,只能对文本简单的输出,并不能美化或者修改格式

要点:

  1. 其中 print 命令的最大不同是,printf 需要指定 format
  2. format 用于指定后面的每个item的输出格式
  3. printf 语句不会自动打印换行符:\n
  4. format 格式的指示符都以%开头,后跟一个字符
format 解释
%c 显示字符的ASCII
%d %i 十进制整数
%e %E 科学计数法显示数值
%f 显示浮点数
%g %G 以科学计数法的格式或浮点数的格式显示数值
%s 显示字符串
%u 无符号整数
%% 显示%自身
- 左对齐,默认右对齐
+ 显示数值符号: printf "%+d"
1
2
3
4
5
6
7
awk '{print $0}' 2.txt
awk '{printf $0}' 2.txt
awk '{printf "%s\n",$1}' 2.txt
awk '{printf "%s\n",$0}' 2.txt
printf "%s" a b c
printf "%s\n" a b c
printf "== %s ==\n" a b c

1
2
3
awk 'NR==3,NR==5{printf "第一列:%s, 第二列:%s\n", $1,$2}' 3.txt
awk -F ':' 'BEGIN{printf "%-10s\t%-10s\t%-10s\t%-10s\t%-10s\t%-10s\t%-10s\n","Username","password","UID","GID","User mark","Home dir","User bash"}NR==1,NR==10{printf "%-10s\t%-10s\t%-10s\t%-10s\t%-10s\t
%-10s\t%-10s\n",$1,$2,$3,$4,$5,$6,$7}' /etc/passwd

模式:

awk 是按行处理文本,刚才讲解了 print 动作,现在讲解特殊的 pattern :
BEGINEND

  • BEGIN模式是处理文本之前需要执行的操作
  • END模式是处理完所有行之后执行的操作

awk默认是按行处理文本,如果不指定任何模式(条件),awk默认一行行处理
如果指定了模式,只有符合模式的才会被处理

关系运算符 解释 示例
< 小于 x<y
<= 小于等于 x<=y
== 等于 x==y
!= 不等于 x!=y
>= 大于等于 x>=y
> 大于 x>y
~ 匹配正则 x~/正则/
!~ 不匹配正则 x!~/正则/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
awk 'BEGIN{print "start awk"}NR==3{print "==",$0}END{print "Stop awk"}' 2.txt
awk 'NR>=4{print $0}' 2.txt
awk 'NR!=4{print $0}' 2.txt
awk '/^feng/{print $0}' /etc/passwd
awk -F ':' '/^feng/{print $1,$NF}' /etc/passwd
awk -F ':' 'BEGIN{printf "%-10s\t%-10s\t%-10s\t%-10s\n","Username","UID","Home dir","U
ser bash"}/^feng/{printf "%-10s\t%-10s\t%-10s\t%-10s\n",$1,$2,$6,$7}' /etc/passwd
# 找出禁止登陆的用户
awk -F ':' '/nologin$/{print $0}' /etc/passwd
grep "nologin" /etc/passwd -n
awk -F ':' '/^ntp/,/^sshd/{print NR,$0}' /etc/passwd
# 统计 nginx 日志访问 IP 数量
awk '{print $1}' access.log | sort -n | uniq | wc -l
# 统计 nginx 访问最频繁的 IP
awk '{print $1}' access.log | sort -n | uniq -c | sort -nr | head 10


文章作者: Shengyaqingfeng
文章链接: https://creazyboyone.github.io/shell6/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Shengyaqingfeng's Blog