《linux私房菜》这本书中将sed和awk一同归为行的修改这一点,虽然对,但不利于实际处理问题时的思考。因为这样的话,当我们实际处理问题时,遇到比如说统计文本打印内容时,我们选择sed还是awk进行处理呢?
也因此
grep更适合单纯的查找或匹配文本,sed更适合编辑匹配到的文本,awk更适合格式化文本,对文本进行较复杂格式处理。
这样的思路更便于我们处理问题时的思路。
比如我们的变量应用文本,需要根据环境进行编辑时,这时候使用sed来编辑脚本便是我们第一时间能想到的了。
awk
awk命令正如上面所说,可以格式化文本
体现就在于它的分隔符上,默认是空格。
修改方式有两种
awk -F":" aa.txt
awk '{FS=":"}' aa.txt
第二种会导致第一行不适用,需要在BEGIN中编写,因此直接用第一种。
awk根据分隔符可以将行内容分为多段,每段按照从左到右的顺序,用$1,$2, $3…来输出。$0输出整行。
基础使用可以输出指定列
比如说这个问题
计算内存和。
a=0
b=$(cat nowcoder.txt|sed '1d'|awk -F" " '{print $4}')
echo $b
for i in $bdoa=$(echo "$a+$i"|bc)done
echo $a
此外awk的内容是可以包含三部分的,除了必须的逐行处理的内容,还可以包含BEGIN和END的内容。BEGIN表示逐行处理前,END表示逐行处理结束后。
也即如下
awk 'BEGIN{FS=":"} {print $3} END{print "aaa"}' aaa.txt
aaa.txt如下
a:b:c
输出如下
END可以获取到在逐行处理中的变量,下面有示例可以看到。
awk功能光如此也不足道,强的地方还在于它的逻辑处理。
我们可以在文本内部写java语法的循环判断,而不用遵守shell的循环判断语法格式
如下面这个问题,
awk '{num[$2] += 1} END{for(a in num) if(num[a] >= 2) print num[a] a}' nowcoder.txt|sort -n
#除了内部循环以外也使用了一维数组。shell中变量在赋值时就会完成初始化,这种东西见仁见智吧,我不觉得有啥好用的。
shell的变量没有定义都是字符串,自然数组的指针也能是字符串。
可以看到,awk确实可以进行相对复杂的格式化处理。
又因为shell中数组指针是字符串,我们可以用此来定义多维数组,如何理解?也就是说我们可以定义一个类似于这样的数组
num[1,2]=xxxxx
num[1,3]=yyyyy
其中的"1,2"就是这个指针的字符串。
当我们想取时可以用循环遍历来取。
上面说的这些都是在awk块内部建立的,其余地方使用会报错的
你可能会想行数和列数怎么确定呢,事实上不存在给你一个已生成的数组,数组的初始化一般都是你自己建立的。所以行数和列数你是已知的。实在不知道,那就只能for a in 数组来遍历打印看看了。
如下面这个问题用到了二维数组
使用二维数组编写如下
awk '{for(i=1;i<=NF;i++){num[NR,i]=$i}} END{for(j=1;j<=(i-1);j++) {for(k=1;k<=NR;k++){printf num[k,j]"\t"}printf "\n"
}}' nowcoder.txt
END代码块中,NR最后保存为行数, i-1为列数。
awk使用能熟练到这个程度就差不多够了。
sed
grep更适合单纯的查找或匹配文本,sed更适合编辑匹配到的文本,awk更适合格式化文本,对文本进行较复杂格式处理。
还是这个思路,那么当我们遇到单纯编辑文本时,就可以直接考虑用sed
sed命令还是很强大的,
在我工作过程中,关于nginx配置文件的编辑,环境变量配置文件根据环境进行的修改来写脚本文件时,都会用到这个命令。
sed简单使用时,可以在指定的行下添加新行,删除该行,根据正则替换行内匹配到的内容。
如下面这个问题。
sed '/^.*[bB].*$/d' nowcoder.txt
sed使用并不复杂,因此用来处理的问题也不算复杂,但是该用的时候还是很好用的。
上面是匹配到对应行就删除该行,格式为
sed '/正则/d' 文件名
另一个比较常用的是替换
格式为
sed 's/正则/替换的内容/g' 文件名
如下面这个题