Linux-awk的详细使用

awk是一个强大的文本处理工具,常用于从文件中提取数据。它支持正则表达式匹配、内建变量、数组和函数操作。文章介绍了awk的基本语法、选项、用法,包括如何处理数据、指定分隔符、设置变量、使用内建函数,以及在条件判断和循环中的应用。awk在数据分析和日志处理中有着广泛的应用。
摘要由CSDN通过智能技术生成

awk

介绍

awk 是一个文本处理工具,通常用于从文本文件中提取数据并对其进行处理。它是一种解释型语言,可以从标准输入或文件中读取数据,并对这些数据进行逐行处理

语法

awk options 'pattern { action }' filename

其中,options为可选参数。

pattern是一个正则表达式,用于匹配输入文件中的行。如果省略pattern,则默认匹配所有行。

action是一个或多个命令,用于在匹配到的行上执行操作。如果省略action,则默认打印匹配到的行。

filename是要处理的文件的名称。如果省略filename,则默认从标准输入读取数据。

awk 'BEGIN{commands}pattern{commands}END{commands}' file
  • BEGIN{commands}:处理数据前执行的命令
  • pattern{commands}:每行都执行的命令
  • END{commands}:处理数据后执行的命令

awk的命令执行过程

  1. 执行BEGIN{commands}语句块中的语句
  2. 从文件或stdin中读取第一行
  3. 有无模块匹配,若无执行{}中的语句,
  4. 若有则检查该行与patter是否匹配,若匹配,则执行{}中的语句。
  5. 若不匹配则不执行{}中的语句,接着读取下一行
  6. 重复这个过程,直到所有行被读取完毕
  7. 最后执行END{commands}语句块中的语句。

注意事项

awk -F分隔符 '/模式/{动作}' 输入文件

awk的指定一定要用单引号括起

awk的动作一定要用花括号括起

模式可以是正则表达式,条件表达式或两种组合

如果模块是正则表达式要用/定界符

多个动作之间用;号分开

例如:

在去匹配grade.txt文件之间先输出"你好",定义变量i的值为0,随后开始去匹配grade.txt文件每行的第一个字段是否含有li,如果含有li,输出该字段,同时变量i+1,在匹配完grade.txt文件的所有行后,输出"结束了",同时输出含有li的行数。

awk -F":" 'BEGIN{print "你好";i=0} $1 ~/li/{print
$1;i+=1}END{print "结束了" i}' grade.txt

不显示以h开头的行的第一列和第七列

[root@localhost shell-test]# awk -F: '/^[^h]/{print $1,$7}' /etc/p

选项

  • -F:指定输入字段分隔符。例如,-F:表示使用冒号作为字段分隔符。
  • -v:定义awk变量,可以在awk程序中使用。例如,-v var=value定义变量var,并设置其值为value。
  • -f:指定awk程序文件。例如,-f script.awk指定使用脚本文件script.awk作为awk程序。
  • -W:设置awk的行为。例如,-W posix启用POSIX兼容模式,-W traditional启用传统模式。
  • -S:启用seccomp沙箱模式,增强awk的安全性。

基本用法

先创建log.txt文本

[root@localhost 4-18]# vim log.txt
[root@localhost 4-18]# cat log.txt 
2 this is a test
3 Do you like awk
This's a test
10 There are orange,apple,mongo

用法一

awk '{[pattern] action}' {filenames}   # 行匹配语句 awk '' 只能用单引号

实例

# 每行按空格或TAB分割,输出文本中的1、4项
 $ awk '{print $1,$4}' log.txt
 ---------------------------------------------
 2 a
 3 like
 This's
 10 orange,apple,mongo
 # 格式化输出
 $ awk '{printf "%-8s %-10s\n",$1,$4}' log.txt
 ---------------------------------------------
 2        a
 3        like
 This's
 10       orange,apple,mongo

用法二:

awk -F  #-F相当于内置变量FS, 指定分割字符

实例:

# 使用","分割
 $  awk -F, '{print $1,$2}'   log.txt
 ---------------------------------------------
 2 this is a test
 3 Do you like awk
 This's a test
 10 There are orange apple
 # 或者使用内建变量
 $ awk 'BEGIN{FS=","} {print $1,$2}'     log.txt
 ---------------------------------------------
 2 this is a test
 3 Do you like awk
 This's a test
 10 There are orange apple
 # 使用多个分隔符.先使用空格分割,然后对分割结果再使用","分割
 $ awk -F '[ ,]'  '{print $1,$2,$5}'   log.txt
 ---------------------------------------------
 2 this test
 3 Are awk
 This's a
 10 There apple

用法三:

awk -v  # 设置变量

实例:

 $ awk -va=1 '{print $1,$1+a}' log.txt
 ---------------------------------------------
 2 3
 3 4
 This's 1
 10 11
 $ awk -va=1 -vb=s '{print $1,$1+a,$1b}' log.txt
 ---------------------------------------------
 2 3 2s
 3 4 3s
 This's 1 This'ss
 10 11 10s

用法四:

awk -f {awk脚本} {文件名}

实例:

 $ awk -f cal.awk log.txt

运算符

运算符描述
= += -= *= /= %= ^= **=赋值
?:C条件表达式
||逻辑或
&&逻辑与
~ 和 !~匹配正则表达式和不匹配正则表达式
< <= > >= != == ~ !关系运算符
空格连接
+ -加,减
* / %乘,除与求余
+ - !一元加,减和逻辑非
^ ***求幂
++ –增加或减少,作为前缀或后缀
$字段引用
in数组成员

过滤第一列大于2的行

$ awk '$1>2' log.txt    #命令
#输出
3 Do you like awk
This's a test
10 There are orange,apple,mongo

过滤第一列等于2的行

$ awk '$1==2 {print $1,$3}' log.txt    #命令
#输出
2 is

过滤第一列大于2并且第二列等于’Are’的行

$ awk '$1>2 && $2=="Are" {print $1,$2,$3}' log.txt    #命令
#输出
3 Are you

注意事项

&&||的优先级要高,||!要高

文本数据表达式: ==(精确匹配)

~波浪号表示匹配后的模式(模糊匹配)

例子:

有grade.txt文本如下:

[root@localhost shell-test]# cat grade.txt 
name 	chinese 	math 	english
xiaoming	80	90	99
lihua	89	70	99
yang	88	80	90
yangle	80	97	89

精确匹配每行第一个字段是yang的行

[root@localhost shell-test]# awk '$1 == "yang"{print $0}' grade.txt 
----------------------------------------------------
yang	88	80	90

模糊匹配每行第一个字段是yang的行

[root@localhost shell-test]# awk '$1 ~/yang/{print $0}' grade.txt 
------------------------------------------------
yang	88	80	90
yangle	80	97	89

内建变量

变量描述
$n当前记录的第n个字段,字段间由FS分隔
$0完整的输入记录
ARGC命令行参数的数目
ARGIND命令行中当前文件的位置(从0开始算)
ARGV包含命令行参数的数组
CONVFMT数字转换格式(默认值为%.6g)ENVIRON环境变量关联数组
ERRNO最后一个系统错误的描述
FIELDWIDTHS字段宽度列表(用空格键分隔)
FILENAME当前文件名
FNR各文件分别计数的行号
FS字段分隔符(默认是任何空格)
IGNORECASE如果为真,则进行忽略大小写的匹配
NF一条记录的字段的数目
NR已经读出的记录数,就是行号,从1开始
OFMT数字的输出格式(默认值是%.6g)
OFS输出字段分隔符,默认值与输入字段分隔符一致。
ORS输出记录分隔符(默认值是一个换行符)
RLENGTH由match函数所匹配的字符串的长度
RS记录分隔符(默认是一个换行符)
RSTART由match函数所匹配的字符串的第一个位置
SUBSEP数组下标分隔符(默认值是/034)

使用

使用正则,字符串匹配

# 输出第二列包含 "th",并打印第二列与第四列
$ awk '$2 ~ /th/ {print $2,$4}' log.txt
---------------------------------------------
this a
  • 表示模式开始。// 中是模式。
# 输出包含 "re" 的行
$ awk '/re/ ' log.txt
---------------------------------------------
3 Do you like awk
10 There are orange,apple,mongo
  • 忽略大小写
$ awk 'BEGIN{IGNORECASE=1} /this/' log.txt
---------------------------------------------
2 this is a test
This's a test
  • 模式取反
$ awk '$2 !~ /th/ {print $2,$4}' log.txt
---------------------------------------------
Are like
a
There orange,apple,mongo
$ awk '!/th/ {print $2,$4}' log.txt
---------------------------------------------
Are like
a
There orange,apple,mongo
  • 打印passwd文件中的第一列数据,以为分割符
[root@localhost shell-test]# awk -F":" '{print $1}' /etc/passwd

  • 显示每行的内容和行号

    [root@localhost shell-test]# awk -F: 'BEGIN{OFS="@"}/bash$/{print NR,$1,$7}' /etc/passwd
    1@root@/bin/bash
    21@bailongma@/bin/bash
    

    在 /etc/passwd 文件中查找包含 “bash” 字符串的行,并将它们的行号、用户名和默认 shell 以指定的格式输出

也可以和管道(|)连用,效果一样

[root@localhost shell-test]# cat /etc/passwd|awk -F":" '{print $1}'

打印最后一行

[root@localhost shell-test]# awk -F":" '{print $NF}' /etc/passwd
#打印最后一行

$1中过滤出含sc的第一列

[root@localhost shell-test]# awk -F":" '$1~/sc/{print $1}' /etc/passwd
  • 打印出grade.txt文件中的第三列数的和

    [root@localhost shell-test]# cat grade.txt 
    name 	chinese 	math 	english
    xiaoming	80	90	99
    lihua	89	70	99
    yang	88	80	90
    -------------------------------------------------
    [root@localhost shell-test]# awk 'NR>1{sum += $3}END{print sum}' grade.txt
    240
    

    还可以再求和前输出提示信息:

    [root@localhost shell-test]# awk 'BEGIN{print "数学总分数"}NR>1{sum += $3}END{print sum}' grade.txt
    数学总分数
    240
    

    打印数学成绩在80以上的学生姓名

    [root@localhost shell-test]#  awk 'BEGIN{print "数学总分数"}NR>1{sum += $3;if( $3>=80 ) print $1 }END{print sum}' grade.txt
    数学总分数
    xiaoming
    yang
    240
    
  • 打印出passwd用户名长度超过10的字段。

    [root@localhost shell-test]# awk -F: 'length($1)>10{print $0}' /etc/passwd
    systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
    

内置函数

在Shell中,awk是一种强大的文本处理工具,它支持使用函数对输入文本进行处理和转换。awk内置了一些常用的函数,同时也可以自定义函数来满足特定需求。下面是对awk函数的详细解释。

awk提供了一些内置函数,这些函数可以直接在awk程序中使用,无需额外定义。

一些常用的内置函数包括:

  • length(str):返回字符串str的长度。
  • substr(str, start, length):从字符串str中提取起始位置为start,长度为length的子字符串。
  • index(str, target):返回字符串str中第一次出现目标字符串target的位置。
  • split(str, array, sep):将字符串str按照分隔符sep分割成多个子字符串,并将结果存储在数组array中。
  • tolower(str):将字符串str中的大写字母转换为小写字母。
  • toupper(str):将字符串str中的小写字母转换为大写字母。
  • sprintf(format, expr1, expr2, ...):根据指定的格式字符串format,将表达式expr1expr2等转换为格式化的字符串。
  • int(expr):返回表达式expr的整数部分。
  • rand():生成一个0到1之间的随机数。
  • strftime():函数用于将时间戳转换为格式化的时间字符串。
  • systime():函数用于获取当前系统的时间戳。
  • system():函数用于执行Shell命令并返回命令的退出状态码

这只是一小部分awk的内置函数,还有其他许多函数可供使用。您可以参考awk的文档或手册以获取完整的内置函数列表。

自定义函数
除了内置函数,awk还支持定义自定义函数,以便在awk程序中使用。

自定义函数的语法如下:

function 函数名(参数列表) {
    函数体
    return 返回值
}

其中,函数名是自定义函数的名称,参数列表是函数接受的参数,函数体是函数的执行逻辑,返回值是可选的返回结果。

以下是一个示例,展示如何定义和使用自定义函数:

# 定义自定义函数
function multiply(x, y) {
    return x * y
}

# 使用自定义函数
{
    result = multiply($1, $2)
    print "结果:", result
}

上述示例定义了一个名为multiply的自定义函数,接受两个参数xy,并返回它们的乘积。在awk程序中,我们可以通过调用该函数来实现具体的计算。

split

在Shell脚本中,split是一个字符串处理函数,用于将一个字符串分割成子字符串,并将子字符串存储在一个数组中。下面是关于split函数的详细解释:

  1. 语法:
    split(string, array, separator)

    • string:要分割的字符串。
    • array:存储分割后的子字符串的数组。
    • separator:分割字符串的分隔符。可以是一个固定的字符或正则表达式。
  2. 功能:
    split函数将字符串按照指定的分隔符分割成多个子字符串,并将这些子字符串存储在数组中。分割后的子字符串可以根据索引访问,从1开始。

  3. 示例:
    下面是一个使用split函数的示例:

    str="apple,banana,orange"
    split(str, arr, ",")
    print arr[1]    # 输出 "apple"
    print arr[2]    # 输出 "banana"
    print arr[3]    # 输出 "orange"
    

    上面的示例中,str是要分割的字符串,arr是存储分割后子字符串的数组。使用逗号作为分隔符对字符串进行分割,然后可以通过索引访问数组中的元素。

  4. 分隔符:

    • 分隔符可以是一个固定的字符,例如空格、逗号、冒号等。
    • 分隔符也可以是一个正则表达式,用于更复杂的字符串分割。例如,使用空格和逗号作为分隔符:split(str, arr, "[ ,]")
  5. 返回值:
    split函数不返回任何值,它直接将分割后的子字符串存储在数组中。因此,它没有在条件语句中使用。

  6. 注意事项:

    • 如果数组已经包含元素,调用split函数会覆盖数组中的现有内容。
    • 如果分割后的子字符串数量超过数组的大小,额外的子字符串将被丢弃。

总结一下,split函数是Shell脚本中用于分割字符串的函数。它将字符串按照指定的分隔符分割成多个子字符串,并将子字符串存储在一个数组中,以便进一步处理和使用。

substr

在Shell脚本中,substr是一个用于提取字符串子串的函数。它允许你从一个字符串中选择指定位置的字符子串。下面是关于substr函数的详细解释:

  1. 语法:
    substr(string, start [, length])

    • string:要提取子串的源字符串。
    • start:子串的起始位置。如果是正数,则表示从左到右的索引;如果是负数,则表示从右到左的索引(-1表示最后一个字符)。
    • length:可选参数,表示子串的长度。如果省略,则提取从起始位置到字符串末尾的所有字符。
  2. 功能:
    substr函数用于提取字符串中的一个子串,可以根据起始位置和长度来确定提取的子串范围。

  3. 示例:
    下面是一些使用substr函数的示例:

    str="Hello, World!"
    echo $(substr(str, 1, 5))    # 输出 "Hello"
    echo $(substr(str, 8))       # 输出 "World!"
    echo $(substr(str, -6))      # 输出 "World!"
    

    上面的示例中,str是源字符串,使用substr函数从中提取了不同的子串。第一个示例提取了从索引1开始的前5个字符,第二个示例提取了从索引8开始到字符串末尾的所有字符,第三个示例提取了从右侧数第6个字符到末尾的所有字符。

    [root@localhost ~]# echo "hunan|shaoyang|dongkou|gaosha"|awk -F "|" '{print  substr($2,1,4)}'
    shao
    

    该命令的作用是对字符串"hunan|shaoyang|dongkou|gaosha"进行分割,并输出截取的第二个字段的前4个字符。

  4. 注意事项:

    • 起始位置和长度都可以是变量。
    • 如果起始位置超过了字符串的长度,substr函数将返回空字符串。
    • 如果起始位置为负数且绝对值超过了字符串的长度,substr函数将返回整个字符串。
    • 如果长度为负数,substr函数将从起始位置向前提取相应长度的子串。

总结一下,substr函数是Shell脚本中用于提取字符串子串的函数。它允许你根据起始位置和长度从一个字符串中选择指定位置的字符子串。这个函数在字符串处理和提取特定信息时非常有用。

使用

输出/etc/passwd文件中第一段字段中含有s的字符长度

[root@localhost 5-16]# awk -F: '$1 ~ /s/{print length($1)}' /etc/passwd

输出/etc/passwd文件中第二个字段长度为0的用户名,以及当前的日期

[root@localhost /]# awk -F: 'length($2) == 0 {print $1,"密码为空",strftime("%D",systime())}' /etc/passwd

将执行ls -l命令,并将命令的输出打印到标准输出。

awk '{ system("ls -l") }' file.txt

awk和grep结合使用

awk '{ status = system("grep -q pattern file.txt") } END { print "Exit status:", status }' file.txt

上面的命令将执行grep -q pattern file.txt命令,并将命令的退出状态码保存在status变量中。在END块中,它打印出命令的退出状态码。

需要注意的是,system函数返回的是命令的退出状态码,而不是命令的输出。通常,命令的退出状态码为0表示成功,非零值表示失败或错误。如果你需要获取命令的输出,可以使用管道(|)将命令的输出传递给awk,或者将命令的输出重定向到文件。

system函数中使用变量和字符串拼接来构建要执行的命令,以实现动态的命令执行。

awk -v pattern="$pattern" '{ system("grep " pattern " file.txt") }' file.txt

上面的命令中,$pattern是一个awk变量,它的值在命令执行之前被替换到命令中。

[root@localhost /]# awk -F: '{system("mkdir -p /yan/dong/sc"$1)}' /etc/passwd

该命令的作用是根据/etc/passwd文件的每一行的第一个字段,在/yan/dong路径下创建相应的子目录,并将/etc/passwd文件中的每个用户的用户名作为子目录名。

awk中的system函数用于执行命令并返回命令的退出状态码,它可以在awk脚本中实现与操作系统的交互。

awk函数的使用可以根据具体需求来选择合适的内置函数或自定义函数,以实现对文本的处理和转换操作。

awk中的if和for

当在Shell中使用awk时,if语句和for循环是非常有用的控制结构。它们允许您在awk脚本中执行条件判断和循环迭代操作。下面是对awk中if语句和for循环的超详细介绍和使用示例。

if语句

if语句允许您根据条件来执行不同的操作。

语法:

单分支

if (condition) statement

双分支

if (condition) statement1;statement2

多分支

if (条件) {
    操作
}
else if {
    操作
}
else{
	操作
}

示例:

# 根据条件判断输出结果
awk '{ if ($1 > 10) { print $1 " is greater than 10" } else { print $1 " is less than or equal to 10" } }' file.txt

在上述示例中,if语句用于判断第一个字段是否大于10,如果大于10,则输出相应的消息;否则输出另一个消息。

for循环

for循环允许您对数据进行迭代处理。

语法:

for (变量 in 数组/字符串) {
    操作
}

示例:

# 循环遍历数组元素并输出
awk 'BEGIN { fruits["apple"]="red"; fruits["banana"]="yellow"; fruits["orange"]="orange"; for (fruit in fruits) { print fruit " is " fruits[fruit] } }'

在上述示例中,for循环用于遍历数组fruits中的元素,并输出每个水果对应的颜色。

使用示例

下面是一个更完整的示例,结合了if语句和for循环,演示了如何在awk脚本中使用它们:

# 读取文件中的数字,并统计奇偶数的个数
awk '{
    if ($1 % 2 == 0) {
        even_count++
    } else {
        odd_count++
    }
}
END {
    print "Even numbers count: " even_count
    print "Odd numbers count: " odd_count
}' numbers.txt

在上述示例中,通过if语句判断每个数字是否为偶数,然后相应地增加even_countodd_count变量的计数。最后,在END块中打印统计结果。

这是一个简单的示例,但它展示了如何使用if语句和for循环在awk脚本中执行条件判断和循环迭代操作。根据实际需求,可以根据条件执行不同的操作,或对数据进行循环处理。

awk中的数组

在Shell脚本中,awk是一种功能强大的文本处理工具,它支持数组数据结构用于存储和处理数据。数组是一种有序的集合,可以通过索引来访问和操作其中的元素。下面是关于awk中数组的详细解释:

  1. 声明数组:在awk中,可以使用下面的语法来声明一个数组:

    array_name[index] = value
    

    其中,array_name是数组的名称,index是数组元素的索引(唯一),value是要存储的值。需要注意的是,awk中的数组是动态的,不需要提前指定数组的大小。

  2. 访问数组元素:可以使用下面的语法来访问数组中的元素:

    array_name[index]
    

    通过指定数组名称和索引,可以获取对应位置的元素的值。

  3. 遍历数组:可以使用for循环来遍历数组中的所有元素。下面是一个示例:

    awk 'BEGIN { array[1]="A"; array[2]="B"; array[3]="C"; for (i in array) { print array[i] } }'
    

    上面的命令将输出数组中的所有元素,即"A"、“B"和"C”。

  4. 数组长度:可以使用内置的length函数来获取数组的长度。下面是一个示例:

    awk 'BEGIN { array[1]="A"; array[2]="B"; array[3]="C"; print "Array length:", length(array) }'
    

    上面的命令将输出数组的长度,即3。

  5. 删除数组元素:可以使用delete关键字来删除数组中的元素。下面是一个示例:

    awk 'BEGIN { array[1]="A"; array[2]="B"; array[3]="C"; delete array[2]; for (i in array) { print array[i] } }'
    

    上面的命令将删除数组中索引为2的元素,并输出剩余的元素。

  6. 多维数组:awk还支持多维数组,即可以在数组的索引中使用多个值。下面是一个示例:

    awk 'BEGIN { array[1,1]="A"; array[1,2]="B"; array[2,1]="C"; for (i in array) { split(i, indices, SUBSEP); print indices[1], indices[2], array[i] } }'
    

    上面的命令定义了一个二维数组,并遍历输出所有元素及其索引。

  7. 对数组求和

    定义每个省的数据

[root@localhost /]# cat num.txt 
山东 aa 20
山东 bb 89
湖南 aa 12
湖北 aa 123
湖南 bb 143
湖北 bb 23
山西 aa 66
山西 bb 99

对同省的数据求和,同时输出每个省份的总数据

[root@localhost /]# awk '{pro[$1] += $3}END {for(i in pro) print i,pro[i]}' num.txt 
湖南 155
山西 165
山东 109
湖北 146

以上是关于awk中数组的详细解释。数组在awk中非常有用,可以用于存储和处理大量的数据,并进行各种操作,如遍历、添加、删除等。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哈密猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值