Linux文本处理

本文介绍linux文本处理工具,包括grep、awk、sed等工具。

1. grep

查找某个文件的内容:

grep 'hello' hello.txt #从文件hello.txt中查找字符串hello
grep 'hello' *.txt # 从所有以.txt结尾的文件中查找字符串hello

只显示匹配到的字符串:

echo 3hi4hi5 | grep -o hi

查找文件夹的内容:

grep 'hello' -r * #查找当前文件夹下所有文件
grep 'hello' -r dir1 dir2 #查找多个文件夹的内容

查找某一后缀的文件内容:

find . -name "*.h" | xargs grep "abc"
#find查找多个后缀:find . –name "*.h" –or –name "*.cpp"
#其中-or表示或,-and表示且

查询正则表达式:

grep -P '正则表达式' filename
#如果要只显示正则表达式匹配到的那一部分,加上-o

显示匹配行的上下N行记录:

grep -C 5 foo file  显示file文件中匹配foo字串那行以及上下5grep -B 5 foo file  显示foo及前5grep -A 5 foo file  显示foo及后5

反匹配:

grep -v hello hello.txt

不区分大小写:

grep -i hello hello.txt

高亮显示匹配的字符串:

echo 3hi4 | grep --color hi

2. awk

最简单的,awk用于分隔字符串,以“行”为单位。

echo "hi,you" | awk -F"," '{print $1}' #打印hi
echo "hi,you" | awk -F"," '{print substr($2,1,2)}' #打印yo
echo "3,nick" | awk -F"," '{if($1>1)print $2}' #if判断

具体的,awk的基本格式是:

awk -F"分隔符" '条件1{代码段1}条件2{代码段2}条件3{代码段3}' 处理文件名

常用的条件有:

  • BEGIN 相当于初始化,在开始时执行一次
  • END 在结束时执行一次
  • NR>1 从文件的第二行开始处理,不处理第一行
  • FNR==NR 当有多个文件时,这个表示第一个文件的行,其中FNR是当前文件处理的行数
  • FNR>NR 当有2个文件时,这个表示第二个文件的行

例如:

echo "hi" | awk 'BEGIN{print "hello"}END{print "bye"}'

awk有强大的数组(其实是map)来存放临时数据,通过这个就可以实现统计数据、联合数据等多种功能,数组不需要事先定义。假设有文本文件:test.txt

水果    个数
苹果    3
香蕉    5
苹果    6
橙子    2
香蕉    1

如果要统计每种水果总的个数,例如苹果是3+6=9个,使用awk统计代码如下:

awk 'NR>1{a[$1]+=$2}END{for(i in a)print i"\t"a[i]}' test.txt
#香蕉    6
#橙子    2
#苹果    9

awk在处理日期相关时的代码:

echo hi | awk '{print systime()}' # 输出当前时间unix时间戳
echo hi | awk '{print strftime("%Y-%m-%d",1356364800)}' # 转换格式
echo hi | awk '{print strftime("%Y-%m-%d %H:%M:%S",1356364800)}' # 转换格式

一般我们使用SQL语句对表进行统计,都是按行进行处理,相应的,awk也可以实现SQL语句的功能,详见这里。这裡是一个简单的对应表,仅演示思路:

awkSQL
a[A]=…group by A
if(…){}where …
NR==FNR{a[…]=…}NR>FNR{print $0,a[…]}a join b on a.id=b.id
END{if(…){}}having …
!b[A]{a[A]+=1;b[A]=1}count(distinct A)

awk代替xargs

xargs常常和find一起使用,用于对查找到的文件进行处理,例如查看文件内容:

find . -name "*.txt" | xargs cat
find . -name "*.txt" | xargs -i cat {} #等价于这条,-i和{}配合使用,{}表示当前参数

当处理的命令里出现>或|等特殊符号时,应使用sh命令来执行,比如我想把找到的每个文件的内容打印出来并追加到指定目录的相同文件名文件后面:

find . -name "*.txt" | xargs -i cat {} >> ~/{} #这样是不行的
find . -name "*.txt" | xargs -i sh -c "cat {} >> ~/{}" #这样是可以的

awk和xargs一样是按行处理的,可以实现相同的功能:

find . -name "*.txt" | awk '{system("cat "$0)}' #输出文件内容
find . -name "*.txt" | awk '{system("cat "$0" >> ~/"$0)}' #追加到相同文件末尾

可以看到,awk表现出了强大的处理能力。 awk有个问题是,system()函数里面很难再写执行awk命令的语句,单引号是主要问题,此外可读性差。

3. sed

最简单的,sed用于替代字符串,以“行”为单位。sed简明教程

#g表整行,否则只替换第一个
sed -r 's/查找字符串/替换字符串/g' filename
sed -r '/有此字符串的行/s/查找字符串/替换字符串/g' filename
文档更新时间: 2018-11-10 20:27   作者:nick