linux grep、sed、awk 咋用
基础
declare
declare 为 shell 解释器自建命令,默认所有变量类型均为字符串,脚本语言(解释器语言)是解释执行的,解释权归自己所有,只要语句自己认识即可,想咋定就咋定
declare(选项)(参数) 选项 -: 给变量设置类型属性 +: 取消变量的类型属性 -a:将变量声明为数组型 -i:将变量声明为整型 -x:将变量声明为环境变量 -r:将变量声明为只读变量 -p:查看变量的被声明的类型 参数 # 声明 x,y,z,默认字符串连接 [cmd] x=1 [cmd] declare -p x declare -- x="1" [cmd] y=1 [cmd] z=$x+$y && echo $z 1+1 [cmd] declare -i z [cmd] declare -p z declare -i z="1+1" # 声明 i_z 整形,加法不再默认字符串连接 [cmd] declare -i i_z=$x+$y && echo $i_z 2 [cmd] declare -p i_z declare -i i_z="2" # 数组,不需要声明 [cmd] a_x1=1 [cmd] a_x2=2 [cmd] declare -p a_x declare -a a_x='([0]="1" [1]="2")' # 声明只读,可以只有声明,不赋值,不可修改,不可 -p [cmd] declare -r r_x [cmd] declare -p r_x -bash: declare: r_x: not found [cmd] declare -r x [cmd] declare -p x declare -r x="1" [cmd] declare -r i_z # i_z 整形只读,只读设置不可撤销 [cmd] declare -p i_z declare -ir i_z="2" [cmd] i_z=4 -bash: i_z: readonly variable [cmd] declare +r i_z -bash: declare: i_z: readonly variable
引号
特殊字符,有些字符在 shell 中具有特殊含义,需要转义处理,如下表
关键字,充当指令的字符,有些关键字使用特殊字符
单引号、双引号、无引号,在 shell 中,默认所有输入都为字符串,不需要任何引号,规定双引号跟无引号等同,加双引号是为了减少失误。shell 中这些特殊输入输出需要加反斜杠 \( 例如 \# 表示 #,\! 表示 ! )。若不加反斜杠,使用单引号也可达到同样效果
#, ;, ;;, . ., ., "", '', \, /, `, :, !, *, ?, $, (), {}, [], [[]], (()), >& >>& >> <, << <<<, \<, \>, |, >|, ||, &, &&, ~, !, ,, ^
POSIX 正则表达式规范
包括 BRE(基本型)和 ERE(扩展型)两类规则,互不兼容。BRE 规定关键字字符:., \, [, ^, $, * 。ERE中规定关键字字符多 7 个,(, ), {, }, +, ?, | 。grep、vi、sed 工具遵循 BRE 规范,grep -e, egrep, awk 工具遵循 ERE 规范。对于这些工具,会按照相应规范处理这些关键字符。其它没有被当作关键字的特殊字符,加反斜杠输入输出。
实例分析,查找字符串 xoo, grep ".o\{2\}" filename。这里 . 本来是特殊字符,这里 grep 选作关键字,\{ 和 \} 表示花括号, grep 将参数识别为 .o{2},如下是查找特殊字符的命令
[cmd]grep '\"' one.txt -on [cmd]grep "\\\\\\\\" one.txt [cmd]grep "'" one.txt -on [cmd]grep "\\$" one.txt -on [cmd]grep "|" one.txt -on [cmd]grep "\\^" one.txt -on [cmd]grep "\^" one.txt -on [cmd]grep "#" one.txt -on [cmd]grep ";" one.txt -on [cmd]grep "." one.txt -on [cmd]grep "\." one.txt -on [cmd]grep "/" one.txt [cmd]grep "\*" one.txt [cmd]grep "\?" one.txt [cmd]grep "\[" one.txt -on [cmd]grep "\]" one.txt -on [cmd]grep "<" one.txt -on [cmd]grep ">" one.txt -on [cmd]grep "||" one.txt -on [cmd]grep "&" one.txt -on [cmd]grep "&&" one.txt -on [cmd]grep "~" one.txt -on [cmd]grep "\!" one.txt -on
grep 命令
以行为单位查找匹配内容,包含查找内容的行
grep [OPTIONS] [-e PATTERN | -f FILE] [FILE...] 查找 .gz 压缩文件用 zgrep 命令,跟 grep 基本相同 OPTIONS: -v:反选 -w: 单词匹配 -x: 整行匹配 -n:打印行号 -o:grep 默认会输出匹配的行,如果只想输出匹配的字符串,加该参数 -F: 不要使用正则匹配,直接匹配 -e PATTERN:可以有多个,例如 -e "ab" -e "cd",查找 ab 或者 cd,PATTERN 按照相关正则标准写 -f FILE:指定关键字文件,查找少量关键字用 -e PATTERN ,查找几百个呢,用文件比较好 最后是一个被查找的文件列表
sed
一般用于对文件进行格式化,默认不会修改源文件,通过读取文件流到缓冲区,对缓冲行执行相关操作以标准输出流的方式输出,在输出时,会输出源行和修改后行内容。加 -i 参数会直接修改源文件,加 -n 只输出操作后行内容,没操作不输出。
sed [-inV] '/行选择器/动作'
指令:
-i 直接修改源文件
-V 版本信息
动作: a:追加,在当前行后添加一行或多行。当添加多行时,除最后一行外,每行末尾需要用“\”代表数据未完结; c:行替换,用c后面的字符串替换原数据行。当替换多行时,除最后一行外,每行末尾需用“\”代表数据未完结; i:插入,在当前行前插入一行或多行。当插入多行时,除最后一行外,每行末尾需要用“\”代表数据未完结; d:删除,删除指定的行; P:打印,输出指定的行; s:字符串替换,用一个字符串替换另一个字符串。格式为“行范围s/旧字串/新字串/g”(和Vim中的替换格式类似); # 文件内容 [cmd]cat two.txt 11111111a 22222222b 33333333c # 查找含字符串 222 行,并在其之前插入 hello word [cmd]sed '/222/i hello word' two.txt 11111111a hello word 22222222b 33333333c # 查找含字符串 222 行,并在其之后插入 hello word [cmd]sed '/222/a hello word' two.txt 11111111a 22222222b hello word 33333333c # 查找含字符串 222 行,并将改为 hello word 两行 [cmd]sed '/222/c hello \n word' two.txt 11111111a hello word 33333333c # 查找含字符串 222 行,并将该行 b 字符替换为 $ [cmd]sed '/222/s/b/$/g' two.txt 11111111a 22222222$ 33333333c
awk
一般用于编辑文件。awk '[BEGIN{ commands }] [pattern{ commands }] [END{ commands }]' filename 一个awk脚本通常由BEGIN, 通用语句块,END语句块组成,三部分都是可选的。 脚本通常是被单引号或双引号包住。awk 脚本类似与 js 脚本,功能强大
awk执行过程分析
第一步: 执行BEGIN { commands } 语句块中的语句
BEGIN语句块:在awk开始从输入输出流中读取行之前执行,在BEGIN语句块中执行如变量初始化,打印输出表头等操作。
第二步:从文件或标准输入中读取一行,然后执行 pattern{ commands }语句块。它逐行扫描文件,从第一行到最后一行重复这个过程,直到全部文件都被读取完毕。
pattern语句块:pattern语句块中的通用命令是最重要的部分,它也是可选的。如果没有提供pattern语句块,则默认执行{ print },即打印每一个读取到的行。{ }类似一个循环体,会对文件中的每一行进行迭代,通常将变量初始化语句放在BEGIN语句块中,将打印结果等语句放在END语句块中。
第三步:当读至输入流末尾时,执行END { command }语句块
在awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块。
内置变量
$0 整行
$1, $2 第一列,第二列
NF 最后一列变量
FS 分隔符字符
NR 当前行号
-F: 指定分隔符
-v: 指定或者修改内部变量
-v OFS="===": 输出分隔符
cat score.txt Marry 2143 78 84 77 Jack 2321 66 78 45 Tom 2122 48 77 71 Mike 2537 87 97 95 Bob 2415 40 57 62 $ cat cal.awk #!/bin/awk -f #运行前 BEGIN { math = 0 english = 0 computer = 0 printf "NAME NO. MATH ENGLISH COMPUTER TOTAL\n" printf "---------------------------------------------\n" } #运行中 { math+=$3 english+=$4 computer+=$5 printf "%-6s %-6s %4d %8d %8d %8d\n", $1, $2, $3,$4,$5, $3+$4+$5 } #运行后 END { printf "---------------------------------------------\n" printf " TOTAL:%10d %8d %8d \n", math, english, computer printf "AVERAGE:%10.2f %8.2f %8.2f\n", math/NR, english/NR, computer/NR } $ awk -f cal.awk score.txt NAME NO. MATH ENGLISH COMPUTER TOTAL --------------------------------------------- Marry 2143 78 84 77 239 Jack 2321 66 78 45 189 Tom 2122 48 77 71 196 Mike 2537 87 97 95 279 Bob 2415 40 57 62 159 --------------------------------------------- TOTAL: 319 393 350 AVERAGE: 63.80 78.60 70.00
分组计数,多个分隔符
111111*****2222222|||||||3333333########444444444&&&&&&&&&55555555
awk -F '[*|#&]+' '{print $3}' 333
awk '{arr[$1]++} END{for(i in arr){print(i ": " arr[i])}}' two.txt
数据统计
样本抽取
shuf -n 1000 srcName > dstName 从 srcName 抽取 1000 行到 dstName。先对样本进行分析,编写相应处理程序,跑样本,得到预测结果后,再处理源数据
文件切割,防止源数据过大,内存溢出
split -l 1000 test.txt -d -a 3 test_
-l:按行分隔,每1000行切割test.txt文件
-d:添加数字后缀
-a:以3位数数字做尾数
test_:分割后的文件的前缀
去重
uniq -c 相同行数量,只能统计相邻行
排序
sort -n -r -t ':' -k 3
-n,用数值排序,而非字典序
-r,倒序
-t ':', 冒号作为分隔符
-k 3,分割后第 3 列
计数
wc -l