背景
做运维一年了,突然发现自己python和php写了不少。基本的shell却一直搁置没有系统性的去学习总结。 其实在日常工作中,能合理高效的使用shell会提高不少效率。这也是运维工程师必备的基本素质。所以这里决定把一些简单的shell知识点写下来备忘。本博文并没有什么技术含量,主要是用来总结与备忘的,众位求知者可绕行。
内容
一、 什么是awk?
awk的主要功能是把文件逐行的读入,以指定的分隔符(默认为空格)将每行切片,切开的部分再进行各种分析处理。
1 |
使用方法:awk [options] '{pattern + action}' {filename} |
options 为awk的参数变量,主要常用的有如下三种:
1 2 3 4 5 |
-F 指定输入文件折分隔符,如-F:,默认为空格。 -v var=value :赋值一个用户定义变量。 -f scripfile :从脚本文件中读取awk命令。 |
pattern 为数据中查找的内容,可以有如下方式:
1 2 3 4 5 6 7 8 9 10 11 |
(1)正则表达式:使用通配符的扩展集,awk查找的内容,通常用/括起来。 (2)关系表达式:可以用下面运算符表中的关系运算符进行操作,可以是字符(3)串或数字的比较,如$2>$1选择第二个字段比第一个字段长的行。 (4)模式匹配表达式:用运算符~(匹配)和~!(不匹配)。 (5)模式,模式:指定一个行的范围。该语法不能包括BEGIN和END模式。 (6)BEGIN:让用户指定在第一条输入记录被处理之前所发生的动作,通常可在这里设置全局变量。 (7)END:让用户在最后一条输入记录被读取之后发生的动作。 |
action 是在找到匹配内容时所执行的一系列命令,主要包括:
1 2 3 4 5 6 7 |
(1)变量或数组赋值 (2)输出命令 (3)内置函数 (4)控制流命令 |
filename 是目标文件。
典例: 找出/etc/passwd 文件中以root开头的行,并且输出这行的用户名和使用的shell,以及匹配的总行数。
1 2 3 4 5 |
awk -F ":" -v count=0 '/^root/ {count++; print $1 "," $7} END {print count }' /etc/passwd options : -F pattern: /^root/ action: print $1 "," $7 filename : /etc/passwd |
如上,awk会先从/etc/passwd文件中找出符合pattern格式的行,然后再执行输出去操作。
二、awk 内置变量
1 2 3 4 5 6 7 8 9 10 11 12 13 |
ARGC 命令行参数个数 ARGV 命令行参数排列 ENVIRON 支持队列中系统环境变量的使用 FILENAME awk浏览的文件名 FNR 浏览文件的记录数 FS 设置输入域分隔符,等价于命令行 -F选项 NF 浏览记录的域的个数 NR 已读的记录数 OFS 输出域分隔符 ORS 输出记录分隔符 RS 控制记录分隔符 $0 整条记录 $1 分隔后的第一个变量 |
典例1: 用awk 输出/etc/passwd 的文件名,每行的行号,每行的列数,对应的完整行内容。
1 |
awk -F ":" '{ print "filename:" FILENAME , "行号:" NR, "列数:" NF, "内容:"$0 }' /etc/passwd |
典例2:显示/etc/passwd的账户和账户对应的shell,而账户与shell之间以逗号分割,而且在所有行添加”this is begin”,在最后一行添加”this is end”。
1 |
awk -F ":" 'BEGIN { print "this is begin" } { print $1 "," $7 } END { print "this is end"}' /etc/passwd |
上面这个例子中,awk工作流程是这样的:先执行BEGIN,然后读取文件,读入有/n换行符分割的一条记录,然后将记录按指定的域分隔符划分域,填充域,$0则表示所有域,$1表示第一个域,$n表示第n个域,随后开始执行模式所对应的动作action。接着开始读入第二条记录······直到所有的记录都读完,最后执行END操作。
三、awk编程
awk的编程设计的东西很多,这里挑选几个常用的简单叙述一下:
1. awk中的变量
awk设置变量的方式有两种,一种是通过-v参数,在options里面声明。 另一种是直接在action里面定义。 如下:
1 2 3 |
方式1: awk -F ":" -v count=0 '/^root/ {count++; print $1 "," $7} END {print count }' /etc/passwd 方式2:awk -F ":" '{count++;print $0;} END {print count}' /etc/passwd |
count是自定义变量,action{}可以有多个语句,以;号隔开。
典例: 统计test文件夹下,所有文件的总大小(为字节数)
1 |
ls -al test/ | awk -v size=0 '{ size += $5 } END { print "Total size is " size } ' |
2. awk 中的条件判断语句
awk中的条件语句是从C语言中借鉴来的,见如下声明方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
if (expression) { statement; statement; ... ... } if (expression) { statement; } else { statement2; } if (expression) { statement1; } else if (expression1) { statement2; } else { statement3; } |
典例2: 将test目录下面大于10k的文件都移到tmp目录下。
1 |
for f in `ls -al | awk '{if ($5 > 7500) {print $9;}}'`; mv $f /tmp/ ; done |
3. awk中的循环语句
awk中的循环语句同样借鉴于C语言,支持while、do/while、for、break、continue,这些关键字的语义和C语言中的语义完全相同。
4. awk中的数组
因为awk中数组的下标可以是数字和字母,数组的下标通常被称为关键字(key)。值和关键字都存储在内部的一张针对key/value应用hash的表格里。由于hash不是顺序存储,因此在显示数组内容时会发现,它们并不是按照你预料的顺序显示出来的。数组和变量一样,都是在使用时自动创建的,awk也同样会自动判断其存储的是数字还是字符串。一般而言,awk中的数组用来从记录中收集信息,可以用于计算总和、统计单词以及跟踪模板被匹配的次数等等。
典例:显示/etc/passwd的账户,并在前面标上行数
1 |
awk -F ':' 'BEGIN {count=0;} {name[count] = $1;count++;}; END{for (i = 0; i < NR; i++) print i, name[i]}' /etc/passwd |
参考:
http://www.gnu.org/software/gawk/manual/gawk.html
http://www.cnblogs.com/ggjucheng/archive/2013/01/13/2858470.html
http://www.cnblogs.com/azheng007/p/3037246.html