文本利器AWK

jopen 9年前


awk 是一个强大的文本分析工具,相对于 grep 的查找,sed 的编辑,awk 在其对数据分析并生成报告时,显得尤为强大。简单来说 awk 就是把文件 逐行 的读入,以 空格 为默认分隔符将每行切片,切开的部分再进行各种分析处理。

基本的语法是

awk 'BEGIN{ print something} pattern {commands} \  END{print something}' file

AWK BEGIN用法

$ echo -e "line1\nline2" | awk 'BEGIN{ print "start"} { print } \   END { print "END" }'  start  line1  line2  END

特殊变量

$ echo -e "line1 f2 f3 \n line2 f4 f5\n line3 f6 f7" | awk '{  print "Line no:"NR",No of fields:"NF, "$0="$0, "$1="$1,"$2="$2, "$3="$3 }'    Line no:1, No of fields:3 $0=line1 f2 f3  $1=line1 $2=f2 $3=f3  Line no:2, No of fields:3 $0= line2 f4 f5 $1=line2 $2=f4 $3=f5  Line no:3, No of fields:3 $0= line3 f6 f7 $1=line3 $2=f6 $3=f7

NR:当前行号

NF:当前行字段数量

$ seq 5 | awk 'BEGIN { getline;print "Read ahead first line", $0} \  {print $0}'  Read ahead first line 1  2  3  4  5

$0:当前行内容

$1:当前行第一个字段内容

$2:当前行第二个字段内容

Shell 自带的还有其他的一些特殊变量

$0 这个程式的执行名字  $n 这个程式的第n个参数值,n=1..9  $* 这个程式的所有参数,此选项参数可超过9个。  $# 这个程式的参数个数  $$ 这个程式的PID(脚本运行的当前进程ID号)  $! 执行上一个背景指令的PID(后台运行的最后一个进程的进程ID号)  $? 执行上一个指令的返回值 (显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误)  $- 显示shell使用的当前选项,与set命令功能相同  $@ 跟$*类似,但是可以当作数组用

设置字段定界符

$ awk 'BEGIN { FS=":" }{print $NF}' /etc/passwd  /bin/bash  /usr/sbin/nologin  /usr/sbin/nologin  /usr/sbin/nologin  /bin/sync

从 awk 中读取命令的输出

$ echo | awk '{ "grep root /etc/passwd" | getline cmdout; print cmdout }'  root:x:0:0:root:/root:/bin/bash

单词计数

#!/bin/bash  if [ $# -ne 1 ];  then   echo "Usage: $0 filename";   exit -1  fi  filename=$1  egrep -o "\b[a-zA-Z]+\b" $filename | \  awk '{ count[$0]++ }  END{ printf("%-14s%s\n", "word", "count");  for(ind in count)  { printf("%-14s%d\n", ind, count[ind]); }  }'

egrep -o这一行将文本中每一个单词单独作一行输出,为了下面解析方便。

awk 对每行的一个单词计数,主要是利用关联数组的特性,使用count[$0]++来存储 Key-Value 计数。

输出如下:

word          count  dfs           1  gds           2

文件去重

#!/bin/bash  ls -lS --time-style=long-iso | awk 'BEGIN {   getline; getline;   name1=$8; size=$5  }  {   name2=$8;   if ( size==$5 )   {    "md5sum "name1 | getline; csum1=$1;    "md5sum "name2 | getline; csum2=$1;    if ( csum1==csum2)    {     print name1; print name2    }   };   size=$5; name1=name2;  }' | sort -u > duplicate_files  cat duplicate_files | xargs -I {} md5sum {} | sort | uniq -w 32 |\   awk '{ print  "^"$2"$" }' | sort -u > duplicate_sample  echo Removing  comm duplicate_files duplicate_sample -2 -3 | tee /dev/stderr | xargs rm    echo Removed duplicates files successfully.

这段代码用来对文件进行去重。

BEGIN 后的代码z只执行一次,去掉第一行计数。

total 1068  -rw-r--r-- 1 huangyi huangyi 1048576 2015-11-15 10:44 junk.data  -rw-rw-rw- 1 huangyi huangyi     761 2015-11-15 18:32 remove_duplicates.sh  -rw-r--r-- 1 huangyi huangyi      79 2015-11-15 17:39 duplicate_sample

name1 存储第八列的文件名,size 存储第五列的文件大小。

接下来的代码对比相近两行的 md5 值来判断文件是否相同。

size=$5; name1=name2;用来更新比较行。

duplicate_files 存储的是有重复的文件。

Github push 自动化脚本

#!/bin/bash  modified_files=`git status | awk ' /modified:/ {print $2}'`  git add $modified_files  git status  git commit -m "commit from tool"  git push origin master

一般对文件比较多的操作就是修改,因此可以用此脚本 push 到 Github 上。

awk 找出修改文件的路径,多个文件的路径会用空格隔开。

参考

https://www.gnu.org/software/gawk/manual/html_node/Using-BEGIN_002fEND.html

Linux Shell 脚本攻略