1

背景

虽然对awk早有耳闻,据说是个很强大的工具,但一直没机会去了解和使用,最近碰到一个需求,用awk轻松解决,才真正一窥它的厉害。
需求是这样的,应用每次升级都会构建一个新的容器镜像,时间久了,服务器上会积累很多历史镜像,而且因为镜像本身比较大,磁盘消耗特别快,因此需要写一个脚本定期保留最近N个镜像,清除其余历史镜像。
初步列了以下方案

  1. 用java实现(擅长java~~),通过重定向将docker images的输出传给java,java处理完后执行系统命令清除镜像。
  2. 用python处理。
  3. 用bash处理。

java方案虽然可行,但想想代码量就不小,既要处理字符串,又要调用系统命令,而且把java拿来做这种事,总感觉怪怪的。pass。
python不熟,又懒得去学,学完之后估计很长时间不会再用,下次用的时候还得去学,性价比不高,pass。
最理想的就是bash,正宗的脚本语言,但是否有足够能力处理字符串,需要做技术调研,这时想到了awk。

awk介绍

awk不只是linux的一个工具,由于awk脚本具有编程语言三要素,顺序,循环,判断,awk还是一门编程语言,主要用于数据处理和数据计算。awk对文本进行行扫描,以行为单位进行处理,按照以下逻辑进行处理

pattern { action }
pattern { action }
....

其中pattern是匹配条件,actionpattern匹配后执行的动作。
上面提到awk对文本以行为单位进行处理,读取行后,awk默认以空格为切割符对行进行切割(split)操作并按顺序存放在变量$1$2,$3....中,其中$0表示完整行数据,这些变量可以用于patternaction
举个例子,比如用ps -ef列出目前系统进程

zhengjianfengdeMacBook-Pro:shell asan$ ps -ef
  UID   PID  PPID   C STIME   TTY           TIME CMD
    0     1     0   0 17 418  ??        21:55.75 /sbin/launchd
    0    37     1   0 17 418  ??         1:50.35 /usr/libexec/UserEventAgent (System)
    0    38     1   0 17 418  ??         0:37.59 /usr/sbin/syslogd
    0    40     1   0 17 418  ??         0:14.22 /System/Library/PrivateFrameworks/Uninstall.framework/Resources/uninstalld
    0    41     1   0 17 418  ??         0:09.93 /usr/libexec/kextd
    0    42     1   0 17 418  ??         4:15.97 /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/FSEvents.framework/Versions/A/Support/fseventsd
    0    44     1   0 17 418  ??         0:36.08 /opt/cisco/anyconnect/bin/vpnagentd -execv_instance
   55    48     1   0 17 418  ??         0:03.84 /System/Library/CoreServices/appleeventsd --server

如果我们想要打印出第二列PID的值可以这么写

zhengjianfengdeMacBook-Pro:shell asan$ ps -ef|awk '{print $2}'
PID
1
37
38
40
41
42
44
48

如果想要打印PID大于40值可以这么写

zhengjianfengdeMacBook-Pro:shell asan$ ps -ef|awk '$2>40 {print $2}'
PID
41
42
44
48

本文不是awk入门教程,如果想了解更多awk基本用法,可以阅读以下两篇文章:
http://awk.readthedocs.io/en/...
http://www.runoob.com/linux/l...

实现

获取目前系统镜像列表可以通过命令docker images获取,输出格式如下

[root@definesys /]# docker images
REPOSITORY                                                   TAG                 IMAGE ID            CREATED             SIZE
docker.io/xxxxx-authority-ms                                 v1.0.3              02da1a24ac2c        4 days ago          692 MB
docker.io/xxxxx-authority-ms                                 v1.0.2              4a36396f0fea        4 days ago          692 MB
docker.io/xxxxx-uc-user-ms                                   v.1.1.11            6f0db317c7a9        5 days ago          695 MB
docker.io/xxxxx-uc-user-ms                                   v.1.1.10            26983c00bb73        6 days ago          695 MB
docker.io/xxxxx-uc-user-ms                                   v1.1.9              f21d59255405        7 days ago          695 MB
  1. 获取镜像列表

第一步就是要先获取系统的镜像列表,也就是对REPOSITORY进行去重操作,awk去重有个经典的写法。

awk '!a[$0]++ {print $0}'

声明一个hash数组a并且以$0即行数据为key,第一次a[$0]值是未定义的(undef)取反后为true输出,++对a[$0]进行赋值,赋值后a[$0]值为1,第二次a[$0]为1,取反后为0,0++还是0不输出。
对镜像列表进行去重操作可以以镜像名称(REPOSITORY)为key进行去重

docker images|awk '!a[$1]++ {print $1}'
  1. 获取历史镜像

要保留最近N个镜像清除历史镜像,其实就是保留数据前N行,awk有个内置变量NR保存当前处理行编号。结合第一步获取的镜像名称可以先grep出指定镜像列表,再用awk进行筛选.

docker images|grep $image|awk 'NR > 4 {printf "%s:%s:%s\n",$1,$2,$3}'
  1. 完整脚本
#!/bin/sh
#create by jianfeng.zheng
#group docker images
for image in `docker images|awk '!a[$1]++ {print $1}'`
do
        for m in `docker images|grep $image|awk 'NR > 4 {printf "%s:%s:%s\n",$1,$2,$3}'`
        do
                id=`echo $m|awk -F ":" '{print $3}'`
                ##do delete
                echo 'delete docker== > '$m
        done
done

结语

awk还有很多功能待挖掘,但可以肯定的是,以后Linux上数据处理的工作,首选方案就是awk。


DQuery
300 声望93 粉丝

幸福是奋斗出来的