Linux Shell 脚本编程(8)—文本过滤(awk命令)

Linux Shell 脚本编程(8)—文本过滤(awk命令)

文本过滤

awk命令

  • awk 是一款设计用于数据流的工具。可以对行和列进行操作
  • awk是一种编程语言,用于在linux/unix下对文本和数据进行扫描与处理。数据可以来自标准输入、文件、管道。
  • 实际上awk有很多种版本,如:awk、nawk、mawk、gawk、MKS awk、tawk… 这其中有开源产品也有商业产品。

    • 目前在Linux中常用的awk编译器版本有mawk,gawk,其中以RedHat为代表使用的是gawk,以Ubuntu为代表使用的是mawk。gawk是GNU Project 的awk解释器的开源代码实现。
  • awk可从文件或字符串值基于指定规则浏览和抽取信息

  • awk有很多内建的功能:数组、函数。具有高度灵活性!

  • awk逐行扫描,但对列进行操作。

    • : 每一列叫“域”;
    • 分隔符(定界符): 列与列之间区分符号叫做“分隔符”,默认是空格。
时间          开盘          最高      最低          收盘      涨跌          涨幅%     振幅%         
2014-05-28  2034.56     2052.66     2029.34     2050.23     +15.66      0.77        1.15        
2014-05-29  2051.84     2057.08     2039.24     2040.60     -9.63       -0.47       0.87    
2014-05-30  2040.39     2046.96     2031.37     2039.21     -1.38       -0.07       0.76        

#每一列的数据叫做域
#列之间用分隔符(这里是Tab)分开。
  • 注意多个脚本表达式之间用分号进行”;”分割

  • awk命令脚本中引号的用法(注意)
    引号的匹配是就近匹配,注意使用转义.

 '{ print $1 "\"--\"" $2 }'
 #输出结果字段间将以 "--" 进行分割

1. awk 脚本结构方式(3种)

1.1 命令行方式

  • 格式: awk [-F field-separator] ‘commands’ input_file(s)

    • [-F field-seperator] 是可选的,指明文件域分隔符。
    • awk使用空格(’ ‘)作为缺省的域分隔符,因此如果要浏览域间有空格的文本,不必指定这个选项:
      awk ‘commands’ input_file
    • 但如果要浏览诸如passwd文件,此文件各域以冒号(:)作为分隔符,必须指明-F选项,如下
      awk -F”:” ‘commands’ input_file 或 awk -F: ‘commands’ input_file
      //例子: awk -F”:” ’ { print $1 } ’ /etc/passwd
    • ‘commands’ 中 commands为命令或者脚本(文件); 用单引号’ ’ 括起。
  • command(s) 基本结构 = 【模式匹配 + 处理过程】
    pattern { action } pattern 用于找到要处理的行; action用于处理动作。

#一般的格式如下:
awk ' BEGIN{ 命令 } pattern { 命令 } END{ 命令 } ' file(s)


#提取stock.txt的签3列数据。
jianliu@ubuntu:~/aa$ awk ' BEGIN{ print "Start" } { print $1,$2,$3 } END{ print "End" } ' stock.txt
Start
时间 开盘 最高
2014-05-28 2034.56 2052.66
2014-05-29 2051.84 2057.08
2014-05-30 2040.39 2046.96
End

jianliu@ubuntu:~/aa$ cat stock.txt
时间          开盘          最高      最低          收盘      涨跌          涨幅%     振幅%         
2014-05-28  2034.56     2052.66     2029.34     2050.23     +15.66      0.77        1.15        
2014-05-29  2051.84     2057.08     2039.24     2040.60     -9.63       -0.47       0.87    
2014-05-30  2040.39     2046.96     2031.37     2039.21     -1.38       -0.07       0.76

—–通常由3部分组成: BEGIN、END和带模式匹配选项的常见语句块。这3个部分都是可选项,再脚本中可以省略任意部分。

awk ' BEGIN{ 命令 } ' file
awk ' { 命令 } ' file
awk ' END{ 命令 } ' file
  • awk命令工作原理

    • (1) 初始化块: 执行BEGIN { 命令 } 语句块中的语句
      该语句块在读取数据流行数据的最开始前首先被执行一次,一般用于初始化变量、打印输出表格的表头等初始化信息和数据。

    • (2) 循环执行块: 从文件file或stdin中读取一行,然后执行 pattern { 命令 }, 重复这个过程,直到文件全部读取完毕。

    • (3) 结尾块: 当读至输入流末尾时,执行END { 命令 }语句块。
      一般用于答应所有行的分析结果、汇总信息

1。 每读取一行,awk就会检查改行和提供的样式是否匹配样式本身可以是正则表达式、条件语句以及行匹配等;如果当期行匹配该样式pattern,执行{ } 中的语句。

2。 样式pattern是可选的。若未提供样式,则所有的行都是匹配的。

3。 pattern语句块中的{ 命令 },也是可选的。若未提供,则默认执行{ print } ,打印所读取到的每一行

  • 关于 print
    (1)当print的参数是以逗号进行分隔时,参数打印时则以空格作为定界符。
jianliu@ubuntu:~/aa$ echo | awk ' BEGIN { var1="v1"; var2="v2"; var3="v3"; } { print var1, var2, var3; } '
v1 v2 v3
 (2)在awk的print语句中,双引号是被当做拼接操作符(concatenation operator)使用的。
jianliu@ubuntu:~/aa$ echo | awk ' BEGIN { var1="v1"; var2="v2"; var3="v3"; } { print var1 "-" var2 "-" var3; } '
v1-v2-v3

—-awk的printf()函数的语法和C语言中的同名函数一样。我们也可以用这个函数来代替print。


1.2 是将所有awk命令插入一个文件,并使awk程序可执行,然后用awk命令解释器作为脚本的首行,以便通过键入脚本名称来调用它。

jianliu@ubuntu:~/aa$ cat script.sh
#!/bin/bash
awk '{ print  $1 " <-> " $2 " <-> " $3 }' stock.txt


jianliu@ubuntu:~/aa$ awk -f script.sh stock.txt
时间 <-> 开盘 <-> 最高
2014-05-28,三 <-> 2034.56 <-> 2052.66
2014-05-29,四 <-> 2051.84 <-> 2057.08
2014-05-30,五 <-> 2040.39 <-> 2046.96
2014-06-03,二 <-> 2039.20 <-> 2049.58
2014-06-04,三 <-> 2037.99 <-> 2038.48
2014-06-05,四 <-> 2019.44 <-> 2041.70
2014-06-06,五 <-> 2040.86 <-> 2041.57
2014-06-09,一 <-> 2024.94 <-> 2045.26
2014-06-10,二 <-> 2033.21 <-> 2052.76
2014-06-11,三 <-> 2049.13 <-> 2056.63
2014-06-12,四 <-> 2051.58 <-> 2057.11

1.3 将所有的awk命令插入一个单独文件,然后调用 awk -f awk-script-file input-file(s)

-f选项 指明在文件awk_script_file中的awk脚本,input_file(s)是使用awk进行浏览的文件名。

#脚本文件
jianliu@ubuntu:~/aa$ cat script.sh
#!/bin/bash
{ print  $1 " <-> " $2 " <-> " $3 }


jianliu@ubuntu:~/aa$ awk -f script.sh stock.txt
时间 <-> 开盘 <-> 最高
2014-05-28,三 <-> 2034.56 <-> 2052.66
2014-05-29,四 <-> 2051.84 <-> 2057.08
2014-05-30,五 <-> 2040.39 <-> 2046.96
2014-06-03,二 <-> 2039.20 <-> 2049.58
2014-06-04,三 <-> 2037.99 <-> 2038.48
2014-06-05,四 <-> 2019.44 <-> 2041.70
2014-06-06,五 <-> 2040.86 <-> 2041.57
2014-06-09,一 <-> 2024.94 <-> 2045.26
2014-06-10,二 <-> 2033.21 <-> 2052.76
2014-06-11,三 <-> 2049.13 <-> 2056.63
2014-06-12,四 <-> 2051.58 <-> 2057.11

2. 特殊变量使用

变量名称意义注意事项
NR记录数量在执行过程中对应于当前行号
NF字段数量对应于当前行的字段数目,字段之间用定界符隔开
$0包含执行过程中当前行的文本内容。
$1包含第一个字段的文本内容。当前行中的第一列数据
$2包含第二个字段的文本内容。
$NF一行中最后一个字段
$(NF-1)一行中倒数第二个字段
jianliu@ubuntu:~/aa$ echo -e "line1 f2 f3 f4\nline2 f5 f6 f7 f8\nline3 f9 f10 f11 f12 f13 f14" | \ awk ' { print "Line no:"NR",No of fields:"NF, "$0="$0, "$1="$1, "$2="$2, "$3="$3, "$NF="$NF } '
Line no:1,No of fields:4 $0=line1 f2 f3 f4 $1=line1 $2=f2 $3=f3 $NF=f4
Line no:2,No of fields:5 $0=line2 f5 f6 f7 f8 $1=lin2 $2=f5 $3=f6 $NF=f8
Line no:3,No of fields:7 $0=line3 f9 f10 f11 f12 f13 f14 $1=line3 $2=f9 $3=f10 $NF=f14

2.1 统计文件中的行数

jianliu@ubuntu:~/aa$ cat test0.txt
word1  1
aword2 2
word3 3
1word4 4
word@ 5
wor3 6
wo3 7
word12 8
abcde 9
wore21 10
12345 11

jianliu@ubuntu:~/aa$ awk ' END{print NR} ' test0.txt
11
  • 这里只使用了END语句块。每读入一行, awk会将NR更新为对应的行号。当到达最后一行时,NR中的值就是最后一行的行号,于是,位于END语句块中的NR就包含了文件的行数。

2.2 进行数值运算

jianliu@ubuntu:~/aa$ seq 10 | awk 'BEGIN{sum=0; print "Summation:"} {sum+=$1; print $1"+"} END{print "=="; print sum}'
Summation:
1+
2+
3+
4+
5+
6+
7+
8+
9+
10+
==
55

2.2 提取文本中的前3列

jianliu@ubuntu:~/aa$ awk ' { print $1 " <-> " $2 " <-> " $3 } ' stock.txt
时间 <-> 开盘 <-> 最高
2014-05-28,三 <-> 2034.56 <-> 2052.66
2014-05-29,四 <-> 2051.84 <-> 2057.08
2014-05-30,五 <-> 2040.39 <-> 2046.96
2014-06-03,二 <-> 2039.20 <-> 2049.58
2014-06-04,三 <-> 2037.99 <-> 2038.48
2014-06-05,四 <-> 2019.44 <-> 2041.70
2014-06-06,五 <-> 2040.86 <-> 2041.57
2014-06-09,一 <-> 2024.94 <-> 2045.26
2014-06-10,二 <-> 2033.21 <-> 2052.76
2014-06-11,三 <-> 2049.13 <-> 2056.63
2014-06-12,四 <-> 2051.58 <-> 2057.11
2014-06-13,五 <-> 2049.21 <-> 2073.60
2014-06-16,一 <-> 2070.70 <-> 2087.32

3. 将外部变量传递给awk

  • 选项-v,将外部值(并非来自stdin)传递给awk:
jianliu@ubuntu:~/aa$ VAR=1000

jianliu@ubuntu:~/aa$ echo | awk -v VAR2=$VAR '{print VAR2}'
1000
  • 多个外部变量传递给awk
jianliu@ubuntu:~/aa$ var1="var1";var2="var2"

jianliu@ubuntu:~/aa$ echo | awk '{print v1,v2}' v1=$var1 v2=$var2
var1 var2
  • 输入来自文件而非标准输入是,传递多个外部变量
#文本为一行
jianliu@ubuntu:~/aa$ cat TEST0.txt
var1 var2 var3

jianliu@ubuntu:~/aa$ awk '{print v1,v2}' v1=$var1 v2=$var2 TEST0.txt
var1 var2

#文本为三行
jianliu@ubuntu:~/aa$ cat TEST1.txt
var1 
var2 
var3

jianliu@ubuntu:~/aa$ awk  '{print v1,v2}' v1=$var1 v2=$var2 TEST1.txt
var1 var2
var1 var2
var1 var2

#输出结果的差别在于,awk按行进行扫描,默认情况下,每一行都执行{ print v1,v2}操作,而本文0中只有一行,文本1中有三行,故分别执行1次和3次。
  • 在上面的方法中,变量之间用空格分隔,以键-值对的形式(v1=$var1 v2=$var2)作为awk的
    命名行参数紧随在BEGIN、 {}和END语句块之后。

4. getline读取某一行

  • awk通常默认读取一个文件的所有行。如果只想读取某一行,可以使用getline函数。
    有时候,我们需要从BEGIN语句块中读取第一行

  • 格式: getline var —- 变量var就包含了特定行的内容。
    如果调用不带参数的getline,可以用 $0$1$2访问文本行的内容。

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

5. 使用过滤模式对awk处理的行进行过滤

命令条件意义
awk ‘NR < 5’行号小于5的行
awk ‘NR==1, NR==4’行号在1到5之间的行
awk ‘/linux/’包含样式linux的行(可以用正则表达式来指定模式
awk ‘!/linux/’不包含包含模式为linux的行
jianliu@ubuntu:~/aa$ cat test0.txt
word1  1
aword2 2
word3 3
1word4 4
word@ 5
wor3 6
wo3 7
word12 8
abcde 9
wore21 10
12345 11

jianliu@ubuntu:~/aa$ awk 'NR < 5 {print $0}' test0.txt
word1  1
aword2 2
word3 3
1word4 4
jianliu@ubuntu:~/aa$ awk '/word/ {print}' test0.txt
word1  1
aword2 2
word3 3
1word4 4
word@ 5
word12 8
#备注:列出计算机中ID号大于500的用户名
jianliu@ubuntu:~/aa$ awk -F: '$3>500 { print } ' /etc/passwd
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
jianliu:x:1000:1000:Ubuntu14.04,,,:/home/jianliu:/bin/bash

jianliu@ubuntu:~/aa$ awk -F":" '$3>500 { print } ' /etc/passwd
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
jianliu:x:1000:1000:Ubuntu14.04,,,:/home/jianliu:/bin/bash

6. 使用过滤模式对awk处理的行进行过滤

  • 默认的字段定界符是空格。我们也可以用 -F “delimiter”明确指定一个定界符:
$ awk -F: '{ print $NF }' /etc/passwd

或者

#在BEGIN语句块中则可以用OFS="delimiter"设置输出字段的定界符。
awk 'BEGIN { FS=":" } { print $NF }' /etc/passwd

7. 从awk中读取命令输出

  • 将命令的输出结果读入变量output的语法:
    “command” | getline output
#echo会生成一个空白行。变量cmdout包含命令grep root /etc/passwd的输出,该命令会打印出包含root的行。

jianliu@ubuntu:~/aa$ echo | awk ' { "grep root /etc/passwd" | getline cmdout; print cmdout } '
root:x:0:0:root:/root:/bin/bash
  • awk支持以文本作为索引的关联数组。

8. 在awk中使用循环

  • for循环的格式1:
    for(i=0; i<10; i++) { print $i; }
  • for循环的格式2:
    for(i in array) { print array[i])

9. awk内建的字符串控制函数

这里写图片描述

  • 5
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
awk命令是一种用于处理文本文件的强大工具,常用于 shell 脚本中。它可以根据指定的规则对文本进行分割、格式化和提取等操作。下面我将为您解释一些常见的使用示例和处理规则。 示例1:使用awk命令将一个文件中的整数部分提取出来,存到另外一个文件中。假设我们有一个名为input.txt的文件,其中包含了一些数字,我们想要提取出这些数字的整数部分并存储到output.txt文件中。可以使用以下命令实现: ```shell awk '{print int($0)}' input.txt > output.txt ``` 这个命令会逐行读取input.txt文件的内容,将每一行的数字取整后输出到output.txt文件中。 示例2:提取passwd文件中的用户名和UID。假设我们有一个名为passwd的文件,其中包含了系统用户的信息。我们想要提取出用户名和对应的UID。可以使用以下命令实现: ```shell awk -F: '{print $1, $3}' passwd ``` 这个命令使用冒号作为字段分隔符(-F:),然后打印出每一行的第一个字段(用户名)和第三个字段(UID)。 处理规则: - awk命令的处理规则通常由花括号{}包围,可以在其中使用各种条件和操作。 - 可以使用条件语句(if、else)和循环语句(for、while)对文本进行处理。 - 可以使用内置的函数和运算符进行数学计算、字符串处理等操作。 - 可以使用特殊变量(例如$0表示整行文本,$1表示第一个字段)引用文本中的内容。 总之,awk命令是一种非常强大和灵活的文本处理工具,可以在shell脚本中广泛应用。它提供了丰富的功能和语法,可以根据具体需求对文本进行各种操作和提取。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [写脚本必用命令——awk命令的讲解](https://blog.csdn.net/m0_54355780/article/details/122479439)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值