知识共享许可协议本作品采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可。本文仅作为个人学习记录使用,欢迎在许可协议范围内转载或使用,请尊重版权并且保留原文链接,谢谢您的理解合作。如果您觉得本站对您能有帮助,您可以使用RSS方式订阅本站,这样您将能在第一时间获取本站信息。

为啥写这个

最近的工作里面,因为需要处理很多类似CSV之类的文本文件,让我突然想到了sed和awk这两个上古神器。并且在这两个神器的帮助之下,很多尝试性的工作减少了实际的代码编写量,毕竟脚本和C代码的代码量来看,脚本的编写要更加容易以及快速,在做一些探索性的尝试和对文本文件的处理上,是非常有帮助的。这一篇会随着我的使用慢慢的增多,我会慢慢给大家分享这两个神器以及其他的一些linux或是unix下一些工具的使用,所以潮一点就叫Cookbook了,这里面的命令很多是可以解决实际问题的,我也会对这些命令进行分析,告诉大家什么时候可以用、以及怎样用,同时也希望大家能对这些问题有更新更加优美的解决方法。

关于Awk的

awk拼接命令

awk是一个文本流处理的工具,但是结合了awk,grep,sh以及一些常规的linux命令后,也可以实现通过awk输出shell的脚本,达到自动生成一些命令并执行的效果。

ipc资源清理

公司用的后台服务是tuxedo的,用过的人大概知道,服务配置太多了或者挂了的服务太多了等各种原因会导致整个tuxedo服务器挂掉,这时候tmshutdowntmipcrm都已经失效了,那这时候怎么办呢——杀掉所有tuxedo用户下的ipc资源,那这样一个一个的清除会很麻烦,经过一段时间的Google发现了下面三条命令解决了这个问题

1
2
3
4
5
6
7

ipcs|grep user_name|awk '{print "ipcrm -m " $2}'|sh;

ipcs|grep user_name|awk '{print "ipcrm -q " $2}'|sh;

ipcs|grep user_name|awk '{print "ipcrm -s " $2}'|sh;

乍一看去,似乎很复杂,ipcs喽,grep喽,awk喽各种$号之类的,不过这个应该是我们要处理的较简单的命里了,我们来一步一步的解析这个命令是个什么意思。

  1. ipcs获取所有的系统ipc资源,之后通过管道输出给grep

  2. grep user_name这里是通过grep过滤所有不是user_name的ipc资源,把所有属于user_name这个用户的ipc资源的结果输出给awk继续处理

  3. awk '{print "ipcrm -m " $2}'或者awk '{print "ipcrm -q " $2}'或者awk '{print "ipcrm -s " $2}'这句应该是整个核心处理的内容,他做这几个事情,从上一步获取的数据,将每行第二列的内容和ipctm -m/s/q进行拼接,ipcs输出的第二列就是ipc资源的ID,这样我们就会得到这样的输出ipcrm -m XXXX等多行的输出但是这样还不够,awk的处理结果是将所有的东西通过流输出,那还是达不到执行的结果,这样再通过管道将输出的文本,发送给sh,sh也就是shell的命令行,并且他可以接受一个字符流的参数执行命令。

这样便很简单的通过三个命令拼接了很多条命令,将所需要干掉的东西全都干掉了。

接下来我们来看一个延伸,假设我有很多个路径,每个路径下面都有很多要编译的代码,现在我要用一条命令去执行每个路径下makefile的clean命令,清理所有编译的结果,那么我们就写出了下面的命令

1
2
3

ls -1 -d */ | awk '{print "make -f " $1 "makefile clean"}' | sh

这里通过awk拼接ls出来的结果,将ls出来的所有路径拼接上我们要执行的make命令,传给sh去执行,将所有路径下的make clean执行一次

技巧:这里有一个个人觉得的技巧,在|sh之前可以先将命令打印到终端看是否正确,再通过|sh执行。

关于Sed的

Pattern Place和Hold Place

在这里想先说下Hold Place和Pattern Place了,因为在很多有用的,而又诡异的场景里面,我们需要通过Pattern Place和Hold Place来解决我们的问题,顺便也解说下sed是怎么run的,原文可以参考下sed官方文档中——3.1 How sed Works。下面我来给大家解释(雾,其实是翻译)下是怎个回事儿。

Hold Place和Pattern Place是由Sed管理的两个缓冲区。为了下面说的简单点,我就叫他们HP和PP了。PP是每次的活动缓冲区,HP是PP的助手,一开始他们都是空的,接下来我们来看sed到底怎么工作的

  1. 从输入流中获取一行,把空行都去掉
  2. 把它放到PP里面
  3. 执行sed命令
  4. 如果没用-n参数,那么就把结果打印出来,并且把去掉的空行也加回去
  5. 回到第1步继续下一行输入的处理(就这样不断的往复)

嗯嗯,上面一看,我们的HP呢?咋没用到他啊,其实如果没有用一些特殊的命令的话,是不会用到H的,H,h,G,g,x这几个命令将会在循环过程中改变上面对PP和HP中的数据。在sed官方文档说少用的命令里面提到了这些命令,我们来看看他们是干啥的。

  • H:HP = HP + "\n" + PP
  • h:HP = PP
  • G:PP = PP + "\n" + HP
  • g:PP = HP
  • x:交换HP和PP的内容

多行操作的

我们都知道sed是按照行进行处理的,那么一些可以做跨行操作和处理的脚本都会比较麻烦,很多会用到Sed中的hold place之类的东西。挺复杂的,所以在这里把我遇到的这类问题都集中起来,也顺便分析下。

实现多行合并,并且用’|’分隔

我这里用的最多的应该是将一个有多行的文件合并成一个只有一行的输出,有时候还需要使用一些字符来进行分隔。我们先来看这个命令到底长个啥样:

'H;$!d;$g;s/\n/|/g'

看了上面的命令…特别是第一次看的童鞋一定觉得很逆天,或者这个命令肯定是反人类的-,-其实好多sed的命令都挺反人类的

其实这个命令是很简单的,每个;表示一段命令的结束。那么我们来看上面到底做了什么。

  1. H => HP = HP + “\n” + PP
  2. $!d => 除了最后一行都执行d命令,就是清除PP中的内容
  3. $g => 在最后一行执行g命令,就是最后一行把HP中的内容放到PP里面去
  4. s/\n/|/g => 把换行替换成|

这么一分解下,那大家就明白了吧,很多跨行操作以及复杂操作都可以用这种类似的方法的。

最后欢迎大家订阅我的微信公众号 Little Code

公众号

  • 公众号主要发一些开发相关的技术文章
  • 谈谈自己对技术的理解,经验
  • 也许会谈谈人生的感悟
  • 本人不是很高产,但是力求保证质量和原创