Linux三剑客

46

文本三剑客

Linux下处理文本数据非常强大的三个程序

grep

grep是一个过滤器,通过指定条件过滤文本数据
egrep和greo -E 相等,都是开启正则表达式的支持。

语法:
grep [option] [pattern] [file, ...]
command | grep [...] ...

常用参数
-o 只显示匹配到的字符本身。
-v 不显示匹配行(反向匹配)
-i 匹配忽略大小写
-n 显示行号
-r 递归目录搜索
-E 支持正则表达式
-F 不按正则表达式匹配,按字符串字面意思匹配

了解参数
-c 只输出匹配行的数量,不输出匹配行
-w 匹配整词 不匹配包含的(精确匹配,前后有空格或tab)
-x 匹配整行 (同上)
-l 只列出匹配文件名,不显示匹配行数据(与-r搭配)


sed

sed是一个行(流)编辑器,非交互式的对文件进行增删改查操作。

使用者只能在命令行输入编辑命令,指定文件,然后再屏幕上查看输出。它和文本编辑器有本质区别

文本编辑器:编辑对象为文本文件
行编辑器:编辑对象为文本中的行

前者一次处理一个文本整体,而后者是处理文本中的行。

sed数据处理流程

文本行 -> 内存(缓存) -> 屏幕

数据在内存中被处理,然后默认输出到屏幕
也就是说默认情况下sed是修改的只是读到内存的文本行数据,不会修改源文本行

sed命令

语法:sed [options] '{command}[flage]' [filename]

command 内部命令

/abcd/ 匹配模式,在斜杠中写匹配字符
sed '/root/i\addTest' filename
将addTest插入到有root字符的行前。

  • a

a 在匹配后面插入:
sed 'aaddTest' filename
sed 'a\addTest' filename
将addTest字符串追加到file文件每行的后面。
这个两种写法都对,sed认为参数的第一个是命令,可以在a参数后面加\转义,一便区分。

  • i

i 在匹配前插入
sed 'i\addTest' filename
将addTest字符串插入到file文件每行的前面。

  • p

p 打印
sed 'p' filename
打印file文件,但每一行会打印两次,因为加p会打印文件内容,但默认会打印缓存的行,所以每一行会打印两边。

  • d

d 删除
sed '3d' filename
删除file文件的第三行
sed '3,5d' filename
删除file文件的第三行到第五行
sed '/root/d' filename
删除file文件的有root的一行

  • s

s 查找替换
sed 's/lisi/zhangsan/' filename
将file文件行的lisi替换为zhangsan
sed '/user/s/lisi/zhangsan/' filename
将file文件行有user字段的lisi替换为zhangsan

  • c

c 更改
sed 'c\addTest' filename
将file文件每行改为addTest
sed '3c\addTest' filename
将file文件第三行改为addTest
sed '2,5c\addTest' filename
!> 注意2,5在c参数里与其他参数有区别,它会将2到5行视为一行,也就是将2到5行全部删除然后只插入一条addTest。

  • y

y 转换 N D P
sed 'y/abcd/ABCD' filename
将file文件行的a,b,c,d 转换为对于的A,B,C,D
!> 注意!前面的第一个字符会被后面的一个字符代替,并不是一定要有关系也可以用其他任意字符代替前面的字符,只需要位置顺序相 同。

flags

数字 :表示新文本的替换模式
sed 's/lisi/zhangsan/' filename
我们在使用查找替换内部命令s的时候,如果这一行有两个lisi这条命令只会替换第一个lisi,后面的lisi并不会替换
sed 's/lisi/zhangsan/2' filename
此时就只会处理第二个lisi,而不会处理第一个或者其他位置的lisi

g :表示用新文本替换现有外部的全部实列
sed 's/lisi/zhangsan/g' filename
此时就会处理替换行内所有的lisi

p :表示打印内容
sed '3s/lisi/zhangsan/p' filename
将第三行替换的同时在打印一遍

w :将替换结果写入到文件
sed 's/lisi/zhangsan/w tmpfile' filename
将替换的行写入到tmpfile文件保存,源文件不变

options

-n 抑制输出,只打印我要求打印的
sed -n '3s/lisi/zhangsan/p' filename
只会打印我要求的(p参数)的行,其他行不打印

-e script
将脚本中指定的命令添加到处理输入时执行的命令中,多条件,一行中要有多个操作
sed -e 's/tmp/Tmp/;s/fish/bash/' filename
;区分多条命令。

-f script 将文件中指定的命令添加到处理时执行的命令当中。
在cmd文件中添加命令,一行一个,使用是指定即可执行
cmdfile内容:

3s/root/ooo/
/root/s/abc/bca/

使用命令:
sed -f cmdfile filename
即可使用cmd文件内的命令

-i 编辑文件内容(修改源文件)
sed -i 's/root/ooo/g' filename
此时会修改源文件,并且不会打印到屏幕上

-i.xxx 先备份文件以.xxx结尾在编辑文件内容(修改源文件)
sed -i.bak 's/root/ooo/g' filename
此时会先备份一份源文件文件名末尾是.bak,然后再修改源文件,并且不会打印到屏幕上。

推荐使用 -i.xx 以防万一改错了还能恢复。

-r 使用扩展的正则表达式
sed -n -r '/^(root)(.*)(fish)$/p' /etc/passwd
在匹配模式中使用正则表达式,打印以root开头中间除回车以外的任意字符(该字符不出现或出现多个 以fish结尾的行
内容:
root:x:0:0::/root:/bin/fish

! 取反,跟在模式条件后面(与shell有所区别)

命令总结

增: a(行后),i(行前)
i(将后面指定文件的内容追加到匹配的行后)
w(将结果另存文件)

删:d

改(部分):
s/pattern/string/(查找pat替换为string(默认只配一个))
s/patern/string/g(g表示行内全部匹配)
s/patern/string/2(2表示同行之匹配2个)
s/patern/string/ig(ig表示匹配时忽略大小写)

查:p(将结果打印)

小技巧

统计一个文件有多少行:
sed -n '$=' filename

打印file内容时加上行号
sed '=' filename


awk

简介
awk其实也是一种行编辑器,可以把数据截取,处理(运算),输出,功能十分强大。

awk的工作方式是读取数据将每一行数据视为一条记录(record)每条记录以字段分割符分成若干字段,然后输出各个字段的值。

语法
awk [options] [BEGIN]{program} [END][file]
优先级:BEGIN{} -> {program} -> END{}

program和END需要数据源不能脱离数据源执行。
BEGIN是在program之前处理的,它不需要数据源也可以执行如:
awk 'BEGIN{print "HelloWorld"}'
没有制定文件名有没有通过管道传输数据,就可以执行。

提取列

awk可以用与确认列的参数符

参数含义
$0全部的列
$n指定第n列如:$3(第三列
$NF最后一列

awk默认在行数据里是以空格分隔的
提取test文件全部列

awk '{print $0}' test

提取/etc/passwd文件每一行的第一列
因为此文件里列是以:分隔的所以指定分隔符使用 -F
awk -F ":" '{print $1}' test
还可以对列进行处理:
awk -F ":" '{print "User:" $1, "Shell:" $NF}' test

如果只想处理要第一行,可以使用NR==n来指定行。
awk -F ":" 'NR==1{print "User:" $1, "Shell:" $NF}' test


awk高级用法

awk就是一门语言,它拥有语言的特性,可以定义变量,数组,可以进行运算,流程控制。

定义变量:
awk 'NR==1{user=$1,print user}' passwd
结果:root
还可以使用 -v 定义变量
awk -v num=10 'BEGIN{print num}'

定义一个数组:

awk 'BEGIN{array[0]=root;array[1]=200;print array[0],array[1]}'
#输出
root 200

awk运算符

赋值运算 =
比较运算 > >= == < <= !=
数学运算 + - * / % ** ++ --
逻辑运算 && ||
匹配运算 ~ !~

运算例子:

awk 'BEGIN{print 100>=2 && 1<=100}'
1   #打印

为真打印1,为假打印0
匹配例子:

#精确匹配
awk -F ":" '$1 == "root"{print $0}' passwd

精确不匹配
awk -F ":" '$1 != "root"{print $0}' passwd

模糊匹配
awk -F ":" '$1 ~ "ro"{print $0}' passwd

模糊不匹配
awk -F ":" '$1 !~ "ro"{print $0}' passwd

awk 环境变量

--|--
|FIELDWIDTHS|自定义列的宽度以确认列的分隔|
|FS|输入行中的列分隔符(与-F相同)|
|OFS|输出行中的列分隔符用于显示效果(默认空格)|
|RS|输入行的分隔符(默认行分隔符\n)|
|ORS|输出行的分隔符(默认分隔符\n)|

例子:

awk'BEGIN{FIELDWIDTHS="1 2 3"}NR==1{print $1,$2,$3}' file
#自定义列宽,以列宽确认列的分隔,第一列长度为1字符,第二列为2字符,第三列为3字符。

awk 'BEGIN{FS=":"}NR==1{print $1,$2,$3}'
#效果和-F ":"相同
awk 'BEGIN{OFS="-"}NR==1{print $1,$2,$3}' file
#$1,$2,$3之间不在是空格分隔而是“-”

awk 'BEGIN{RS=" "}{print $1,$2,$3}' file
#此时输出效果为[第1行  第2行  第3行]
#行与行之间不在进行换行
#都在一行中显示以自定义的空格来区分。

awk 'BEGIN{ORS}{print $0}' file
#现在输出在屏幕上的行末尾不在换行。

awk 流程控制

awk支持以下流程控制语句
if for while do ... while break

if

源式子:
seq 1 9 > num
awk '$1>5{print $0}' num
会打印$1大于5的行

用if写:
awk '{if($1>5)print $0}' num
注意if后面紧跟需要执行的语句,否则不认为和if有关联。

else:
awk '{if($1<5)print $1*2;else print $1/2}' num
如果小于5就乘2打印,如果大于5就除2打印

for

seq 1 10 > num
awk -v num=0 '{num=num+$1}END{print num}' num
将每一行相加,最后打印结果为55

用for写:
cat num2
10 82 26
39 24 42
39 28 99

awk '{num=0;for(i=1;i<4;i++)num+=$i;print num}' num2
每行的列相加打印:
118
105
166

while

cat num2
10 82 26
39 24 42
39 28 99

awk '{num=0;i=1;while(i<4){num+=$i;i++}print num}' num2
打印:
118
105
166

do ... while

cat num2
10 82 26
39 24 42
39 28 99
其实与while一样,只不过这种写法是先执行一次在判断,while是先判断在执行。

awk '{num=0;i=1;do{num+=$i;i++}while(i<4)print num}' num2
打印:
118
105
166

break

可在循环中搭配if跳出循环
cat num2
10 82 26
39 24 42
39 28 99
在循环中判断当num大于50时跳出循环

  • while-break

awk '{num=0;i=1;while(i<4){num+=$i;i++;if(num>50)break}print num}' num2
输出:
92
63
67

  • for-break

awk '{num=0;for(i=1;i<4;i++){num+=$i;if(num>50)break}print num}' num2
输出:
92
63
67


awk字符串处理函数

|函数名|解释|函数返回值|
--|--
|length(str)|计算字符串长度|整数长度值|
|index(str1,str2)|在str1中查找str2的下标|索引,从1计数|
|tolower(str)|转小写|转换后的str|
|toupper(str)|转大写|转换后的str|
|substr(str,m,n)|截取从str的m开始长度n|截取后的字符串|
|split(str,arr,fs)|按fs切割str结果存为arr|切割后的子串的个数|
|match(str,RE)|在str中查找RE位置|位置索引|
|sub(RE,RepStr,str)|将str中符合re的替换为repstr(只替换一个)|替换的个数|
|gsub(RE,RepStr,str)|将str中符合re的全部替换为repstr|替换个数|


awk小技巧

打印test文本的行数:
awk 'END{print NR}' test

打印test文本最后一行内容:
awk 'END{print $0}' test

打印test文本最后行的列数:
awk 'END{print NF}' test
打印指定行的列数:
awk 'NR==n{print NF}' num2


find 文件查找

find语法 :find ./ -name test.txt
find常用选项

常用选项:
-name 根据文件名搜索
-iname 根据文件名搜索(不区分大小写)
-user 搜索文件属主(用户名)的所有文件
-group 搜索文件属组(组名)的所有文件
-type :
find . -type f 文件
find . -type d 目录
find . -type c 字符设备文件
find . -type b 块设备文件
find . -type l 链接文件
find . -type p 管道文件

-size :
find . -size -nc 小于n字节的文件
find . -size +nM 大于1M的文件
find . -size nk 等于nKb的文件
!> 不建议使用精准匹配大小,有很多问题。

-mtime :
find . -mtime -n n天以内修改的文件
find . -mtime +n n天以外修改的文件
find . -mtime n 正好n天修改的文件

-mmin 效果同上,不过单位是分钟。

-mindepth n 查找n目录层级
查找2级子目录下的普通的文件。
find . -mindepth 2 -type f
!> 当多参数时mindepth必须要在第一个位置

-maxdepth n 表示最多搜索到n-1级子目录,不会遍历全部目录。

了解选项:
-nouser 搜索没有属主的
-nogroup 搜索没有属组的
-perm 655 搜索指定权限的

-prune 排除文件
搜索文件时排除test_1目录
find . -path ./test_1 -prune -o -type f
排除多个目录
find . -path ./test_1 -prune -o -path ./test_2 -prune -o -type f

-prune语法较为怪异。

-newer Afile 查找比Afile新的文件

文件操作
-print 将查询结果显示,默认开启。
-exec 对结果执行命令:
find . -name '*.bak' -exec cp {} /tmp/ \;
{}代表搜索到的结果, \;为特定格式。
-ok-exec功能相同但每次操作会给用户提示

逻辑运算符
-a 与 搜索条件之间的默认使用的运算符
-o
-not !


whereis

查命令二进制文件,命令man文档,命令源码。
参数:
-b 只返回二进制文件
-m 只返回帮助文件
-s 只返回源码文件(无则不返回)

无参数使用时默认使用全部参数。

which

将一个默认参数-b只返回唯一二进制文件。