awk中数组用法
awk命令的用法

awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。
简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。
awk有3个不同版本: awk、nawk和gawk,未作特别说明,一般指gawk,gawk 是AWK 的GNU 版本。
awk其名称得自于它的创始人Alfred Aho 、Peter Weinberger 和Brian Kernighan 姓氏的首个字母。
实际上AWK 的确拥有自己的语言:AWK 程序设计语言,三位创建者已将它正式定义为“样式扫描和处理语言”。
它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报表,还有无数其他的功能。
使用方法awk '{pattern + action}' {filenames}尽管操作可能会很复杂,但语法总是这样,其中pattern 表示AWK 在数据中查找的内容,而action 是在找到匹配内容时所执行的一系列命令。
花括号({})不需要在程序中始终出现,但它们用于根据特定的模式对一系列指令进行分组。
pattern就是要表示的正则表达式,用斜杠括起来。
awk语言的最基本功能是在文件或者字符串中基于指定规则浏览和抽取信息,awk抽取信息后,才能进行其他文本操作。
完整的awk脚本通常用来格式化文本文件中的信息。
通常,awk是以文件的一行为处理单位的。
awk每接收文件的一行,然后执行相应的命令,来处理文本。
调用awk有三种方式调用awk1.命令行方式awk [-F field-separator] 'commands' input-file(s)其中,commands 是真正awk命令,[-F域分隔符]是可选的。
input-file(s) 是待处理的文件。
在awk中,文件的每一行中,由域分隔符分开的每一项称为一个域。
通过awk命令统计文件中的行数字数和字符数

通过awk命令统计文件中的行数字数和字符数awk是一种强大的文本处理工具,它可以方便地对文件进行分析和处理。
在本文中,我们将使用awk命令来统计文件中的行数和字符数。
使用awk命令统计行数和字符数的基本语法是:```awk '{行数计数器++} {字符数计数器+=length($0)} END {print "行数:"行数计数器, "字符数:"字符数计数器}' 文件名```其中,`行数计数器++`用于统计行数,每当awk读取一行文本时,行数计数器会自动加1。
`字符数计数器+=length($0)`用于统计字符数,每当awk读取一行文本时,字符数计数器会自动加上该行的字符数。
下面是一个示例,我们将使用awk命令统计一个名为example.txt的文件中的行数和字符数:```awk '{lines++} {chars+=length($0)} END {print "行数:" lines, "字符数:" chars}' example.txt```以上命令将输出文件example.txt中的行数和字符数。
实际使用中,我们可以将以上命令封装成一个shell脚本,以方便多次使用和批量处理。
以下是一个简单的shell脚本示例:```shell#!/bin/bash# 输入文件名read -p "请输入文件名: " filename# 统计行数和字符数count=$(awk '{lines++} {chars+=length($0)} END {print "行数:" lines, "字符数:" chars}' $filename)# 输出统计结果echo $count```保存脚本为count_lines_chars.sh,并给予执行权限。
awkk命令用法

awkk命令用法
awk是一个强大的文本处理工具,它使用一种特定的语法,可以用来进行模式扫描和文本/数据提取。
awk的基本语法如下:
```
awk 'BEGIN{ commands } pattern{ commands } END{ commands }'
```
首先,执行关键字BEGIN标识的{}中的命令。
完成BEGIN大括号中命令的后,开始执行body命令。
逐行读取数据,默认读到分割的内容为一条记录,其实就是行的概念。
将记录按照指定的分隔符划分为字段,其实就是列的概念。
循环执行body块中的命令,每读取一行,执行一次body,最终完成body执行。
最后,执行END命令,通常会在END中输出最后的结果。
awk是输入驱动的,有多少输入行,就会执行多少次body命令。
awk的强大之处在于它支持各种强大的文本处理功能,包括字符串操作、正则表达式匹配、数学运算等。
同时,awk还支持变量和数组,可以方便地进行数据处理和转换。
此外,awk还有许多内置函数和选项,可以用来扩展其功能和灵活性。
例如,可以通过-F选项指定字段分隔符,通过-f选项指定外部函数文件等。
总的来说,awk是一个非常强大的文本处理工具,它可以用来进行数据提取、转换、报告生成等任务。
如果你需要进行文本处理工作,awk绝对是一个值得学习和掌握的工具。
awk用法

用法:文本间隔:# 每行后面增加一行空行awk '1;{print ""}'awk 'BEGIN{ORS="\n\n"};1'# 每行后面增加一行空行。
输出文件不会包含连续的两个或两个以上的空行# 注意:在Unix系统,DOS行包括的CRLF (\r\n)通常会被作为非空行对待# 因此'NF' 将会返回TRUE。
awk 'NF{print $0 "\n"}'# 每行后面增加两行空行awk '1;{print "\n"}'编号和计算:# 以文件为单位,在每句行前加上编号(左对齐).# 使用制表符(\t)来代替空格可以有效保护页变的空白。
awk '{print FNR "\t" $0}' files*# 用制表符(\t)给所有文件加上连贯的编号。
awk '{print NR "\t" $0}' files*# number each line of a file (number on left, right-aligned)# Double the percent signs if typing from the DOS command prompt. awk '{printf("%5d : %s\n", NR,$0)}'# 给非空白行的行加上编号# 记得Unix对于\r 的处理的特殊之处。
(上面已经提到)awk 'NF{$0=++a " :" $0};{print}'awk '{print (NF? ++a " :" :"") $0}'# 计算行数(模拟"wc -l")awk 'END{print NR}'# 计算每行每个区域之和awk '{s=0; for (i=1; i<=NF; i++) s=s+$i; print s}'# 计算所有行所有区域的总和awk '{for (i=1; i<=NF; i++) s=s+$i}; END{print s}'# 打印每行每区域的绝对值awk '{for (i=1; i<=NF; i++) if ($i < 0) $i = -$i; print }'awk '{for (i=1; i<=NF; i++) $i = ($i < 0) ? -$i : $i; print }'# 计算所有行所有区域(词)的个数awk '{ total = total + NF }; END {print total}' file# 打印包含"Beth" 的行数awk '/Beth/{n++}; END {print n+0}' file# 打印第一列最大的行# 并且在行前打印出这个最大的数awk '$1 > max {max=$1; maxline=$0}; END{ print max, maxline}'# 打印每行的列数,并在后面跟上此行内容awk '{ print NF ":" $0 } '# 打印每行的最后一列awk '{ print $NF }'# 打印最后一行的最后一列awk '{ field = $NF }; END{ print field }'# 打印列数超过4的行awk 'NF > 4'# 打印最后一列大于4的行awk '$NF > 4'文本转换和替代:# 在Unix环境:转换DOS新行(CR/LF)为Unix格式awk '{sub(/\r$/,"");print}' # 假设每行都以Ctrl-M结尾# 在Unix环境:转换Unix新行(LF)为DOS格式awk '{sub(/$/,"\r");print}# 在DOS环境:转换Unix新行(LF)为DOS格式awk 1# 在DOS环境:转换DOS新行(CR/LF)为Unix格式# DOS版本的awk不能运行, 只能用gawk:gawk -v BINMODE="w" '1' infile >outfile# 用"tr" 替代的方法。
awk使用规则

awk使用规则awk 是一种很棒的语言。
awk 适合于文本处理和报表生成,它还有许多精心设计的特性,允许进行需要特殊技巧程序设计。
与某些语言不同,awk 的语法较为常见。
它借鉴了某些语言的一些精华部分,如C 语言、python 和bash(虽然在技术上,awk 比python 和bash 早创建)。
awk 是那种一旦学会了就会成为您战略编码库的主要部分的语言。
第一个awk让我们继续,开始使用awk,以了解其工作原理。
在命令行中输入以下命令:$ awk '{ print }' /etc/passwd您将会见到/etc/passwd 文件的内容出现在眼前。
现在,解释awk 做了些什么。
调用a wk 时,我们指定/etc/passwd 作为输入文件。
执行awk 时,它依次对/etc/passwd 中的每一行执行print 命令。
所有输出都发送到stdout,所得到的结果与与执行catting /etc/passwd完全相同。
现在,解释{ print } 代码块。
在awk 中,花括号用于将几块代码组合到一起,这一点类似于C 语言。
在代码块中只有一条print 命令。
在awk 中,如果只出现print 命令,那么将打印当前行的全部内容。
这里是另一个awk 示例,它的作用与上例完全相同:$ awk '{ print $0 }' /etc/passwd在awk 中,$0 变量表示整个当前行,所以print 和print $0 的作用完全一样。
如果您愿意,可以创建一个awk 程序,让它输出与输入数据完全无关的数据。
以下是一个示例:$ awk '{ print "" }' /etc/passwd只要将"" 字符串传递给print 命令,它就会打印空白行。
如果测试该脚本,将会发现对于/etc/passwd 文件中的每一行,awk 都输出一个空白行。
Linux命令高级技巧使用awk进行文件分割和数据提取

Linux命令高级技巧使用awk进行文件分割和数据提取在Linux系统中,awk是一种强大的文本处理工具,它可以根据指定的条件和规则对文本进行分割和提取数据。
使用awk可以使文件的处理更加高效和灵活,提高工作效率。
本文将介绍如何使用awk命令进行文件分割和数据提取的高级技巧。
一、文件分割文件分割是指将大文件按照一定的规则划分为多个小文件,以便于管理和处理。
awk命令可以根据指定的分隔符将文件进行分割,并输出为多个小文件。
下面是一个示例,假设我们有一个包含学生信息的大文件student.txt,每行包含学生姓名、年龄和成绩,用逗号分隔。
假设我们要将该文件按照每个学生的成绩分割成不同的文件,成绩在90分以上的学生放在一个文件,成绩在80到90分之间的学生放在另一个文件,成绩在80分以下的学生放在第三个文件。
我们可以使用awk命令按照如下方式进行文件分割:```shellawk -F ',' '{if ($3 >= 90) print > "high.txt"; else if ($3 >= 80) print > "medium.txt"; else print > "low.txt"}' student.txt```该命令中的-F参数指定了分隔符为逗号,$3表示第三个字段(即成绩)。
根据成绩的不同,将不同的行输出到不同的文件中,分别为high.txt、medium.txt和low.txt。
二、数据提取除了文件分割,awk命令还可以用于提取文件中的特定数据。
通过指定条件和规则,我们可以从文件中提取出我们需要的内容,并输出到终端或者保存到新文件中。
假设我们有一个日志文件access.log,其中记录了用户的访问记录,包括IP地址、访问时间和访问的页面。
我们需要从该日志文件中提取出所有访问时间在某个时间段内的记录。
awk参数详解
awk参数详解wk是⾏处理器: 相⽐较屏幕处理的优点,在处理庞⼤⽂件时不会出现内存溢出或是处理缓慢的问题,通常⽤来格式化⽂本信息awk处理过程: 依次对每⼀⾏进⾏处理,然后输出awk命令形式:awk [-F|-f|-v] ‘BEGIN{} //{command1; command2} END{}’ file[-F|-f|-v] ⼤参数,-F指定分隔符,-f调⽤脚本,-v定义变量 var=value' ' 引⽤代码块BEGIN 初始化代码块,在对每⼀⾏进⾏处理之前,初始化代码,主要是引⽤全局变量,设置FS分隔符// 匹配代码块,可以是字符串或正则表达式{} 命令代码块,包含⼀条或多条命令;多条命令使⽤分号分隔END 结尾代码块,在对每⼀⾏进⾏处理之后再执⾏的代码块,主要是进⾏最终计算或输出结尾摘要信息特殊要点:$0 表⽰整个当前⾏$1 每⾏第⼀个字段NF 字段数量变量NR 每⾏的记录号,多⽂件记录递增FNR 与NR类似,不过多⽂件记录不递增,每个⽂件都从1开始\t 制表符\n 换⾏符FS BEGIN时定义分隔符RS 输⼊的记录分隔符,默认为换⾏符(即⽂本是按⼀⾏⼀⾏输⼊)~ 匹配,与==相⽐不是精确⽐较!~ 不匹配,不精确⽐较== 等于,必须全部相等,精确⽐较!= 不等于,精确⽐较&& 逻辑与|| 逻辑或+ 匹配时表⽰1个或1个以上/[0-9][0-9]+/ 两个或两个以上数字/[0-9][0-9]*/ ⼀个或⼀个以上数字FILENAME ⽂件名OFS 输出字段分隔符,默认也是空格,可以改为制表符等ORS 输出的记录分隔符,默认为换⾏符,即处理结果也是⼀⾏⼀⾏输出到屏幕-F'[:#/]' 定义三个分隔符print & $0print 是awk打印指定内容的主要命令awk '{print}' /etc/passwd == awk '{print $0}' /etc/passwdawk '{print " "}' /etc/passwd //不输出passwd的内容,⽽是输出相同个数的空⾏,进⼀步解释了awk是⼀⾏⼀⾏处理⽂本awk '{print "a"}' /etc/passwd //输出相同个数的a⾏,⼀⾏只有⼀个a字母awk -F":" '{print $1}' /etc/passwdawk -F: '{print $1; print $2}' /etc/passwd //将每⼀⾏的前⼆个字段,分⾏输出,进⼀步理解⼀⾏⼀⾏处理⽂本awk -F: '{print $1,$3,$6}' OFS="\t" /etc/passwd //输出字段1,3,6,以制表符作为分隔符-f指定脚本⽂件awk -f script.awk fileBEGIN{FS=":"}{print $1} //效果与awk -F":" '{print $1}'相同,只是分隔符使⽤FS在代码⾃⾝中指定awk 'BEGIN{X=0} /^$/{ X+=1 } END{print "I find",X,"blank lines."}' testI find 4 blank lines.ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is",sum}' //计算⽂件⼤⼩total size is 17487-F指定分隔符$1 指指定分隔符后,第⼀个字段,$3第三个字段, \t是制表符⼀个或多个连续的空格或制表符看做⼀个定界符,即多个空格看做⼀个空格awk -F":" '{print $1}' /etc/passwdawk -F":" '{print $1 $3}' /etc/passwd //$1与$3相连输出,不分隔awk -F":" '{print $1,$3}' /etc/passwd //多了⼀个逗号,$1与$3使⽤空格分隔awk -F":" '{print $1 " " $3}' /etc/passwd //$1与$3之间⼿动添加空格分隔awk -F":" '{print "Username:" $1 "\t\t Uid:" $3 }' /etc/passwd //⾃定义输出awk -F: '{print NF}' /etc/passwd //显⽰每⾏有多少字段awk -F: '{print $NF}' /etc/passwd //将每⾏第NF个字段的值打印出来awk -F: 'NF==4 {print }' /etc/passwd //显⽰只有4个字段的⾏awk -F: 'NF>2{print $0}' /etc/passwd //显⽰每⾏字段数量⼤于2的⾏awk '{print NR,$0}' /etc/passwd //输出每⾏的⾏号awk -F: '{print NR,NF,$NF,"\t",$0}' /etc/passwd //依次打印⾏号,字段数,最后字段值,制表符,每⾏内容awk -F: 'NR==5{print}' /etc/passwd //显⽰第5⾏awk -F: 'NR==5 || NR==6{print}' /etc/passwd //显⽰第5⾏和第6⾏route -n|awk 'NR!=1{print}' //不显⽰第⼀⾏//匹配代码块//纯字符匹配 !//纯字符不匹配 ~//字段值匹配 !~//字段值不匹配 ~/a1|a2/字段值匹配a1或a2awk '/mysql/' /etc/passwdawk '/mysql/{print }' /etc/passwdawk '/mysql/{print $0}' /etc/passwd //三条指令结果⼀样awk '!/mysql/{print $0}' /etc/passwd //输出不匹配mysql的⾏awk '/mysql|mail/{print}' /etc/passwdawk '!/mysql|mail/{print}' /etc/passwdawk -F: '/mail/,/mysql/{print}' /etc/passwd //区间匹配awk '/[2][7][7]*/{print $0}' /etc/passwd //匹配包含27为数字开头的⾏,如27,277,2777...awk -F: '$1~/mail/{print $1}' /etc/passwd //$1匹配指定内容才显⽰awk -F: '{if($1~/mail/) print $1}' /etc/passwd //与上⾯相同awk -F: '$1!~/mail/{print $1}' /etc/passwd //不匹配awk -F: '$1!~/mail|mysql/{print $1}' /etc/passwdIF语句必须⽤在{}中,且⽐较内容⽤()扩起来awk -F: '{if($1~/mail/) print $1}' /etc/passwd //简写awk -F: '{if($1~/mail/) {print $1}}' /etc/passwd //全写awk -F: '{if($1~/mail/) {print $1} else {print $2}}' /etc/passwd //if...else...条件表达式== != > >=awk -F":" '$1=="mysql"{print $3}' /etc/passwdawk -F":" '{if($1=="mysql") print $3}' /etc/passwd //与上⾯相同awk -F":" '$1!="mysql"{print $3}' /etc/passwd //不等于awk -F":" '$3>1000{print $3}' /etc/passwd //⼤于awk -F":" '$3>=100{print $3}' /etc/passwd //⼤于等于awk -F":" '$3<1{print $3}' /etc/passwd //⼩于awk -F":" '$3<=1{print $3}' /etc/passwd //⼩于等于逻辑运算符&& ||awk -F: '$1~/mail/ && $3>8 {print }' /etc/passwd //逻辑与,$1匹配mail,并且$3>8awk -F: '{if($1~/mail/ && $3>8) print }' /etc/passwdawk -F: '$1~/mail/ || $3>1000 {print }' /etc/passwd //逻辑或awk -F: '{if($1~/mail/ || $3>1000) print }' /etc/passwd数值运算awk -F: '$3 > 100' /etc/passwdawk -F: '$3 > 100 || $3 < 5' /etc/passwdawk -F: '$3+$4 > 200' /etc/passwdawk -F: '/mysql|mail/{print $3+10}' /etc/passwd //第三个字段加10打印awk -F: '/mysql/{print $3-$4}' /etc/passwd //减法awk -F: '/mysql/{print $3*$4}' /etc/passwd //求乘积awk '/MemFree/{print $2/1024}' /proc/meminfo //除法awk '/MemFree/{print int($2/1024)}' /proc/meminfo //取整输出分隔符OFSawk '$6 ~ /FIN/ || NR==1 {print NR,$4,$5,$6}' OFS="\t" netstat.txtawk '$6 ~ /WAIT/ || NR==1 {print NR,$4,$5,$6}' OFS="\t" netstat.txt//输出字段6匹配WAIT的⾏,其中输出每⾏⾏号,字段4,5,6,并使⽤制表符分割字段输出处理结果到⽂件①在命令代码块中直接输出 route -n|awk 'NR!=1{print > "./fs"}'②使⽤重定向进⾏输出 route -n|awk 'NR!=1{print}' > ./fs格式化输出netstat -anp|awk '{printf "%-8s %-8s %-10s\n",$1,$2,$3}'printf表⽰格式输出%格式化输出分隔符-8长度为8个字符s表⽰字符串类型打印每⾏前三个字段,指定第⼀个字段输出字符串类型(长度为8),第⼆个字段输出字符串类型(长度为8),第三个字段输出字符串类型(长度为10)netstat -anp|awk '$6=="LISTEN" || NR==1 {printf "%-10s %-10s %-10s \n",$1,$2,$3}'netstat -anp|awk '$6=="LISTEN" || NR==1 {printf "%-3s %-10s %-10s %-10s \n",NR,$1,$2,$3}'IF语句awk -F: '{if($3>100) print "large"; else print "small"}' /etc/passwdsmallsmallsmalllargesmallsmallawk -F: 'BEGIN{A=0;B=0} {if($3>100) {A++; print "large"} else {B++; print "small"}} END{print A,"\t",B}' /etc/passwd //ID⼤于100,A加1,否则B加1awk -F: '{if($3<100) next; else print}' /etc/passwd //⼩于100跳过,否则显⽰awk -F: 'BEGIN{i=1} {if(i<NF) print NR,NF,i++ }' /etc/passwdawk -F: 'BEGIN{i=1} {if(i<NF) {print NR,NF} i++ }' /etc/passwd另⼀种形式awk -F: '{print ($3>100 ? "yes":"no")}' /etc/passwdawk -F: '{print ($3>100 ? $3":\tyes":$3":\tno")}' /etc/passwdwhile语句awk -F: 'BEGIN{i=1} {while(i<NF) print NF,$i,i++}' /etc/passwd7 root 17 x 27 0 37 0 47 root 57 /root 6数组netstat -anp|awk 'NR!=1{a[$6]++} END{for (i in a) print i,"\t",a[i]}'netstat -anp|awk 'NR!=1{a[$6]++} END{for (i in a) printf "%-20s %-10s %-5s \n", i,"\t",a[i]}'9523 19929 1LISTEN 67903 13038/cupsd 17913 110837 19833 1应⽤1awk -F: '{print NF}' helloworld.sh //输出⽂件每⾏有多少字段awk -F: '{print $1,$2,$3,$4,$5}' helloworld.sh //输出前5个字段awk -F: '{print $1,$2,$3,$4,$5}' OFS='\t' helloworld.sh //输出前5个字段并使⽤制表符分隔输出awk -F: '{print NR,$1,$2,$3,$4,$5}' OFS='\t' helloworld.sh //制表符分隔输出前5个字段,并打印⾏号应⽤2awk -F'[:#]' '{print NF}' helloworld.sh //指定多个分隔符: #,输出每⾏多少字段awk -F'[:#]' '{print $1,$2,$3,$4,$5,$6,$7}' OFS='\t' helloworld.sh //制表符分隔输出多字段应⽤3awk -F'[:#/]' '{print NF}' helloworld.sh //指定三个分隔符,并输出每⾏字段数awk -F'[:#/]' '{print $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12}' helloworld.sh //制表符分隔输出多字段应⽤4计算/home⽬录下,普通⽂件的⼤⼩,使⽤KB作为单位ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is:",sum/1024,"KB"}'ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is:",int(sum/1024),"KB"}' //int是取整的意思应⽤5统计netstat -anp 状态为LISTEN和CONNECT的连接数量分别是多少netstat -anp|awk '$6~/LISTEN|CONNECTED/{sum[$6]++} END{for (i in sum) printf "%-10s %-6s %-3s \n", i," ",sum[i]}'应⽤6统计/home⽬录下不同⽤户的普通⽂件的总数是多少?ls -l|awk 'NR!=1 && !/^d/{sum[$3]++} END{for (i in sum) printf "%-6s %-5s %-3s \n",i," ",sum[i]}'mysql 199root 374统计/home⽬录下不同⽤户的普通⽂件的⼤⼩总size是多少?ls -l|awk 'NR!=1 && !/^d/{sum[$3]+=$5} END{for (i in sum) printf "%-6s %-5s %-3s %-2s \n",i," ",sum[i]/1024/1024,"MB"}'应⽤7输出成绩表awk 'BEGIN{math=0;eng=0;com=0;printf "Lineno. Name No. Math English Computer Total\n";printf "------------------------------------------------------------\n"}{math+=$3; eng+=$4; com+=$5;printf "%-8s %-7s %-7s %-7s %-9s %-10s %-7s \n",NR,$1,$2,$3,$4,$5,$3+$4+$5}END{printf "------------------------------------------------------------\n";printf "%-24s %-7s %-9s %-20s \n","Total:",math,eng,com;printf "%-24s %-7s %-9s %-20s \n","Avg:",math/NR,eng/NR,com/NR}' test0[root@localhost home]# cat test0Marry 2143 78 84 77Jack 2321 66 78 45Tom 2122 48 77 71Mike 2537 87 97 95Bob 2415 40 57 62。
AWK手册
awk 手册简体中文版由bones7456 (bones7456@)整理.原文:应该是.tw/aspac/reports/94/94011/但是原文很乱.说明:之前也是对awk几乎一无所知,无意中看到这篇文章,网上一搜,居然没有像样的简体中文版.有的也是不怎么完整,或者错误一大堆的.于是就顺手整理了下这篇文章.通过整理这篇文章,自己也渐渐掌握了awk的种种用法.原文可能比较老,有些目前已经不适用的命令有所改动,文中所有命令均在ubuntu7.04下调试通过,用的awk是mawk.由于本人能力有限,错误和不妥之处在所难免,欢迎多多指正.1.前言有关本手册:这是一本awk学习指引, 其重点着重于:●awk 适于解决哪些问题?●awk 常见的解题模式为何?为使读者快速掌握awk解题的模式及特性, 本手册系由一些较具代表性的范例及其题解所构成; 各范例由浅入深, 彼此间相互连贯,范例中并对所使用的awk 语法及指令辅以必要的说明. 有关awk的指令, 函数,...等条列式的说明则收录于附录中, 以利读者往后撰写程序时查阅. 如此编排, 可让读者在短时间内顺畅地学会使用awk来解决问题. 建议读者循着范例上机实习, 以加深学习效果.读者宜先具备下列背景:[a.] UNIX 环境下的简单操作及基本概念.例如: 文件编辑, 文件复制及管道, 输入/输出重定向等概念[b.] C 语言的基本语法及流程控制指令.(awk 指令并不多, 且其中之大部分与C语言中之用法一致, 本手册中对该类指令之语法及特性不再加以繁冗的说明, 读者若欲深究,可自行翻阅相关的 C 语言书籍)2.awk概述为什么使用awkawk 是一种程序语言. 它具有一般程序语言常见的功能.因awk语言具有某些特点, 如: 使用直译器(Interpreter)不需先行编译; 变量无类型之分(Typeless), 可使用文字当数组的下标(Associative Array)...等特色. 因此, 使用awk撰写程序比起使用其它语言更简洁便利且节省时间. awk还具有一些内建功能, 使得awk擅于处理具数据行(Record), 字段(Field)型态的资料; 此外, awk内建有pipe的功能, 可将处理中的数据传送给外部的Shell命令加以处理, 再将Shell命令处理后的数据传回awk程序, 这个特点也使得awk程序很容易使用系统资源.由于awk具有上述特色, 在问题处理的过程中, 可轻易使用awk来撰写一些小工具; 这些小工具并非用来解决整个大问题,它们只扮演解决个别问题过程的某些角色, 可藉由Shell所提供的pipe将数据按需要传送给不同的小工具进行处理, 以解决整个大问题. 这种解题方式, 使得这些小工具可因不同需求而被重复组合及重用(reuse); 也可藉此方式来先行测试大程序原型的可行性与正确性, 将来若需要较高的执行速度时再用C语言来改写.这是awk最常被应用之处. 若能常常如此处理问题, 读者可以以更高的角度来思考抽象的问题, 而不会被拘泥于细节的部份.本手册为awk入门的学习指引, 其内容将先强调如何撰写awk程序,未列入进一步解题方式的应用实例, 这部分将留待UNIX进阶手册中再行讨论.如何取得awk一般的UNIX操作系统, 本身即附有awk. 不同的UNIX操作系统所附的awk其版本亦不尽相同. 若读者所使用的系统上未附有awk,可透过anonymous ftp 到下列地方取得:.tw:/pub/gnu.tw:/UNIX/gnu:/pub/gnuawk如何工作为便于解释awk程序架构, 及有关术语(terminology), 先以一个员工薪资档(emp.dat ), 来加以介绍.A125 Jenny 100 210A341 Dan 110 215P158 Max 130 209P148 John 125 220A123 Linda 95 210文件中各字段依次为员工ID, 姓名, 薪资率,及实际工时. ID中的第一码为部门识别码. "A","P"分别表示"组装"及"包装"部门.本小节着重于说明awk程序的主要架构及工作原理, 并对一些重要的名词辅以必要的解释. 由这部分内容, 读者可体会出awk语言的主要精神及awk与其它语程序言的差异处. 为便于说明, 以条列方式说明于后.名词定义●数据行: awk从数据文件上读取数据的基本单位.以上列文件emp.dat为例,awk读入的第一笔数据行是"A125 Jenny 100 210"第二笔数据行是"A341 Dan 110 215"一般而言, 一个数据行就相当于数据文件上的一行资料. (参考: 附录 B 内建变量"RS" )●字段(Field) : 为数据行上被分隔开的子字符串.以数据行"A125 Jenny 100 210"为例,第一栏第二栏第三栏第四栏"A125" "Jenny" 100 210一般是以空格符来分隔相邻的字段. ( 参考: 附录 D 内建变量"FS" )3.如何执行awk于UNIX的命令行上键入诸如下列格式的指令: ( "$"表Shell命令行上的提示符号)$awk 'awk程序' 数据文件文件名则awk会先编译该程序, 然后执行该程序来处理所指定的数据文件.(上列方式系直接把程序写在UNIX的命令行上)awk程序的主要结构:awk程序中主要语法是Pattern { Actions}, 故常见之awk 程序其型态如下: Pattern1 { Actions1 }Pattern2 { Actions2 }......Pattern3 { Actions3 }Pattern 是什么?awk 可接受许多不同型态的Pattern. 一般常使用"关系表达式"(Relational expression) 来当成Pattern.例如:x > 34 是一个Pattern, 判断变量x 与34 是否存在大于的关系.x == y 是一个Pattern, 判断变量x 与变量y 是否存在等于的关系.上式中x >34 , x == y 便是典型的Pattern.awk 提供C 语言中常见的关系运算符(Relational Operators) 如>, <, >=, <=, ==, !=此外, awk 还提供~ (match) 及!~(not match) 二个关系运算符(注一).其用法与涵义如下:若A 为一字符串, B 为一正则表达式(Regular Expression)A ~B 判断字符串A 中是否包含能匹配(match)B表达式的子字符串.A !~B 判断字符串A 中是否不包含能匹配(match)B表达式的子字符串.例如:"banana" ~ /an/ 整个是一个Pattern.因为"banana"中含有可以匹配/an/ 的子字符串, 故此关系式成立(true),整个Pattern的值也是true.相关细节请参考附录 A Patterns, 附录 E Regular Expression(注一:) 有少数awk论著, 把~, !~ 当成另一类的Operator,并不视为一种Relational Operator. 本手册中将这两个运算符当成一种Relational Operator. Actions 是什么?Actions 是由许多awk指令构成. 而awk的指令与C 语言中的指令十分类似. 例如:awk的I/O指令: print, printf( ), getline...awk的流程控制指令: if(...){..} else{..}, while(...){...}...(请参考附录B --- "Actions" )awk 如何处理Pattern { Actions } ?awk 会先判断(Evaluate) 该Pattern 的值, 若Pattern 判断后的值为true (或不为0的数字,或不是空的字符串), 则awk将执行该Pattern 所对应的Actions.反之, 若Pattern 之值不为true, 则awk将不执行该Pattern所对应的Actions.例如: 若awk程序中有下列两指令50 > 23 {print "Hello! The word!!" }"banana" ~ /123/ { print "Good morning !" }awk会先判断50 >23 是否成立. 因为该式成立, 所以awk将印出"Hello! The word!!". 而另一Pattern 为"banana" ~/123/, 因为"banana" 内未含有任何子字符串可match /123/, 该Pattern 之值为false, 故awk将不会印出"Good morning !"awk 如何处理{ Actions } 的语法?(缺少Pattern部分)有时语法Pattern { Actions }中, Pattern 部分被省略,只剩{Actions}.这种情形表示"无条件执行这个Actions".awk 的字段变量读入数据行时, awk如何更新(update)这些内建的字段变量?当awk 从数据文件中读取一个数据行时, awk 会使用内建变量$0 予以记录.每当$0 被改动时(例如: 读入新的数据行或自行变更$0,...) awk 会立刻重新分析$0 的字段情况, 并将$0 上各字段的数据用$1, $2, ..予以记录.awk的内建变量(Built-in Variables)awk 提供了许多内建变量, 使用者于程序中可使用这些变量来取得相关信息.常例如: awk 从资料文件emp.dat 中读入第一笔数据行"A125 Jenny 100 210" 之后, 程序中:$0 之值将是"A125 Jenny 100 210"$1 之值为"A125"$2 之值为"Jenny"$3 之值为100$4 之值为210$NF 之值为4$NR 之值为1$FILENAME 之值为"emp.dat"awk的工作流程:执行awk时, 它会反复进行下列四步骤.1.自动从指定的数据文件中读取一个数据行.2.自动更新(Update)相关的内建变量之值. 如: NF, NR, $0...3.依次执行程序中所有的Pattern { Actions } 指令.4.当执行完程序中所有Pattern { Actions } 时, 若数据文件中还有未读取的数据, 则反复执行步骤1到步骤4.awk会自动重复进行上述4个步骤, 使用者不须于程序中编写这个循环(Loop).打印文件中指定的字段数据并加以计算awk 处理数据时, 它会自动从数据文件中一次读取一笔记录, 并会将该数据切分成一个个的字段; 程序中可使用$1, $2,... 直接取得各个字段的内容. 这个特色让使用者易于用awk 编写reformatter 来改变量据格式.[ 范例:] 以文件emp.dat 为例, 计算每人应发工资并打印报表.[ 分析:] awk 会自行一次读入一列数据, 故程序中仅需告诉awk 如何处理所读入的数据行.执行如下命令: ( $ 表UNIX命令行上的提示符)$ awk '{ print $2, $3 * $4 }' emp.dat执行结果如下:屏幕出现:Jenny 21000Dan 23650Max 27170John 27500Linda 19950[ 说明:]UNIX命令行上, 执行awk的语法为:$awk 'awk程序' 欲处理的资料文件文件名本范例中的程序部分为{print $2, $3 * $4}.把程序置于命令行时, 程序之前后须以' 括住.emp.dat 为指定给该程序处理的数据文件文件名.本程序中使用: Pattern { Actions } 语法.Pattern 部分被省略, 表无任何限制条件. 故awk读入每笔数据行后都将无条件执行这个Actions.print为awk所提供的输出指令, 会将数据输出到stdout(屏幕).print 的参数间彼此以"," (逗号) 隔开, 印出数据时彼此间会以空白隔开. (参考附录D 内建变量OFS)将上述的程序部分储存于文件pay1.awk 中. 执行命令时再指定awk程序文件之文件名. 这是执行awk的另一种方式, 特别适用于程序较大的情况, 其语法如下: $ awk -f awk程序文件名数据文件文件名故执行下列两命令,将产生同样的结果.$ awk -f pay1.awk emp.dat$ awk '{ print $2, $3 * $4 }' emp.dat读者可使用"-f" 参数,让awk主程序使用“其它仅含awk函数的文件中的函数”其语法如下:$ awk -f awk主程序文件名-f awk函数文件名数据文件文件名(有关awk 中函数的声明与使用于7.4 中说明)awk中也提供与C 语言中类似用法的printf() 函数. 使用该函数可进一步控制数据的输出格式.编辑另一个awk程序如下, 并取名为pay2.awk{ printf("%6s Work hours: %3d Pay: %5d\n", $2,$3, $3* $4) }执行下列命令$awk -f pay2.awk emp.dat执行结果屏幕出现:Jenny Work hours: 100 Pay: 21000Dan Work hours: 110 Pay: 23650Max Work hours: 130 Pay: 27170John Work hours: 125 Pay: 27500Linda Work hours: 95 Pay: 199504.选择符合指定条件的记录Pattern { Action }为awk中最主要的语法. 若某Pattern之值为真则执行它后方的Action. awk中常使用"关系表达式" (Relational Expression)来当成Pattern.awk 中除了>, <, ==, != ,...等关系运算符( Relational Operators )外,另外提供~(match),!~(Not Match) 二个关系运算符. 利用这两个运算符, 可判断某字符串是否包含能匹配所指定正则表达式的子字符串. 由于这些特性, 很容易使用awk 来编写需要字符串比对, 判断的程序.[ 范例:] 承上例,组装部门员工调薪5%,(组装部门员工之ID以"A"开头)所有员工最后之薪资率若仍低于100, 则以100计.编写awk程序打印新的员工薪资率报表.[分析] : 这个程序须先判断所读入的数据行是否合于指定条件, 再进行某些动作.awk中Pattern { Actions } 的语法已涵盖这种" if ( 条件) { 动作} "的架构.编写如下之程序, 并取名adjust1.awk$1 ~ /^A.*/ { $3 *= 1.05 } $3<100 { $3 = 100 }{ printf("%s %8s %d\n", $1, $2, $3)}执行下列命令:$awk -f adjust1.awk emp.dat结果如下: 屏幕出现:A125 Jenny 105A341 Dan 115P158 Max 130P148 John 125A123 Linda 100说明:awk的工作程序是: 从数据文件中每次读入一个数据行, 依序执行完程序中所有的Pattern{ Action }指令:$1~/^A.*/ { $3 *= 1.05 }$3 < 100 { $3 = 100 }{printf("%s %8s %d\n",$1,$2,$3)}再从数据文件中读进下一笔记录继续进行处理.第一个Pattern { Action }是: $1 ~ /^A.*/ { $3 *= 1.05 }$1 ~ /^A.*/ 是一个Pattern, 用来判断该笔数据行的第一栏是否包含以"A"开头的子字符串. 其中/^A.*/ 是一个Regular Expression, 用以表示任何以"A"开头的字符串. (有关Regular Expression 之用法参考附录 E ).Actions 部分为$3 *= 1.05$3 *= 1.05 与$3 = $3 * 1.05 意义相同. 运算子"*=" 之用法则与C 语言中一样. 此后与C 语言中用法相同的运算子或语法将不予赘述.第二个Pattern { Actions } 是: $3 <100 {$3 = 100 } 若第三栏的数据内容(表薪资率)小于100, 则调整为100.第三个Pattern { Actions } 是: {printf("%s %8s %d\n",$1, $2, $3 )} 省略了Pattern(无条件执行Actions), 故所有数据行调整后的数据都将被印出.5.awk 中数组awk程序中允许使用字符串当做数组的下标(index). 利用这个特色十分有助于资料统计工作.(使用字符串当下标的数组称为Associative Array)首先建立一个数据文件, 并取名为reg.dat. 此为一学生注册的资料文件; 第一栏为学生姓名, 其后为该生所修课程.Mary O.S. Arch. DiscreteSteve D.S. Algorithm Arch.Wang Discrete Graphics O.S.Lisa Graphics A.I.Lily Discrete Algorithmawk中数组的特性使用字符串当数组的下标(index).使用数组前不须宣告数组名及其大小.例如: 希望用数组来记录reg.dat 中各门课程的修课人数.这情况,有二项信息必须储存:(a) 课程名称, 如: "O.S.","Arch.".. ,共有哪些课程事先并不明确.(b)各课程的修课人数. 如: 有几个人修"O.S."在awk中只要用一个数组就可同时记录上列信息. 其方法如下:使用一个数组Number[ ] :以课程名称当Number[ ] 的下标.以Number[ ] 中不同下标所对映的元素代表修课人数.例如:有2个学生修"O.S.", 则以Number["O.S."] = 2 表之.若修"O.S."的人数增加一人,则Number["O.S."] = Number["O.S."] + 1 或Number["O.S."]++ .如何取出数组中储存的信息以C 语言为例, 声明int Arr[100]; 之后, 若想得知Arr[ ]中所储存的数据, 只须用一个循环, 如:for(i=0; i<100; i++) printf("%d\n", Arr[i]);即可. 上式中:数组Arr[ ] 的下标: 0, 1, 2,..., 99数组Arr[ ] 中各下标所对应的值: Arr[0], Arr[1],...Arr[99]但awk 中使用数组并不须事先宣告. 以刚才使用的Number[ ] 而言, 程序执行前, 并不知将来有哪些课程名称可能被当成Number[ ] 的下标.awk 提供了一个指令, 藉由该指令awk会自动找寻数组中使用过的所有下标. 以Number[ ] 为例, awk将会找到"O.S.", "Arch.",...使用该指令时, 须指定所要找寻的数组, 及一个变量. awk会使用该的变量来记录从数组中找到的每一个下标. 例如for(course in Number){....}指定用course 来记录awk 从Number[ ] 中所找到的下标. awk每找到一个下标时, 就用course记录该下标之值且执行{....}中之指令. 藉由这个方式便可取出数组中储存的信息.(详见下例)[ 范例: ] 统计各科修课人数,并印出结果.建立如下程序,并取名为course.awk:{ for( i=2; i <= NF; i++) Number[$i]++ }END{for(course in Number) printf("%10s %d\n", course, Number[course] )}执行下列命令:$awk -f course.awk reg.dat执行结果如下:Graphics 2O.S. 2Discrete 3A.I. 1D.S. 1Arch. 2Algorithm 2[ 说明: ]这程序包含二个Pattern { Actions }指令.{ for( i=2; i <= NF; i++) Number[$i]++ }END{for(course in Number) printf("%10s %d\n", course, Number[course] )}第一个Pattern { Actions }指令中省略了Pattern 部分. 故随着每笔数据行的读入其Actions部分将逐次无条件被执行.以awk读入第一笔资料" Mary O.S. Arch. Discrete" 为例, 因为该笔数据NF = 4(有4个字段), 故该Action 的for Loop中i = 2,3,4.i $i 最初Number[$i] Number[$i]++ 之后i=2时$i="O.S." Number["O.S."]的值从默认的0,变成了1 ;i=3时$i="Arch." Number["Arch."]的值从默认的0,变成了1 ;同理,i=4时$i="Discrete" Number["Discrete"]的值从默认的0,变成了1 ;第二个Pattern { Actions }指令中END 为awk之保留字, 为Pattern 的一种. END 成立(其值为true)的条件是: "awk处理完所有数据, 即将离开程序时. "平常读入数据行时, END并不成立, 故其后的Actions 并不被执行;唯有当awk读完所有数据时, 该Actions才会被执行( 注意, 不管数据行有多少笔, END仅在最后才成立, 故该Actions仅被执行一次.)BEGIN 与END 有点类似, 是awk中另一个保留的Pattern.唯一不同的是: "以BEGIN 为Pattern 的Actions 于程序一开始执行时, 被执行一次."NF 为awk的内建变量, 用以表示awk正处理的数据行中, 所包含的字段个数. awk程序中若含有以$ 开头的自定变量, 都将以如下方式解释:以i= 2 为例, $i = $2 表第二个字段数据. ( 实际上, $ 在awk 中为一运算符(Operator), 用以取得字段数据.)6.awk 程序中使用Shell 命令awk程序中允许呼叫Shell指令. 并提供管道解决awk与系统间数据传递的问题. 所以awk很容易使用系统资源. 读者可利用这个特点来编写某些适用的系统工具.[ 范例: ] 写一个awk程序来打印出线上人数.将下列程序建文件, 命名为count.awkBEGIN {while ( "who" | getline ) n++print n}并执行下列命令:awk -f count.awk执行结果将会印出目前在线人数[ 说明: ]awk 程序并不一定要处理数据文件. 以本例而言, 仅输入程序文件count.awk, 未输入任何数据文件.BEGIN 和END 同为awk中的一种Pattern. 以BEGIN 为Pattern的Actions ,只有在awk开始执行程序,尚未开启任何输入文件前, 被执行一次.(注意: 只被执行一次)"|" 为awk 中表示管道的符号. awk 把| 之前的字符串"who"当成Shell上的命令, 并将该命令送往Shell执行, 执行的结果(原先应于屏幕印出者)则藉由pipe送进awk程序中.getline为awk所提供的输入指令.注一: 当Pattern 为BEGIN 或END 时, getline 将由stdin 读取数据, 否则由awk正处理的数据文件上读取数据.getline 一次读取一行数据, 若读取成功则return 1, 若读取失败则return -1, 若遇到文件结束(EOF), 则return 0;本程序使用getline 所return 的数据来做为while 判断循环停止的条件,某些awk版本较旧,并不容许使用者改变$0 之值. 这种版的awk 执行本程序时会产生Error, 读者可于getline 之后置上一个变量(如此, getline 读进来的数据便不会被置于$0 ), 或直接改用gawk便可解决.7.awk 程序的应用实例本节将示范一个统计上班到达时间及迟到次数的程序.这程序每日被执行时将读入二个文件:员工当日到班时间的数据文件( 如下列之arr.dat )存放员工当月迟到累计次数的文件.当程序执行执完毕后将更新第二个文件的数据(迟到次数), 并打印当日的报表.这程序将分成下列数小节逐步完成, 其大纲如下:[7.1] 在到班资料文件arr.dat 之前增加一行抬头"ID Number Arrvial Time", 并产生报表输出到文件today_rpt1 中.<思考: 在awk中如何将数据输出到文件>[7.2]将today_rpt1 上的数据按员工代号排序, 并加注执行当日日期; 产生文件today_rpt2<思考awk中如何运用系统资源及awk中Pipe之特性>[7.3] 将awk程序包含在一个shell script文件中[7.4] 于today_rpt2 每日报表上, 迟到者之前加上"*", 并加注当日平均到班时间;产生文件today_rpt3[7.5] 从文件中读取当月迟到次数, 并根据当日出勤状况更新迟到累计数.<思考使用者在awk中如何读取文件数据>某公司其员工到勤时间档如下, 取名为arr.dat. 文件中第一栏为员工代号, 第二栏为到达时间. 本范例中, 将使用该文件为数据文件.1034 7:261025 7:271101 7:321006 7:451012 7:461028 7:491051 7:511029 7:571042 7:591008 8:011052 8:051005 8:12重定向输出到文件awk中并未提供如C 语言中之fopen() 指令, 也未有fprintf() 文件输出这样的指令. 但awk中任何输出函数之后皆可借助使用与UNIX 中类似的I/O 重定向符, 将输出的数据重定向到指定的文件; 其符号仍为> (输出到一个新产生的文件) 或>> ( 添加输出的数据到文件末尾).[例:]在到班数据文件arr.dat 之前增加一行抬头如下:"ID Number Arrival Time", 并产生报表输出到文件today_rpt1中建立如下文件并取名为reformat1.awkBEGIN { print " ID Number Arrival Time" > "today_rpt1"print "===========================" > "today_rpt1"}{ printf(" %s %s\n", $1,$2 ) > "today_rpt1" }执行:$awk -f reformat1.awk arr.dat执行后将产生文件today_rpt1, 其内容如下:ID Number Arrival Time============================1034 7:261025 7:271101 7:321006 7:451012 7:461028 7:491051 7:511029 7:571042 7:591008 8:011052 8:051005 8:12[ 说明: ]awk程序中, 文件名称today_rpt1 的前后须以" (双引号)括住, 表示today_rpt1 为一字符串常量. 若未以"括住, 则today_rpt1 将被awk解释为一个变量名称. 在awk中任何变量使用之前, 并不须事先声明. 其初始值为空字符串(Null string) 或0.因此程序中若未以" 将today_rpt1 括住, 则today_rpt1 将是一变量, 其值将是空字符串, 这会在执行时造成错误(Unix 无法帮您开启一个以空字符串为文件名的文件).因此在编辑awk程序时, 须格外留心. 因为若敲错变量名称,awk在编译程序时会认为是一新的变量, 并不会察觉. 因此往往会造成运行时错误.BEGIN 为awk的保留字, 是Pattern 的一种.以BEGIN 为Pattern 的Actions 于awk程序刚被执行尚未读取数据文件时被执行一次, 此后便不再被执行.读者或许觉得本程序中的I/O重定向符号应使用" >>" (append)而非" >".本程序中若使用">" 将数据重导到today_rpt1, awk 第一次执行该指令时会产生一个新档today_rpt1, 其后再执行该指令时则把数据追加到today_rpt1文件末, 并非每执行一次就重开一个新文件.若采用">>"其差异仅在第一次执行该指令时, 若已存在today_rpt1则awk 将直接把数据append在原文件之末尾. 这一点, 与UNIX中的用法不同.awk 中如何利用系统资源awk程序中很容易使用系统资源. 这包括在程序中途调用Shell 命令来处理程序中的部分数据; 或在调用Shell 命令后将其产生的结果交回awk 程序(不需将结果暂存于某个文件). 这一过程是借助awk 所提供的管道(虽然有些类似Unix 中的管道, 但特性有些不同),及一个从awk 中呼叫Unix 的Shell 命令的语法来达成的.[例:] 承上题, 将数据按员工ID排序后再输出到文件today_rpt2 , 并于表头附加执行时的日期.[ 分析: ]awk 提供与UNIX 用法近似的pipe, 其记号亦为"|". 其用法及含意如下: awk程序中可接受下列两种语法:[a. 语法] awk output 指令| "Shell 接受的命令"( 如: print $1,$2 | "sort -k 1" )[b. 语法] "Shell 接受的命令" | awk input 指令( 如: "ls " | getline)注: awk input 指令只有getline 一个.awk output 指令有print, printf() 二个.在a 语法中, awk所输出的数据将转送往Shell , 由Shell 的命令进行处理.以上例而言, print 所输出的数据将经由Shell 命令"sort -k 1" 排序后再送往屏幕(stdout).上列awk程序中, "print$1, $2" 可能反复执行很多次, 其输出的结果将先暂存于pipe 中,等到该程序结束时, 才会一并进行"sort -k 1".须注意二点: 不论print $1, $2 被执行几次, "sort -k 1" 的执行时间是"awk程序结束时","sort -k 1" 的执行次数是"一次".在b 语法中, awk将先调用Shell 命令. 其执行结果将通过pipe 送入awk程序,以上例而言, awk先让Shell 执行"ls",Shell 执行后将结果存于pipe, awk指令getline再从pipe 中读取数据.使用本语法时应留心: 以上例而言,awk "立刻"调用Shell 来执行"ls", 执行次数是一次.getline 则可能执行多次(若pipe中存在多行数据).除上列a, b 二中语法外, awk程序中其它地方如出现像"date", "cls", "ls"... 这样的字符串, awk只把它当成一般字符串处理.建立如下文件并取名为reformat2.awk# 程序reformat2.awk# 这程序用以练习awk中的pipeBEGIN {"date" | getline # Shell 执行"date". getline 取得结果并以$0记录print " Today is " , $2, $3 >"today_rpt2"print "=========================" > "today_rpt2"print " ID Number Arrival Time" >"today_rpt2"close( "today_rpt2" )}{printf( "%s %s\n", $1 ,$2 ) | "sort -k 1 >>today_rpt2"}执行如下命令:awk -f reformat2.awk arr.dat执行后, 系统会自动将sort 后的数据追加( Append; 因为使用" >>") 到文件today_rpt2末端. today_rpt2 内容如下:Today is 09月21日=========================ID Number Arrival Time1005 8:121006 7:451008 8:011012 7:461025 7:271028 7:491029 7:571034 7:261042 7:591051 7:511052 8:051101 7:32[ 说明: ]awk程序由三个主要部分构成:[ i.] Pattern { Action} 指令[ ii.] 函数主体. 例如: function double( x ){ return 2*x } (参考第11节Recursive Program )[ iii.] Comment ( 以# 开头识别之)awk 的输入指令getline, 每次读取一列数据. 若getline之后未接任何变量, 则所读入之资料将以$0 记录, 否则以所指定的变量储存之. [ 以本例而言] :执行"date" | getline 后, $0 之值为"2007年09月21日星期五14:28:02 CST",当$0 之值被更新时, awk将自动更新相关的内建变量, 如: $1,$2,..,NF.故$2 之值将为"09月", $3之值将为"21日".(有少数旧版的awk不允许即使用者自行更新(update)$0的值,或者更新$0时,它不会自动更新$1,$2,..NF. 这情况下, 可改用gawk或nawk. 否则使用者也可自行以awk字符串函数split()来分隔$0上的数据)本程序中printf() 指令会被执行12次( 因为有arr.dat中有12行数据), 但读者不用担心数据被重复sort了12次. 当awk结束该程序时才会close 这个pipe , 此时才将这12行数据一次送往系统,并呼叫"sort -k 1 >> today_rpt2" 处理之.awk提供另一个调用Shell命令的方法, 即使用awk函数system("shell命令")例如:$ awk 'BEGIN{system("date > date.dat")getline < "date.dat"print "Today is ", $2, $3}'但使用system( "shell 命令" ) 时, awk无法直接将执行中的部分数据输出给Shell 命令. 且Shell 命令执行的结果也无法直接输入到awk中.执行awk 程序的几种方式本小节中描述如何将awk程序直接写在shell script 之中. 此后使用者执行awk 程序时, 就不需要每次都键入" awk -f program datafile" .script 中还可包含其它Shell 命令, 如此更可增加执行过程的自动化.建立一个简单的awk程序mydump.awk, 如下:{print}这个程序执行时会把数据文件的内容print 到屏幕上( 与cat功用类似).print 之后未接任何参数时, 表示"print $0".若欲执行该awk程序, 来印出文件today_rpt1 及today_rpt2 的内容时,必须于UNIX 的命令行上执行下列命令:方式一awk -f mydump.awk today_rpt1 today_rpt2方式二awk '{print}' today_rpt1 today_rpt2第二种方式系将awk 程序直接写在Shell 的命令行上, 这种方式仅适合较短的awk程序.方式三建立如下之shell script, 并取名为mydisplay,#!/bin/sh# 注意以下的awk 与' 之间须有空白隔开awk '{print}' $*# 注意以上的' 与$* 之间须有空白隔开执行mydisplay 之前, 须先将它改成可执行的文件(此步骤往后不再赘述). 请执行如下命令:$ chmod +x mydisplay往后使用者就可直接把mydisplay 当成指令, 来display任何文件.例如:$ ./mydisplay today_rpt1 today_rpt2[ 说明: ]在script文件mydisplay 中, 指令"awk"与第一个' 之间须有空格(Shell中并无" awk' "指令).第一个' 用以通知Shell 其后为awk程序.第二个' 则表示awk 程序结束.故awk程序中一律以"括住字符串或字符, 而不使用' , 以免Shell混淆.$* 为shell script中的用法, 它可用来代表命令行上"mydisplay之后的所有参数".例如执行:$ mydisplay today_rpt1 today_rpt2事实上Shell 已先把该指令转换成:awk '{ print}' today_rpt1 today_rpt2本例中, $* 用以代表"today_rpt1 today_rpt2". 在Shell的语法中, 可用$1 代表第一个参数, $2 代表第二个参数. 当不确定命令行上的参数个数时, 可使用$* 表之.awk命令行上可同时指定多个数据文件.。
Linux命令高级技巧使用awk进行数据格式化和输出
Linux命令高级技巧使用awk进行数据格式化和输出Linux命令高级技巧:使用awk进行数据格式化和输出在Linux系统中,awk是一种强大的文本处理工具,可用于数据提取、格式化、转换和输出。
本文将介绍使用awk进行数据格式化和输出的高级技巧。
一、awk的基本语法awk命令的基本语法如下:```bashawk 'pattern {action}' file```其中,pattern表示匹配条件,action表示要执行的操作,file表示要处理的文件。
当pattern匹配到文件的某一行时,就执行action中定义的操作。
二、数据格式化与输出1. 格式化输出字段awk可以对文件的字段进行格式化输出。
通过在action中使用printf 函数,可以指定输出的格式。
例如,下面的例子将以两位小数的形式输出文件的第二个字段:awk '{printf "%.2f\n", $2}' file```2. 自定义字段分隔符默认情况下,awk将空格作为字段的分隔符。
但是,你也可以通过设置变量FS来定义自己的字段分隔符。
例如,将逗号作为字段分隔符:```bashawk -F ',' '{print $1,$2}' file```3. 按照条件进行输出awk可以根据条件进行数据输出。
你可以使用if语句,通过判断条件决定是否输出符合条件的数据。
例如,下面的例子将输出第一个字段为"Apple"的行:```bashawk '$1=="Apple" {print $0}' file```4. 对数据进行统计和计算awk可以对文件中的数据进行统计和计算操作。
你可以定义变量,在action中通过对数据累加或者计算结果来实现统计。
例如,下面的例子统计文件中第二个字段的总和:awk '{sum+=$2} END{print sum}' file```5. 使用正则表达式匹配字段awk可以使用正则表达式来匹配字段,从而实现更为灵活的数据处理和输出。
awk教程
Awk教程一、awk 简介awk是一种解释执行的编程语言,专门用来处理文本数据的。
二、awk工作流程:Awk内部工作原理;AWK执行的流程非常简单:读( Read )、执行( Execute )与重复( Repeat );下面是流程图:Awk工作流程图读( Read ):AWK 从输入流(文件、管道或者标准输入)中读入一行然后将其存入内存中。
执行(Execute):对于每一行输入,所有的 AWK 命令按顺执行。
默认情况下,AWK 命令是针对于每一行输入,但是我们可以将其限制在指定的模式中。
重复(Repeate):一直重复上述两个过程直到文件结束。
三、awk程序结构Awk程序结构主要包括三块:BEGIN(开始块)、主体块、END(结束块);开始块(BEGIN BLOCK):语法:BEGIN{awk-commands}开始块就是awk程序启动时执行的代码部分(在处理输入流之前执行),并且在整个过程中只执行一次;一般情况下,我们在开始块中初始化一些变量。
BEGIN是awk 的关键字,因此必须要大写。
【注:开始块部分是可选,即你的awk程序可以没有开始块部分】主体块(Body Block):语法:/pattern/{awk-commands}针对每一个输入的行都会执行一次主体部分的命令,默认情况下,对于输入的每一行,awk都会执行主体部分的命令,但是我可以使用/pattern/限制其在指定模式下。
结束块(END BLOCK):语法:END{awk-commands}结束块是awk程序结束时执行的代码(在处理完输入流之后执行),END也是awk 的关键字,必须大写,与开始块类似,结束块也是可选的。
示例1:题目:有一个文本a.txt,内容如下:1 zhengchengcheng math 1002 wangbin chinese 803 wangcheng pgysical 854 lily english 755 mary history 90使用awk将其标准输出并附带表头信息?解答:四、awk基本语法Awk命令行模式:一般情况下,我们使用awk命令行模式比较多,即直接使用awk命令处理文本数据;Awk命令行格式如下:awk [options] ‘{awk-commands}’ fileAwk程序文件:当然,除了直接使用awk命令来处理文本之外,我们还可以将awk命令写成脚本来执行,即awk程序文件。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
awk中数组用法
在awk中,数组是一种强大的数据结构,它可以用于存储和操作数据。
数组是根据索引进行访问的,索引可以是任何类型的值,通常是整数或字符串。
1. 声明数组:在awk中声明一个数组很简单,只需使用数组名加上括号即可。
例如,要声明一个名为myArray的数组,可以使用以下语法:
`myArray[]`
2. 赋值和访问数组元素:可以通过索引将值赋给数组元素,也可以使用索引来获取数组元素的值。
例如,要将值赋给myArray数组的第一个元素,可以使用以下语法:
`myArray[1] = "Hello"`
要访问myArray数组的第一个元素,可以使用以下语法:
`print myArray[1]`
3. 遍历数组:要遍历数组中的所有元素,可以使用for循环。
以下是一个遍历数组的示例:
```
for (i in myArray) {
print myArray[i]
}
```
这将打印出myArray数组中的所有元素。
4. 数组函数:awk提供了许多有用的数组函数,可以在处理数组时使用。
以下是常用的一些数组函数:
- `length(array)`:返回数组中元素的个数。
- `delete array[index]`:删除数组中指定索引的元素。
- `in array`:检查数组中是否存在指定的索引。
通过使用这些数组函数,可以更灵活地操作和处理数组。
总结:
awk中的数组是一种强大的工具,可以用于存储和操作数据。
通过声明数组、赋值和访问数组元素、遍历数组以及使用数组函数,可以有效地处理数据。
在编写awk脚本时,合理利用数组可以简化程序逻辑,提高数据处理效率。