简述

grep一般用于模式匹配,sed(stream editor)和awkgrep派生,可以完成数据转换。之所以称之为过滤程序,是因为这些特殊的转换是用简单的程序设计语言编写的程序来表述的,不同的程序可产生不同的转换。

它们的通用操作为:

$ program 模式-操作 文件名

运行上述命令会使它们顺序扫描文件,查找与模式相匹配的行,找到时,则执行相应的操作。(对于grep,默认操作是打印)

grep - 查找

Unix 上 “grep” 命令的名字来源于 “:g/re/p”,其中 “re” 是正则表达式 (Regular Expression) 的意思。

$ grep 模式 文件名

检索所指定的文件名或标准输入,并打印与模式相匹配的每一行。

参数:

  • -n --line-number 打印行号
  • -v --invert-match 对测试结果求反
  • -i --ignore-case 使得模式中的小写字母与文件中的大写或小写字母都匹配
  • -w --word-regexp 匹配全字
  • -r --recursive

fgrepefrep都接受-f选项表示从指定的文件中读取模式,在此文件中,用换行分隔了可并行检索的模式。

示例:

$ find ./ -name "*c" | xargs grep -rn "foo"

sed - 替换

sed的基本思想是:

$ sed `一系列ed命令` 文件名...

从输入文件中一次一行地读行,按顺序将列表中的命令应用到每一行,并将其编辑过的行写到标准输出。

$ sed -f 命令文件 文件名...

s 命令

使用 s 命令替换:

$ sed "s/old_word/new_word/g" 文件名

配合重定向写入文件:

$ sed "s/old_word/new_word/g" 文件名 > 另一个文件名

使用 -i 参数直接修改文件内容:

$ sed -i "s/old_word/new_word/g" 文件名

在每一行之前或之后加内容:

$ sed "s/^/new/g" 文件名
$ sed "s/$/new/g" 文件名

指定需要替换的范围,下例为只替换第三行,和只替换第 3-6 行:

$ sed "3s/old_word/new_word/g" 文件名
$ sed "3,6s/old_word/new_word/g" 文件名

只替换每一行的第 1 个 old_word:

$ sed "s/old_word/new_word/1" 文件名

只替换每一行的第 3 个以后的 old_word(包含第3个):

$ sed "s/old_word/new_word/3g" 文件名

a/i 命令

a 表示追加写入(append),比如在文件 text 第 3 行后写入 hello,即在第 4 行写入

$ sed '3a hello' -i text

i 表示插入(insert),比如在文件 text 第 3 行插入 hello

$ sed '3i hello' -i text

其他

获取第 3 行内容:

$ sed -n "3p" 文件名

awk - 分析

$ awk ' 程序 ' 文件名

程序是指:

模式/条件 {操作}
模式/条件 {操作}
...

awk一次一行的读文件名中的输入,依次将每行与每个模式相比较,对每个与模式匹配的行,执行其对应的操作,如sedawk并不改变其输入文件。

如打印与正则表达式相匹配的行:

$ awk '/正则表达式/ {print}' 文件名

如果省略模式,则操作被作用到任何输入行;如果省略操作,则默认动作是打印相匹配的行。

awk 可以将命令写入单独文件,通过 -f 指定文件:

$ awk -f progfile 文件名...

特殊变量

$0              - 当前行内容
$1, $2, $3, ... - 按FS将当前行划分为域,分别代表第一个域,第二个...
NR              - 当前行的行号
NF              - 当前行的域的数量
$NF             - 当前行最后一个域
FS              - 分割符,默认为空格或tab,可以通过 `-F` 参数指定

内置函数

substr
print
printf

awk 程序

BEGIN {

}
/匹配模式/ {

}
END {

}

示例

如果有日志文件log:

$ cat log
Sat Sep 23 22:35:13 DST 2017 - 127.0.0.1
Sat Sep 23 22:35:13 DST 2017 - 127.0.0.1
Sat Sep 23 22:35:19 DST 2017 - 155.122.2.2
Sat Sep 23 22:35:19 DST 2017 - 255.255.0.0
Sat Sep 23 22:35:19 DST 2017 - 155.122.2.2
Sat Sep 23 22:35:19 DST 2017 - 155.122.2.2

按IP地址出现的频度打印:

$ awk 'BEGIN{FS="-"} {ips[$2] += 1} END{for (ip in ips) print ips[ip], ip}' log | sort -r
3  155.122.2.2
2  127.0.0.1
1  255.255.0.0

按文件的相反顺序打印:

$ awk '{line[NR] = $0} END{ for (i = NR; i > 0; i--) print line[i]}' test

计算消费 Lag 的总值:

$ /usr/local/kafka/bin/kafka-consumer-groups.sh --zookeeper $(hostname):2181 --describe --group logstash \
  | tail -n +2 \
  | head -n 32 \
  | awk -F ',' 'BEGIN {sum=0} {sum+=$6} END {print sum}'

获取当前磁盘 io 状态:

# iostat首次运行时显示自系统启动开始的各项统计信息,之后运行iostat将显示自上次运行该命令以后的统计信息
disk_info() {
  disk=$1

  rs=`iostat -d -k -x 1 2 | grep $disk | awk 'NR == 2 {print $4}'`
  ws=`iostat -d -k -x 1 2 | grep $disk | awk 'NR == 2 {print $5}'`
  rkBs=`iostat -d -k -x 1 2 | grep $disk | awk 'NR == 2 {print $6}'`
  wkBs=`iostat -d -k -x 1 2 | grep $disk | awk 'NR == 2 {print $7}'`
  echo "rs: $rs \t ws: $ws \t rkBs: $rkBs \t wkBs: $wkBs"
}