0%

Shell 文本处理和数据分析

“热情、努力、朴素的心。”——稻盛和夫

cut

cut 命令可以按照给定的分隔符切分数据行并打印。

选项 作用
-f 选择显示的列
-s 不显示没有分隔符的行
-d 自定义分隔符

cut -s -d' ' -f1,3 text以空格切割,选取第 1,3 行且不打印没有分隔符的行。

sort

sort 命令可以按照行进行排序。

选项 作用
-n 按照数值序排序(默认为字典序)
-r 倒序
-t 自定义分隔符
-k 选择排序列
-u 合并相同行
-f 忽略大小写

sed

sed 是一个类似于 vim 末行模式的行编辑器,基本语法为sed [options] 'AddressCommand' file

Options

选项 作用
-n 静默模式
-i 直接修改源文件
-e 同时执行多个脚本
-f 使用脚本处理
-r 使用扩展正则表达式

Commands

命令 作用
d 删除行
p 显示符合条件的行
a \string 在指定内容后面追加新行,内容为 string
i \string 在指定内容前面追加新行,内容为 string
r FILE 将指定文件的内容添加到符合条件的行处
w FILE 将地址范围内的行另存到指定文件中
s/pattern/string/修饰符 查找并替换,默认只替换每行中第一个被模式匹配到的字符串

s/pattern/string/修饰符中的修饰符:

  • g:行内全局替换
  • i:忽略大小写
  • 转义:\(\)\1\2

Address

  • 可以没有
  • 给定范围
  • 查找指定行/str/

例子

1
2
sed  's/\(id:\)[0-6]\(:initdefault:\)/\15\2/ig'  inittab
sed 's/\(IPADDR=\([1-9][0-9]\{0,2\}\.\)\{3\}\).*/\188/gi' /etc/sysconfig/network-scripts/ifcfg-eth0

awk

awk 是一个强大的文本分析工具。相对于 grep 的查找,sed 的编辑,awk 在分析数据并形成报告方面尤为强大。awk 能够逐行读取文件,按照分隔符切割行,然后进行处理分析。

awk -F'{pattern + action}'{filenames}

  • 支持自定义分隔符
  • 支持正则表达式
  • 支持自定义变量、数组(a[1],a[tom],map(key)
  • 支持内置变量
    • ARGC:命令行参数个数
    • ARGV:命令行参数排列
    • ENVIRON:支持队列中系统环境变量的使用
    • FILENAME:awk 浏览的文件名
    • FNR:浏览文件的记录数
    • FS:输入域分隔符,等价于 -F 选项
    • NF:浏览记录的域的个数
    • NR:已读的记录数
    • OFS:输出域分隔符
    • ORS:输出记录分隔符
    • RS:控制记录分隔符
  • 支持函数
  • 支持流程控制语句

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 显示 /etc/passwd 下账户的列(类比 cut)
awk -F':' '{print $1}' passwd

# 显示 /etc/passwd 下账户和账户对应的 shell,账户与 shell 之间以逗号分割,且在所有输出最开头添加表头(name,shell),最后一行添加 "blue,/bin/nosh"(类比 cut + sed)
awk -F':' 'BEGIN{print "name,shell"} {print $1 "," $7} END{print "blue,/bin/nosh"}' passwd

# 搜索 /etc/passwd 中有 root 关键字的所有行
awk '/root/ {print $0}' passwd

# 打印 /etc/passwd 中每行的行号,每行的列数及对应行的完整内容
awk –F’:’ ‘{print NR”\t”NF”\t”$0}’ passwd

# 假设有以下数据:
# tom 0 2012-12-11 car 3000
# John 1 2013-01-13 bike 1000
# Vivi 1 2013-01-18 car 2800
# Tom 0 2013-01-20 car 2500
# John 1 2013-01-28 bike 3500
# 现在要按照姓名统计 1 月合计工资,同时将 0 替换为 manager,1 替换为 worker 输出
awk '{
split($3,date,"-");
if(date[2]=="01"){
name[$1]+=$5;
if($2=="0"){
role[$1]="M"
}
else{
role[$1]="W"
}
}
}
END{
for(i in name){
print i "\t" name[i]"\t" role[i]
}
}' awk.txt