【生意多】-免费发布分类信息
当前位置: 首页 » 新闻 » 教程 » 正文

见过最好的AWK手册

放大字体  缩小字体 发布日期:2020-07-12 15:17:42    浏览次数:18
导读

  为使读者快速掌握awk解题的模式及特性, 本手册系由一些较具代表性的范例及其题解所构成; 各范例由浅入深, 彼此间相互连贯,范例中并对所使用的awk语法及指令辅以必要的说明. 有关awk的指令, 函数,...等条列式的说明则收录于附录中, 以利读者往后撰写程序时查阅. 如此编排, 可让读者在短时间内顺畅地学会使用awk来解决问

  为使读者快速掌握awk解题的模式及特性, 本手册系由一些较具代表性的范例及其题解所构成; 各范例由浅入深, 彼此间相互连贯,范例中并对所使用的awk语法及指令辅以必要的说明. 有关awk的指令, 函数,...等条列式的说明则收录于附录中, 以利读者往后撰写程序时查阅. 如此编排, 可让读者在短时间内顺畅地学会使用awk来解决问题. 建议读者循着范例上机实习, 以加深学习效果.

  (awk 指令并不多, 且其中之大部分与 C语言中之用法一致, 本手册中对该类指令之语法及特性不再加以繁冗的说明, 读者若欲深究,可自行翻阅相关的 C 语言书籍)

  因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进阶手册中再行讨论.

  文件中各字段依次为 员工ID, 姓名, 薪资率,及 实际工时. ID中的第一码为部门识别码. A,P分别表示组装及包装部门.

  本小节着重于说明awk程序的主要架构及工作原理, 并对一些重要的名词辅以必要的解释. 由这部分内容, 读者可体会出awk语言的主要精神及awk与其它语程序言的差异处. 为便于说明, 以条列方式说明于后.

  l        数据行: awk从数据文件上读取数据的基本单位.以上列文件emp.dat为例, awk读入的

  一般而言, 一个 数据行 就相当于数据文件上的一行资料. (参考 : 附录 B 内建变量RS )

  当 awk 从数据文件中读取一个数据行时, awk 会使用内建变量$0 予以记录.每当 $0 被改动时 (例如 : 读入新的数据行 或 自行变更 $0,...) awk 会立刻重新分析 $0 的字段情况, 并将 $0 上各字段的数据用 $1, $2, ..予以记录.

  awk 提供了许多内建变量, 使用者于程序中可使用这些变量来取得相关信息.常见的内建变量有 :

  各个字段的内容. 这个特色让使用者易于用 awk 编写 reformatter 来改变量据格式.

  Pattern 部分被省略, 表无任何限制条件. 故awk读入每笔数据行后都将无条件执行这个 Actions.

  print 的参数间彼此以 , (逗号) 隔开, 印出数据时彼此间会以空白隔开. (参考 附录 D 内建变量OFS)

  将上述的 程序部分 储存于文件 pay1.awk 中. 执行命令时再指定awk程序文件 之文件名. 这是执行awk的另一种方式, 特别适用于程序较大的情况, 其语法如下:

  awk中也提供与 C 语言中类似用法的 printf() 函数. 使用该函数可进一步控制数据的输出格式.

  awk的工作程序是: 从数据文件中每次读入一个数据行, 依序执行完程序中所有的 Pattern{ Action }指令:

  awk程序中允许使用字符串当做数组的下标(index). 利用这个特色十分有助于资料统计工作.(使用字符串当下标的数组称为Associative Array)

  首先建立一个数据文件, 并取名为 reg.dat. 此为一学生注册的资料文件; 第一栏为学生姓名, 其后为该生所修课程.

  但 awk 中使用数组并不须事先宣告. 以刚才使用的 Number[ ] 而言, 程序执行前, 并不知将来有哪些课程名称可能被当成 Number[ ] 的下标.

  使用该指令时, 须指定所要找寻的数组, 及一个变量. awk会使用该的变量来记录从数组中找到的每一个下标. 例如

  指定用 course 来记录 awk 从Number[ ] 中所找到的下标. awk每找到一个下标时, 就用course记录该下标之值且执行{....}中之指令. 藉由这个方式便可取出数组中储存的信息.

  唯有当awk读完所有数据时, 该Actions才会被执行 ( 注意, 不管数据行有多少笔, END仅在最后才成立, 故该Actions仅被执行一次.)

  awk程序中允许呼叫Shell指令. 并提供管道解决awk与系统间数据传递的问题. 所以awk很容易使用系统资源. 读者可利用这个特点来编写某些适用的系统工具.

  awk 程序并不一定要处理数据文件. 以本例而言, 仅输入程序文件count.awk, 未输入任何数据文件.

  为 awk 中表示管道的符号. awk 把 之前的字符串who当成Shell上的命令, 并将该命令送往Shell执行, 执行的结果(原先应于屏幕印出者)则藉由pipe送进awk程序中.

  本程序使用 getline 所 return 的数据来做为 while 判断循环停止的条件,某些awk版本较旧,并不容许使用者改变 $0 之值. 这种版的 awk 执行本程序时会产生 Error, 读者可于 getline 之后置上一个变量 (如此, getline 读进来的数据便不会被置于 $0 ), 或直接改用gawk便可解决.

  当程序执行执完毕后将更新第二个文件的数据(迟到次数), 并打印当日的报表.这程序将分成下列数小节逐步完成, 其大纲如下:

  某公司其员工到勤时间档如下, 取名为 arr.dat. 文件中第一栏为员工代号, 第二栏为到达时间. 本范例中, 将使用该文件为数据文件.

  awk中并未提供如 C 语言中之fopen() 指令, 也未有fprintf() 文件输出这样的指令. 但awk中任何输出函数之后皆可借助使用与UNIX 中类似的 I/O 重定向符, 将输出的数据重定向到指定的文件; 其符号仍为 (输出到一个新产生的文件) 或 ( 添加输出的数据到文件末尾 ).

  在awk中任何变量使用之前, 并不须事先声明. 其初始值为空字符串(Null string) 或 0.因此程序中若未以 将 today_rpt1 括住, 则 today_rpt1 将是一变量, 其值将是空字符串, 这会在执行时造成错误(Unix 无法帮您开启一个以空字符串为文件名的文件).

  因此在编辑awk程序时, 须格外留心. 因为若敲错变量名称,awk在编译程序时会认为是一新的变量, 并不会察觉. 因此往往会造成运行时错误.

  以 BEGIN 为 Pattern 的 Actions 于awk程序刚被执行尚未读取数据文件时被执行一次, 此后便不再被执行.

  本程序中若使用 将数据重导到 today_rpt1, awk 第一次执行该指令时会产生一个新档 today_rpt1, 其后再执行该指令时则把数据追加到today_rpt1文件末, 并非每执行一次就重开一个新文件.

  若采用其差异仅在第一次执行该指令时, 若已存在today_rpt1则 awk 将直接把数据append在原文件之末尾. 这一点, 与UNIX中的用法不同.

  awk程序中很容易使用系统资源. 这包括在程序中途调用 Shell 命令来处理程序中的部分数据; 或在调用 Shell 命令后将其产生的结果交回 awk 程序(不需将结果暂存于某个文件). 这一过程是借助 awk 所提供的管道 (虽然有些类似 Unix 中的管道, 但特性有些不同),及一个从 awk 中呼叫 Unix 的 Shell 命令的语法来达成的.

  [例 :] 承上题, 将数据按员工ID排序后再输出到文件 today_rpt2 , 并于表头附加执行时的日期.

  上列awk程序中, print$1, $2 可能反复执行很多次, 其输出的结果将先暂存于 pipe 中,等到该程序结束时, 才会一并进行 sort -k 1.

  使用本语法时应留心: 以上例而言,awk 立刻调用 Shell 来执行 ls, 执行次数是一次.

  除上列 a, b 二中语法外, awk程序中其它地方如出现像 date, cls, ls... 这样的字符串, awk只把它当成一般字符串处理.

  (有少数旧版的awk不允许即使用者自行更新(update)$0的值,或者更新$0时,它不会自动更新 $1,$2,..NF. 这情况下, 可改用gawk或nawk. 否则使用者也可自行以awk字符串函数split()来分隔$0上的数据)

  执行 mydisplay 之前, 须先将它改成可执行的文件(此步骤往后不再赘述). 请执行如下命令:

  但某些awk程序 仅 包含以 BEGIN 为Pattern的指令. 执行这种awk程序时, awk并不须开启任何数据文件.此时命令行上若指定一个不存在的数据文件,并不会产生 无法打开文件的错误.(事实上awk并未打开该文件)

  awk会将 Shell 命令行上awk程序(或 -f 程序文件名)之后的所有字符串, 视为将输入awk进行处理的数据文件文件名.

  若执行awk的命令行上 未指定任何数据文件文件名, 则将stdin视为输入之数据来源, 直到输入end of file( Ctrl-D )为止.

  将会发现: 此后键入的任何数据将逐行复印一份于屏幕上. 这情况不是机器当机 ! 是因为awk程序正处于执行中. 它正按程序指示, 将读取数据并重新dump一次; 只因执行时未指定数据文件文件名, 故awk 便以stdin(键盘上的输入)为数据来源. 读者可利用这个特点, 设计可与awk即时聊天的程序.

  awk不仅能自动分割字段, 也允许使用者改变其字段切割方式以适应各种格式之需要. 使用者也可自定义函数, 若有需要可将该函数单独写成一个文件,以供其它awk程序调用.

  [ 范例 : ] 承接 6.2 的例子, 若八点为上班时间, 请加注 *于迟到记录之前, 并计算平均上班时间.

  因八点整到达者,不为迟到, 故仅以到达的小时数做判断是不够的; 仍应参考到达时的分钟数. 若 将到达时间转换成以分钟为单位, 不仅易于判断是否迟到, 同时也易于计算到达平均时间.

  到达时间($2)的格式为 dd:dd 或 d:dd; 数字当中含有一个 :.但文本数字交杂的数据awk无法直接做数学运算. (注: awk中字符串26与数字26, 并无差异, 可直接做字符串或数学运算, 这是awk重要特色之一. 但awk对文本数字交杂的字符串无法正确进行数学运算).

  对到达时间($2) d:dd 或 dd:dd 进行字符串运算,分别取出到达的小时数及分钟数.

  substr( 字符串,起始位置,长度) :返回从起始位置起, 指定长度之子字符串. 若未指定长度, 则返回从起始位置到字符串末尾的子字符串.

  明显地, awk程序中使用方法二比方法一更简洁方便. 本例子中采用方法二,也借此示范改变字段切割方式的用途.

  awk 中亦允许使用者自定函数. 函数定义方式请参考本程序, function 为 awk 的保留字.

  因为 Shell 排序后的数据也要写到 today_rpt3, 所以awk必须先关闭使用中的today_rpt3 以使 Shell 正确将排序后的数据追加到today_rpt3否则2个不同的 process 同时打开一个文件进行输出将会产生不可预期的结果.

  [ 范 例 : ] 承上题,从文件中读取当月迟到次数, 并根据当日出勤状况更新迟到累计数.(按不同的月份累计于不同的文件)

  程序中自动抓取系统日期的月份名称, 连接上late.dat, 形成累计迟到次数的文件名称(如 : 09月late.dat,...), 并以变量late_file记录该文件名.

  若使用者可自行把数据放入$0, awk会自动对这新置入 $0 的数据进行字段分割. 之后程序中可用$1, $2,..来表示该笔资料的第一栏,第二栏,..,

  (注: 有少数awk版本不容许使用者自行将数据置于 $0, 遇此情况可改用gawk或nawk)

  执行getline指令时, 若成功读取记录,它会返回1. 若遇到文件结束, 它返回0; 无法打开文件则返回-1.

  awk是依照其内建变量 RS(Record Separator) 的定义将文件中的数据分隔成一行一行的Record. RS 的默认值是 \n(跳行符号), 故平常awk中一行数据就是一笔 Record. 但有些文件中一笔Record涵盖了多行数据, 这种情况下不能再以 \n 来分隔Records. 最常使用的方法是相邻的Records之间改以 一个空白行 来隔开. 在awk程序中, 令 RS = (空字符串)后, awk把会空白行当成来文件中Record的分隔符. 显然awk对 RS = 另有解释方式,简略描述如下, 当 RS = 时:数个并邻的空白行, awk仅视成一个单一的Record Saparator. (awk不会于两个紧并的空白行之间读取一笔空的Record)

  awk会略过(skip)文件头或文件尾的空白行. 故不会因为这样的空白行,造成awk多读入了二笔空的数据.

  该文件的开头有数行空白行, 各笔Record之间使用一个或数个空白行隔开. 读者请细心观察,当 RS = 时, awk读取该数据文件之方式.

  本程序同时也改变字段分隔字符( FS= \n ), 如此一笔数据中的每一行都是一个field. 例如: awk读入的第一笔 Record 为

  大部分的应用程序都允许使用者在命令之后增加一些选择性的参数.执行awk时这些参数大部分用于指定数据文件文件名, 有时希望在程序中能从命令行上得到一些其它用途的数据. 本小节中将叙述如何在awk程序中取用这些参数.

  ARGC : 为一整数. 代表命令行上, 除了选项-v, -f 及其对应的参数之外所有参数的数目.

  awk将被蒙骗,误以为命令行上并无数据文件文件名, 故不会以 ARGV[1], ARGV[2],..为文件名来打开文件读取数据; 但在程序中仍可通过 ARGV[1], ARGV[2],..来取得命令行上的数据.

  执行awk程序时, awk会自动从文件中读取数据来进行处理, 直到文件结束.只要将awk读取数据的来源改成键盘输入,便可设计与awk 交互的程序了.

  [ 范例 :] 本节将编写一个英语生字测验的程序, 它将印出中文字意,再由使用者回答其英语生字.

  awk 中除了函数的参数列(Argument List)上的参数(Arguments)外,所有变量不管于何处出现,全被视为全局变量. 其生命持续至程序结束 --- 该变量不论在function外或 function内皆可使用,只要变量名称相同所使用的就是同一个变量,直到程序结束.

  因递归函数内部的变量, 会因它调用子函数(本身)而重复使用,故编写该类函数时, 应特别留心.

  函数内可任意使用主程序中的任何变量.函数内所启用的任何变量(除参数外), 于该函数之外依然可以使用.此特性优劣参半, 最大的坏处是式中的变量不易被保护, 特别是递归调用本身, 执行子函数时会破坏父函数内的变量.

  一个变通的方法是: 在函数的参数列中虚列一些参数. 函数执行中使用这些虚列的参数来记录不想被破坏的数据,如此执行子函数时就不会破坏到这些数据. 此外awk 并不会检查调用函数时所传递的参数个数是否一致.

  可将上列函数中的 i 虚列在该函数的参数列上, 如此 i 便是一个局部变量, 不会因执行子函数而被破坏.

  [ 范例 :]以下是一个常见的递归调用范例. 它要求使用者输入一串元素(各元素间用空白隔开) 然后印出这些元素所有可能的排列.

  为避免执行子函数时破坏 new_main_lst, nf, i, j 故把这些变量也列于参数列上. 如此,new_main_lst, nf, i, j 将被当成局部变量,而不会受到子函数中同名的变量影响. 读者声明函数时,参数列上不妨将这些 虚列的参数 与真正用于传递信息的参数间以较长的空白隔开, 以便于区别.

  BEGIN 成立(其值为true)的时机是: awk 程序一开始执行, 尚未读取任何数据之前. 所以在 BEGIN { Actions } 语法中, 其 Actions 部份仅于程序一开始执行时被执行一次. 当 awk 从数据文件读入数据行后, BEGIN 便不再成立, 故不论有多少数据行, 该 Actions 部份仅被执行

  有些awk程序甚至不需要读入任何数据行. 遇到这情况可把整个程序置于以 BEGIN 为 Pattern的 Actions 中.

  END 成立(其值为true)的时机与 BEGIN 恰好相反, 为:awk 处理完所有数据, 即将离开程序时平常读入数据行时, END并不成立, 故其对应的 Actions 并不被执行; 唯有当awk读完所有数据时, 该 Actions 才会被执行

  Pattern 中被用来比对的字符串为$0 时(如本例), 可仅以正则表达式部分表示整个Pattern.

  该 Pattern 用以判断 $0(数据行) 中是否含有匹配该正则表达式的子字符串; 若含有该成立(true) 则执行其对应的 Actions.

  (a)与 C 语言中相同, 若 表达式 计算(evaluate)后之值不为 0 或空字符串, 则执行 语句1; 否则执行 语句2.

  (b)进行逻辑判断的表达式所返回的值有两种, 若最后的逻辑值为true, 则返回1, 否则返回0.

  (a) 上例要求用户从键盘上输入一个字符, 若该字符不是Y, y, N, 或 n则会不停执行该循环, 直到读取正确字符为止.

  (a)这个 for 指令, 专用以查找数组中所有的下标值, 并依次使用所指定的变量予以记录. 以本例而言, 变量 any 将逐次代表 last, 1 及2 .

  上例中, awk 不断地从文件 datafile 中读取资料, 当$1等于0时,就停止该执行循环.

  (c)打印时, 一般字串将被原封不动地打印出来. 遇到格式控制字符时,则依序把 format后方之 item 转换成所指定的格式后进行打印.

  (c)上式中, 字串 ID# : 与变量 id 之间使用,隔开, 打印时两者之间会以自动 OFS(请参考 附录D 內建变量 OFS) 隔开. OFS 之值一般內定为 一个空格

  需与后方的 shell command 完全相同(一字不差), 较佳的方法是先以该字串定义一个简短的变量, 程序中再以此变量代替该shell command

  awk 程式中常使用数组(Array)来记忆大量数据, delete 指令便是用来释放数组中的元素所占用的内存空间.

  若原字串中含有欲找寻的子字串,则返回该子字串在原字串中第一次出现的位置,若未曾出现该子字串则返回0.

  awk会在原字串中找寻合乎正则表达式的子字串. 若合乎条件的子字串有多个, 则以原字串中最左方的子字串为准.

  awk将依所指定的分隔字符(field separator)来分隔原字串成一个个的栏位(field),并以指定的数组记录各个被分隔的栏位.

  该函数的用法与awk或C的输出函数printf()相同. 所不同的是sprintf()会将要求印出的结果当成一个字串返回. 一般最常使用sprintf()来改变资料格式. 如: x 为一数值资料, 若欲将其变成一个含二位小数的资料,可执行如下指令:

  sub()不仅可执行替换(replacement)的功用,当第二个参数为空字串()时,sub()所执行的是去除指定字串的功用.

  通过 sub() 与 match() 的搭配使用,可逐次取出原字串中合乎指定条件的所有子字串.

  除非使用者自行指定rand()函数起始的种子,否则每次执行awk程式时,  rand()函数都将使用同一个內定的种子,来产生随机数.

  ARGC表示命令行上除了选项 -F, -v, -f 及其所对应的参数之外的所有参数的个数.若将awk程式直接写於命令列上, 则 ARGC 亦不将该程式部分列入计算.

  令 FS = [ :]+ 表示任何由 空白 或 冒号: 所组成的字串都可当成分隔字符, 则分割后 :

  awk 每读入一笔资料后, 在程序中可以 NF 来得知该行数据包含的栏位个数.在下一笔资料被读入之前, NF 并不会改变. 但使用者若自行使用$0来记录数据,例如: 使用 getline , 此时 NF 将代表新的 $0 上所记载的资料的栏位个数.

  不论是查找字串或替换字串, 都得先告诉这些指令所要查找(被替换)的字串为何.若未能预先明确知道所要查找(被替换)的字串为何, 只知该字串存在的范围或特征时,例如 :

  例 (一) 中, 要查找任一在 T 与 .c 之间存在一个阿拉伯数字的字串;当然您可以列举的方式, 一一把所要找寻的字串告诉执行命令的指令.但例 (二) 中合乎该条件的字串有无限种可能, 势必无法一一列举.此时,便需要另一种字串表示的方法(协定).

  正则表达式(以下简称 Regexp)是一种字串表达的方式. 可用以指定具有某特征的所有字串.

  须留心 UNIX Shell 中使用 *表示 Wild card, 可用以代表任意长度的字串.而 Regexp 中使用 . 来代表一个任意字符.(注意: 并非任意长度的字串)Regexp 中 * 另有其它涵意, 并不代表任意长度的字串.

  Regexp 中特殊字符将被解释成特定的意义. 若要表示特殊字符的字面(literal meaning)意义时,在特殊字符之前加上\即可.

  例如: Regexp /[ Tt ]/ 其中括号內有空白字符, 除表示T, t 中任一个字符, 也可代表一个 (空白字符)

  文章目录Pillow模块讲解一、Image模块1.1 、打开图片和显示图片1.2、创建一个简单的图像1.3、图像混合(1)透明度混合(2)遮罩混合1.4、图像缩放(1)按像素缩放(2)按尺寸缩放1.5、图像的剪切与粘贴(1)图像粘贴(2)裁剪图像1.4、图像旋转和格式转换(1)图像旋转(2)格式转换1.5、分离和合并(1)分离(2)合并二、ImageFilter2.1、高斯模糊2.2、其它滤镜三、......

  当HR压你价,说你只值7K时,你可以流畅地回答,记住,是流畅,不能犹豫。礼貌地说:“7K是吗?了解了。嗯~其实我对贵司的面试官印象很好。只不过,现在我的手头上已经有一份11K的offer。来面试,主要也是自己对贵司挺有兴趣的,所以过来看看……”(未完)这段话主要是陪HR互诈的同时,从公司兴趣,公司职员印象上,都给予对方正面的肯定,既能提升HR的好感度,又能让谈判气氛融洽,为后面的发挥留足空间。......

  虽然大公司并不是人人都能进,但我仍建议还未毕业的同学,尽力地通过校招向大公司挤,但凡挤进去,你这一生会容易很多。大公司哪里好?没能进大公司怎么办?答案都在这里了,记得帮我点赞哦。目录:技术氛围 内部晋升与跳槽 啥也没学会,公司倒闭了? 不同的人脉圈,注定会有不同的结果 没能去大厂怎么办?一、技术氛围纵观整个程序员技术领域,哪个在行业有所名气的大牛,不是在大厂?而且众所......

  董付国系列教材《Python程序设计基础》、《Python程序设计(第2版)》、《Python可以这样学》配套视频,讲解Python 3.5.x和3.6.x语法、内置对象用法、选择与循环以及函数设计与使用、lambda表达式用法、字符串与正则表达式应用、面向对象编程、文本文件与二进制文件操作、目录操作与系统运维、异常处理结构。

  在linux下抓取目录树,双击后获取该节点子节点(逐步生成)。另外有两个类,一个是windows下的(一次性获取目录树),一个是linux下的(足部获取目录树)

 
关键词: awk手册
(文/小编)
打赏
免责声明
• 
本文为小编原创作品,作者: 小编。欢迎转载,转载请注明原文出处:http://www.31duo.com/news/show-373285.html 。本文仅代表作者个人观点,本站未对其内容进行核实,请读者仅做参考,如若文中涉及有违公德、触犯法律的内容,一经发现,立即删除,作者需自行承担相应责任。涉及到版权或其他问题,请及时联系我们。
 

(c)2016-2019 31DUO.COM All Rights Reserved浙ICP备19001410号-4

浙ICP备19001410号-4