前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Linux命令(36)——awk命令

Linux命令(36)——awk命令

作者头像
恋喵大鲤鱼
发布2018-08-03 16:16:34
2.2K0
发布2018-08-03 16:16:34
举报
文章被收录于专栏:C/C++基础C/C++基础

1.简介

AWK是一个优良的文本处理工具,Linux及Unix环境中现有的功能最强大的数据处理引擎之一。数据可以来自标准输入(stdin)、一个或多个文件,或其它命令的输出。它支持用户自定义函数和动态正则表达式等先进功能,是linux/unix下的一个强大编程工具。它在命令行中使用,但更多是作为脚本来使用。awk有很多内建的功能,比如数组、函数等,这是它和C语言的相同之处,灵活性是awk最大的优势。简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。

awk有3个不同版本: awk、nawk和gawk,未作特别说明,一般指gawk,gawk 是 AWK 的 GNU 版本。

awk其名称得自于它的创始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母。实际上AWK的确拥有自己的语言: AWK程序设计语言 , 三位创建者已将它正式定义为“样式扫描和处理语言”。它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报表,还有无数其他的功能。

2.命令格式

代码语言:javascript
复制
awk [options] 'pattern + {action}' [filenames...]

尽管操作可能会很复杂,但语法总是这样。awk通常用来格式化文本文件中的信息,是以文件的一行为处理单位,每接收文件的一行,然后执行相应的命令,来处理文本。其中pattern表示AWK在数据中查找的内容,而action是在找到匹配内容时所执行的一系列命令。花括号{}不需要在程序中始终出现,但它们用于根据特定的模式对一系列指令进行分组。pattern表示的正则表达式,用斜杠括起来,action 对匹配的行进行处理。

注意: (1)pattern缺省为1,action缺省为{print}。 (2)pattern + {action}可以同时存在多个,每个pattern之间的关系是或,只要当前行匹配pattern,则执行pattern后大括号中的commands。

3.常用命令选项

代码语言:javascript
复制
-F fs,--field-separator fs:使用字符串fs作为域分隔符。可以同时指定多个域分隔符,此时需要使用一对中括号括起来。例如使用-和|可写作 -F '[-|]'。如果用[]作为分隔符,可写作-F '[][]'。不指定分隔符,默认为空格和Tab。需要注意,awk命令使用-F' '显示指定空格时,tab也会被作为分隔符。
-v [var]=[val],--assign [var]=[val]:定义一个awk变量并赋值,可以将外部变量传递给awk;
-f [program-file],--file [program-file]:从指定的awk脚本文件program-file读取awk指令;
-m[f/r] val:对val值设置内在限制,-mf选项限制分配给val的最大块数目;-mr选项限制记录的最大数目。这两个功能是Bell实验室版awk的扩展功能,在标准awk中不适用;
-O,--optimize:在程序的内部表示上启用优化。目前,这只包括简单的常量折叠。gawk的维护者系统随着时间推移,增加额外的优化;
-W compat,-W traditional,--compat,--traditional:是awk运行在兼容模式下,gawk的任何扩展都不会被识别;
-W copyleft,--copyleft,-W copyright,--copyright:打印简短的版权信息;
-W dump-variables[=file],--dump-variables[=file]:将awk的全局变量排序后打印到指定的文件file中,如果没有指定file,则在当前目录默认生成一个awkvars.out;
-W exec [file],--exec [file]:功能类似于命令选项-f,但脚本文件需要以#!开头;另外命令行的变量将不再生效;
-W gen-po,--gen-po:解析awk程序,产生.po格式的文件到标准输出,来标明程序中每一个可本地化的字符串位置(自己翻译的可能不准确);
-W help,-W usage,--help,--usage:打印全部awk选项和每个选项的简短说明;
-W lint[=value],--lint[=value]:打印有关在其它版本awk中,出现可疑的或不可移植结构的警告。该选项提供了一个可选的参数fatal,即将警告视为致命的错误;
-W lint-old,--lint-old:打印关于不能向传统unix平台移植的结构的警告;
-W non-decimal-data,--non-decimal-data:识别输入数据中的八进制和十六进制数;
-W posix,--posix:打开兼容模式,会出现以下限制:
    不识别\x;
    当域分隔fs是一个空格时,只有空格和tab能作为域分隔符,换行符将不能作为一个域分隔符;
    在?和:之后,不能继续当前行;
    函数关键字func将不能被识别;
    操作符**和**=不能代替^和^=;
    fflush函数无效。
-W profile[=prof_file],--profile[=prof_file]:输出性能分析报告至指定的文件prof_file,如果prof_file缺省,默认输出到awkprof.out;
-W re-interval,--re-interval:允许间隔正则表达式的使用,参考(grep中的Posix字符类),如括号表达式[[:alpha:]];
-W source program-text,--source program-text:使用program-text作为源代码,可与-f命令混用;
-W use-lc-numeric,--use-lc-numeric:是awk使用本地小数点解析输入的数据(自己翻译的可能不准确);
-W version,--version:打印awk版本信息;
--:标识命令选项结束。(自己翻译的可能不准确)

4.调用awk方式

有三种方式调用awk。

(1)命令行方式。

代码语言:javascript
复制
awk [-F  field-separator]  'pattern + {action}'  input-file(s)

其中,commands 是真正awk命令,[-F域分隔符]是可选的。 input-file(s) 是待处理的文件。 在awk中,文件的每一行中,由域分隔符分开的每一项称为一个域。通常,在不指名-F域分隔符的情况下,默认的域分隔符是空格。

(2)shell脚本方式。 将所有的awk命令插入一个文件,脚本中在首行注明使用awk命令来解析执行,相当于将shell脚本首行的:#!/bin/sh换成:#!/bin/awk,最后通过键入脚本名称来调用。

(3)将所有的awk命令插入到一个单独文件,然后使用-f选项调用。

代码语言:javascript
复制
awk -f awk-script-file input-file(s)

其中,-f选项加载awk-script-file中的awk脚本,input-file(s)跟上面的是一样的。

5.awk内置变量

awk有许多内置变量用来设置环境信息,这些变量可以被改变,下面给出常见的内置变量说明。

代码语言:javascript
复制
$n             当前记录的第n个字段,n从1开始,字段间由FS分隔
$0             当前完成的记录(当前处理行)
ARGC            命令行参数个数
ARGIND          命令行中当前处理文件的位置(从0开始算)
ARGV            命令行参数数组
CONVFMT         数字转换格式,默认值为%.6g
ENVIRON         支持队列中系统环境变量的使用
ERRNO           最后一个系统错误的描述
FIELDWIDTHS     字段宽度列表(用空格键分隔)
FILENAME        awk浏览的文件名
FNR             当前被处理文件的记录数
FS              设置输入域分隔符,等价于命令行-F选项
IGNORECASE      如果为真,则进行忽略大小写的匹配
LINT            动态控制--lint选项是否生效,为false不生效,为true则生效;
NF              浏览记录的域的个数
NR              已读的记录数
OFMT            数字的输出格式,默认值是%.6g
OFS             输出域分隔符
ORS             输出记录分隔符             
RS              The input record separator,输入记录的分隔符,默认为换行符
RT              The record terminator,输入记录的结束符      
RSTART          由match函数所匹配的字符串的第一个位置
RLENGTH         由match函数所匹配的字符串的长度
SUBSEP          数组下标分隔符(默认值是\034)
TEXTDOMAIN      awk程序所使用的文本所处的地域

6.awk编程示例

6.1基础打印输出

(1)假设last -n 5的输出如下:

代码语言:javascript
复制
[root@www ~]# last -n 5 <==仅取出前五行
root     pts/1   192.168.1.100  Tue Feb 10 11:21   still logged in
root     pts/1   192.168.1.100  Tue Feb 10 00:46 - 02:28  (01:41)
root     pts/1   192.168.1.100  Mon Feb  9 11:41 - 18:30  (06:48)
dmtsai   pts/1   192.168.1.100  Mon Feb  9 11:41 - 11:41  (00:00)
root     tty1                   Fri Sep  5 14:09 - 14:10  (00:01)

如果只是显示最近登录的5个帐号:

代码语言:javascript
复制
#last -n 5 | awk  '{print $1}'
root
root
root
dmtsai
root

awk工作流程是这样的:读入有’\n’换行符分割的一条记录,然后将记录按指定的域分隔符划分域,填充域,0则表示所有域,0则表示所有域,0则表示所有域,1表示第一个域,n表示第n个域。默认域分隔符是"空白键"或"[tab]键",所以n表示第n个域。默认域分隔符是"空白键"或"[tab]键",所以n表示第n个域。默认域分隔符是"空白键" 或 "[tab]键",所以1表示登录用户,$3表示登录用户ip,以此类推。

(2)如果想显示/etc/passwd配置文件中的账户以及账户对应的shell,而账户与shell之间以tab键分割。

代码语言:javascript
复制
#cat /etc/passwd |awk  -F ':'  '{print $1"\t"$7}'
root    /bin/bash
daemon  /bin/sh
bin     /bin/sh
sys     /bin/sh

注意,这里使用了-F指定域分隔符为’:’。

(3)如果只是显示/etc/passwd的账户和账户对应的shell,而账户与shell之间以逗号分割,而且在所有行添加列名name,shell,在最后一行添加”blue,/bin/nosh”。

代码语言:javascript
复制
cat /etc/passwd |awk  -F ':'  'BEGIN {print "name,shell"}  {print $1","$7} END {print "blue,/bin/nosh"}'
name,shell
root,/bin/bash
daemon,/bin/sh
bin,/bin/sh
sys,/bin/sh
....
blue,/bin/nosh

awk工作流程是这样的:先执行BEGING,然后读取文件,读入有/n换行符分割的一条记录,然后将记录按指定的域分隔符划分域,填充域,0则表示所有域,0则表示所有域,0则表示所有域,1表示第一个域,$n表示第n个域,随后开始执行模式所对应的动作action。接着开始读入第二条记录······直到所有的记录都读完,最后执行END操作。

(4)搜索/etc/passwd有root关键字的所有行。

代码语言:javascript
复制
#awk -F: '/root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash

上面三种是awk的action的使用示例,而这种是pattern的使用示例,匹配了pattern(这里是root)的行才会执行action(没有指定action,默认输出每行的内容)。

搜索支持正则表达式,例如找root开头的。

代码语言:javascript
复制
awk -F: '/^root/' /etc/passwd

(5)搜索/etc/passwd有root关键字的所有行,并显示对应的shell。

代码语言:javascript
复制
# awk -F: '/root/{print $7}' /etc/passwd             
/bin/bash

这里是awk的pattern+action示例用法,同时指明了action是{print $7}。

(6)打印/etc/passwd第三行的第一列和第二列。

代码语言:javascript
复制
awk -F: 'NR==3{print $1,$2;}' /etc/passwd

#输出结果:
daemon x

6.2.awk在每一列后添加字符串后输出

设定变量内容:

代码语言:javascript
复制
a="/test.html /dir1 /abc.txt"

希望得到

代码语言:javascript
复制
echo $a
--exclude=/test.html --exclude=/dir1 --exclude=/abc.txt

如何用awk实现。

解决办法:

代码语言:javascript
复制
echo $a|awk '{for(i=1;i<=NF-1;++i){printf "-execute=%s ",$i}}{print "--exclude="$NF""}'

#或者
echo $a|awk '{for(i=1;i<=NF;i++){printf "--exclude="$i" "}{print ""}}'

后者是网友给出的答案,和我上面的写法是差不多的,只是对printf在使用形式上有所差别而已。第二种方法print “”是用于换行,print每次输出后默认进行换行。

6.3shell编程使用awk浮点运算保留两位小数

代码语言:javascript
复制
a=3
b=10
c=$(awk 'BEGIN{printf "%.2f",'$a'*100/'$b'}')
echo c:$c%

或者:

代码语言:javascript
复制
c=$(awk -v n=$a -v m=$b 'BEGIN{printf "%.2f",n*100/m}')
echo c:$c%

-v表示定义awk的变量!v是variable的首字母。输出:c:30.00%。

6.4awk访问shell变量

awk默认是无法访问shell变量的,我所知道的有三种方法。 方法一:awk -v 选项让awk 里使用shell变量。

代码语言:javascript
复制
var0=dablelv0
var1=dablelv1
awk -v tmpVar0=$var0 -v tmpVar1=$var1 'BEGIN{print tmpVar0" "tmpVar1}'

输出: dablelv0 dablelv1 注意: BEGIN必须大写,awk的{action}必须要使用单引号括起来。

方法二:'"$var"' 这种写法是老外常用的写法。如:

代码语言:javascript
复制
var="test" 
awk 'BEGIN{print "'$var'"}'

这种写法其实际是双括号变为单括号的常量,传递给了awk。

如果var中含空格,为了shell不把空格作为分格符,应该如下使用:

代码语言:javascript
复制
var="this is a test" 
awk 'BEGIN{print "'"$var"'"}' 

方法三:export 变量,将变量设置为临时会话环境变量,仅在当前shell会话中有效。在awk中使用ENVIRON["var"]形式访问变量。

代码语言:javascript
复制
var="this is a test"
export $var #或者 export var

#或者
export var="this is a test"

awk 'BEGIN{print ENVIRON["var"]}' 

6.5awk执行shell命令

awk执行shell命令有两种方法。 方法一:使用awk的system()函数。

代码语言:javascript
复制
export var=dablelv
awk 'BEGIN{system("echo $var")}'

**输出:**dablelv 注意:一定要使用export将变量设置为临时环境变量,因为awk的system()实际上是新建了一个shell进程来执行给定的shell命令,否则无法访问父进程的变量。

方法二:使用使用print cmd | "/bin/bash"

代码语言:javascript
复制
var="this is a test"
awk 'BEGIN{print "echo ""'"$var"'"|"sh"}'

#或者
var="this is a test"
awk -v varTmp="$var" 'BEGIN{print "echo "varTmp|"sh"}'

输出:this is a test 注意: (1)指定bash的时候需要双引号括起来; (2)方法二与方法一的区别在于方法二是将变量在awk解析后再通过管道传给shell,所以无需将变量设置为临时环境变量,因为shell接收到的变量已经是变量的值。

7.awk常见问题

(1)awk以空格为分隔符Tab也被作为域分隔符。现在只以空格为分隔符,需要使用中括号的方式。不使用中括号,则仍然会将Tab作为分隔符。

代码语言:javascript
复制
#错误的写法
awk -F' ' '{print $1;}' test.txt

#正确的写法
awk -F'[ ]' '{print $1;}' test.txt 

参考文献

[1]man awk [2]Linux命令大全.awk命令 [3]Linux命令大全.Linux awk 命令 [4]linux awk命令详解 [5]Shell脚本之awk篇 [6]awk使用shell变量 [7]awk中使用shell命令 [8]awk按照多个分隔符进行分割

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016年01月01日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.简介
  • 2.命令格式
  • 3.常用命令选项
  • 4.调用awk方式
  • 5.awk内置变量
  • 6.awk编程示例
    • 6.1基础打印输出
      • 6.2.awk在每一列后添加字符串后输出
        • 6.3shell编程使用awk浮点运算保留两位小数
          • 6.4awk访问shell变量
            • 6.5awk执行shell命令
            • 7.awk常见问题
            • 参考文献
            相关产品与服务
            腾讯云 BI
            腾讯云 BI(Business Intelligence,BI)提供从数据源接入、数据建模到数据可视化分析全流程的BI能力,帮助经营者快速获取决策数据依据。系统采用敏捷自助式设计,使用者仅需通过简单拖拽即可完成原本复杂的报表开发过程,并支持报表的分享、推送等企业协作场景。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档