文本处理之awk基础

预定义变量

预定义变量分为两类:控制awk工作的变量和携带信息的变量。

第一类:控制AWK工作的预定义变量
RS :输入记录分隔符,默认为换行符\n ,参考RS
IGNORECASE :默认值为0,表示所有的正则匹配不忽略大小写。设置为非0值(例如1),之后的匹配将忽略
大小写。例如在BEGIN块中将其设置为1,将使FS、RS都以忽略大小写的方式分隔字段或分隔record
FS :读取记录后,划分为字段的字段分隔符。参考FS
FIELDWIDTHS :以指定宽度切割字段而非按照FS。参考FIELDWIDTHS
FPAT :以正则匹配匹配到的结果作为字段,而非按照FS划分。参考FPAT
OFS :print命令输出各字段列表时的输出字段分隔符,默认为空格" "
ORS :print命令输出数据时在尾部自动添加的记录分隔符,默认为换行符\n
CONVFMT :在awk中数值隐式转换为字符串时,将根据CONVFMT的格式按照sprintf()的方式自动转换为字
符串。默认值为"%.6g
OFMT :在print中,数值会根据OFMT的格式按照sprintf()的方式自动转换为字符串。默认值为"%.6g

第二类:携带信息的预定义变量
ARGC 和ARGV :awk命令行参数的数量、命令参数的数组。参考ARGC和ARGV
ARGIND :awk当前正在处理的文件在ARGV中的索引位置。所以,如果awk正在处理命令行参数中的某文件,
则ARGV[ARGIND] == FILENAME 为真
FILENAME :awk当前正在处理的文件(命令行中指定的文件),所以在BEGIN中该变量值为空
ENVIRON :保存了Shell的环境变量的数组。例如ENVIRON["HOME"] 将返回当前用户的家目录
NR :当前已读总记录数,多个文件从不会重置为0,所以它是一直叠加的
  可以直接修改NR,下次读取记录时将在此修改值上自增
FNR :当前正在读取文件的第几条记录,每次打开新文件会重置为0
  可以直接修改FNR,下次读取记录时将在此修改值上自增
NF :当前记录的字段数,参考NF
RT :在读取记录时真正的记录分隔符,参考RT
RLENGTH :match()函数正则匹配成功时,所匹配到的字符串长度,如果匹配失败,该变量值为-1
RSTART :match()函数匹配成功时,其首字符的索引位置,如果匹配失败,该变量值为0
SUBSEP : arr[x,y] 中下标分隔符构建成索引时对应的字符,默认值为\034 ,是一个不太可能出现在字符串中的不可打印字符。参考复杂数组

awk选项、内置变量、内置函数

选项

-e program-text
--source program-text
指定awk程序表达式,可结合-f选项同时使用
在使用了-f选项后,如果不使用-e,awk program是不会执行的,它会被当作ARGV的一个参数
-f program-file
--file program-file
从文件中读取awk源代码来执行,可指定多个-f选项
-F fs
--field-separator fs
指定输入字段分隔符(FS预定义变量也可设置)
-n
--non-decimal-data
识别文件输入中的8进制数(0开头)和16进制数(0x开头)
echo '030' | awk -n '{print $1+0}'
-o [filename]
格式化awk代码。
不指定filename时,则默认保存到awkprof.out
指定为`-`时,表示输出到标准输出
-v var=val
--assign var=val
在BEGIN之前,声明并赋值变量var,变量可在BEGIN中使用

读取文件的几种方式:

1,按字符数量读取:每一次可以读取一个字符,或者多个字符,直到把整个文件读取完
  while read -n 1 char;do echo $char;done < a.txt
2,按照分隔符进行读取:一直读取直到遇到分隔符才停止,下次继续从分隔的位置处向后读取,直到读完整个文件
  while read -d "m" chars;do echo "$chars";done < a.txt
3,按行读取:每次读取一行,直到把整个文件读完
  是按照分隔符读取的一种特殊情况:将分隔符指定为了换行符\n
  while read line;do echo "$line";done < a.txt
4,一次性读取整个文件
  是按字符数量读取的特殊情况,也是按分隔符读取的特殊情况
  read -N 10000000 data < a.txt
  read -d '_' data < a.txt
5,按字节数量读取

awk用法入门

awk 'awk_program' a.txt

1)a.txt是awk要读取的文件,可以是0个文件或一个文件,也可以多个文件

如果不给定任何文件,但又需要读取文件,则表示从标准输入中读取

2)单引号包围的是awk代码,也称为awk程序
尽量使用单引号,因为在awk中经常使用$符号,而$ 符号在shell是变量符号,如果使用双引号包围awk代码,则 符 号 会 被 s h e l l 解 析 成 s h e l l 变 量 , 然 后 进 行 s h e l l 变 量 替 换 。 使 用 单 引 号 包 围 a w k 代 码 , 则 符号会被shell解析成shell变量,然后进行shell变量替换。使用单引号包围awk代码,则 shellshellshell使awk 会脱离shell的魔掌,使得$ 符号留给了awk去解析

3)awk程序中,大量使用大括号,大括号表示代码块,代码块中间可以之间连用,代码内部的多个语句需使用分号“;” 分隔。

awk '{print $0}' a.txt
awk '{print $0}{print $0;print $0}' a.txt

BEGIN和END语句块

awk 'BEGIN{print "我在前面"}{print $0}' a.txt
awk 'END{print "我在后面"}{print $0}' a.txt
awk 'BEGIN{print "我在前面"}{print $0}END{print "我在后面"}' a.txt

BEGIN代码块:

在读取文件之前执行,且执行一次
在BEGIN代码块中,无法使用$0或其他一些特殊变量

END代码块:

在读取文件完成之后执行,且执行一次
有END代码块,必有要读取的数据(可以是标准输入)
END代码块中可以使用$0等一些特殊变量,只不过这些特殊变量保存的是最后一轮awk循环的数据

main代码块:

读取文件时循环执行,(默认情况)每读取一行,就执行一次main代码块
main代码块可有多个

awk命令行结构和语法结构

在shell命令行当中,双短横线–表示选项到此结束,后面的都是命令的参数

awk [ -- ] program-text file ...
awk -f program-file [ -- ] file ...
awk -e program-text [ -- ] file ...

cmd -x -r root -ppassword a.txt b.txt c.txt
  1,选项分为长选项和短选项
  2,选项分为3种:
    1)不带参数的选项
    2)是带参数的选项,如果该选项后面没有给参数,则报错
    3)参数可选的选项,选项后面可以跟参数,也可以不跟参数
      参数可选选项,如果要接参数,则必须将参数紧紧跟在选项后面,不能使用空格分隔选项和参数
  3,两种参数:
    1)选项型参数
    2)非选项型参数

范例:awk的语法充斥着pattern{action}的模式,它们称为awk rule:awk语句块可划分如下

awk 'BEGIN{n=3} /^[0-9]/$1>5{$1=333;print $1}  /Alice/{print "Alice"} END{print "hello"}' a.txt
1)pattern部分用于测试筛选数据,action表示在测试通过后执行的操作
2)pattern和action都可以省略
  省略pattern,等价于对每个一行数据都执行action
    awk '{print $0}' a.txt
  省略代码块{action},等价于{print}即输出所有行
    awk '/Alice/' a.txt 等价于 awk '/Alice/{print $0}' a.txt
  省略代码块中的action,表示对筛选的行什么都不做
    awk '/Alice/{}' a.txt
  parttern{action}任何一部分都可以省略
    awk '' a.txt
  多个pattern{action}可以直接连接连用
  action中多个语句连用需使用分号分隔

pattern和action

对于pattern{action}语句结构(都称之为语句块),其中的pattern部分可以使用下面列出的模式

# 特殊pattern
BEGIN
END

# 布尔代码块
/regulat expression/    # 正则匹配成功与否/a.*ef/{action}
relational expression   # 即等值比较,大小比较 3>2{action}
pattern && pattern      # 逻辑与3>2 && 3>1 {action}
pattern || pattern      # 逻辑或 3>2 || 3<1 {action}
! pattern               # 逻辑取反 !/a.*ef/{action}
(pattern)               # 改变优先级
pattern ? pattern : pattern  # 三目运算符决定的布尔值
# 范围pattern,非布尔代码块
pattern1,pattern2      # 范围,pat1打开,pat2关闭,即flip,flop模式

action部分,可以是任何语句,例如print语句。

awk读取文件

详细分析awk如何读取文件

awk读取输入文件时,每次读取一条记录(record)(默认情况下按行读取,所以此时记录就是行)。每读取一条记录,将其保存到 $0中,然后执行一次main代码段

awk '{print $0}' a.txt

如果是空文件,则因为无法读取到任何一条记录,将导致直接关闭文件,而不会进入main代码段。

touch x.log   # 创建一个空文件
awk '{print "holle word"}' x.log

可设置表示输入记录分隔符的预定义变量RS(Record Separator)来改变每次读取的记录模式。

# RS="\n" , RS="m"
awk 'BEGIN{RS="\n"}{print $0}' a.txt
awk 'BEGIN{RS="m"}{print $0}' a.txt

RS通常设置在BEGIN代码块中,因为要先于读取文件就确定好RS分隔符

RS指定输入记录分隔符时,所读取的记录中是不包含分隔符字符的。例如RS="a",则$0 中一定不可能出现字符a。

RS两种可能情况:

RS为单个字符:直接使用该字符来分割记录
RS为多个字符:将其当做正则表达式,只要匹配正则表达式的符号,都用来分割记录
  设置预定义变量IGNORECASE为非零值,正则匹配时表示忽略大小写
  兼容模式下,只有首字符才生效,不会使用正则模式去分割记录

特殊的RS值用来解决特殊读取需求:

RS="":按段落读取
RS="\0":一次性读取所有数据,但有些特殊文件中包含了空字符\0
RS="^$":真正的一次性读取所有数据,因为非空文件不可能匹配成功
RS="\n+":按行读取,但忽略所有空行
按段落读取:RS=''
awk 'BEGIN{RS=''}{print $0"------""}' a.txt

#一次性读取所有数据:RS='\0' RS="^$"
awk 'BEGIN{RS='\0'}{print $0"------""}' a.txt
awk 'BEGIN{RS='^$'}{print $0"------"}' a.txt

# 忽略空行:RS='\n+'
awk 'BEGIN{RS='\n+'}{print $0"------""}' a.txt

# 忽略大小写:预定义变量IGNORECASE设置为非0值
awk 'BEGIN{IGNORECASE=1}{print $0"------"}' RS='[ab]' a.txt
预定义变量RT:
在awk每次读完一条记录时,会设置一个称为RT的预定义变量,表示Record Termination。
当RS为单个字符时,RT的值和RS的值是相同的。
当RS为多个字符(正则表达式)时,则RT设置为正则匹配到记录分隔符之后,真正用于划分记录时的字符。
当无法匹配到记录分隔符时,RT设置为控制空字符串(即默认的初始值)。
awk 'BEGIN{RS="(fe)?male"}{print RT}' a.txt

两种行号:NR和FNR

在读取每条记录之后,将其赋值给$0,同时还会设置NR,FNR,RT。

NR:所有文件的行号计数器
FNR:是各个文件的行号计数器

awk '{print NR}' a.txt b.txt
awk '{print FNR}' a.txt b.txt

详细分析字段分割

awk读取每一条记录之后,会将其赋值给$0,同时还会对这条记录按照预定义变量 FS划分字段,将划分好的各个字段分别赋值给$1,$2, 3... 3... 3...n,同时将划分的字段数量赋值给预定义变量NF

引用字段的方式

$N 引用字段:

  N=0:即$0,引用记录本身
  0NF:表示引用不存在的字段,返回空字符串
  N<0:报错

可使用变量或计算的方式指定要获取的字段序号。

awk '{n = 5;print $n}' a.txt
awk '{print $(2+2)}' a.txt    # 括号必不可少,用于改变优先级
awk '{print $(NF-3)}' a.txt
分割字段的方式

读取record之后,将使用预定义变量 FS,FILEDWIDTHHS或FPAT中的一种来分割字段。分割完成之后,再进入main代码段(所以,在main中设置FS对本次已经读取的record是没有影响的,但会影响下次读取)

FS或 -F

FS 或者 -F:字段分隔符
  Fs为单个字符时,该字符即为字段分隔符
  FS为多个字符时,则采用正则表达式模式作为字段分隔符
  特殊的,也是FS默认的情况,FS为单个空格时,将以连续的空白(空格,制表符,换行符)作为字段分隔符
  特殊的,FS为空字符串""时,将对每个字符都进行分隔,即每个字符都作为一个字段
  设置预定义变量IGNORECASE为非零值,正则匹配时表示忽略大小写(只影响正则,所以FS为单字时无影响)
  如果record中无法找到FS指定的分隔符(例如将FS设置为"\n"),则整个记录作为一个字段,即$1 和$0 相等。

范例:
面试题:取出分区利用率

[20:41:33 root@Bj-Ubuntu ~]# df | awk '{print $1,$5}'
Filesystem Use%
udev 0%
tmpfs 6%
/dev/sda2 14%
tmpfs 0%
tmpfs 0%
tmpfs 0%
/dev/loop0 100%
/dev/loop1 100%
/dev/sda3 1%
tmpfs 0%
[20:42:06 root@Bj-Ubuntu ~]# df | awk -F"[[:space:]]+|%" '{print $5}'
Use
0
6
14
0
0
0
100
100
1
0

[root@longwang ~]# df | awk -F"[ %]+" '{print $5}'
Use
0
0
10
0
10
1
16
0
[root@longwang ~]# df | awk -F"[ %]+" '{print $1,$5}'
Filesystem Use
devtmpfs 0
tmpfs 0
tmpfs 10
tmpfs 0
/dev/mapper/cl-root 10
/dev/mapper/cl-data 1
/dev/sda1 16
tmpfs 0

范例

[root@VM_0_10_centos ~]# awk -F'[[ ]' '{print $1,$5}'
/apps/nginx/logs/nginx.access.log | head -n3
58.87.87.99 09/Jun/2020:03:42:43
128.14.209.154 09/Jun/2020:03:42:43
64.90.40.100 09/Jun/2020:03:43:11

取ip地址centos6

[06:47:47 root@centos6 ~]# ip a |awk -F"[ /]+" '/inet / && !/127/{print $3}'
172.31.0.10

ubuntu

[20:43:38 root@Bj-Ubuntu ~]# ip a |awk -F"[ /]+" '/inet / && !/127/{print $3}'
172.31.0.19

centos8

[root@longwang ~]# ip a | awk -F"[ /]+" '/inet / && !/127/{print $3}'
172.31.0.38

面试题:文件host_list.log 如下格式,请提取”.magedu.com”前面的主机名部分并写入到回到该文件中

[root@longwang ~]# cat host_list.log 
1 www.magedu.com
2 blog.magedu.com
3 study.magedu.com
4 linux.magedu.com
5 python.magedu.com
[root@longwang ~]# awk -F"[ .]" '{print $2}' host_list.log 
www
blog
study
linux
python
[root@longwang ~]# awk -F"[ .]" '{print $2}' host_list.log >> host_list.log 
[root@longwang ~]# cat host_list.log 
1 www.magedu.com
2 blog.magedu.com
3 study.magedu.com
4 linux.magedu.com
5 python.magedu.com
www
blog
study
linux
python

常见的内置变量

FS:输入字段分隔符,默认为空白字符,功能相当于 -F

范例

[root@longwang ~]# awk -v FS=':' '{print $1,FS,$3}' /etc/passwd
root : 0
bin : 1
daemon : 2
adm : 3

[root@longwang ~]# awk -v FS=":" '{print $1FS$3}' /etc/passwd
root:0
bin:1
daemon:2
[root@longwang ~]# awk -F: '{print $1,$3,$7}' /etc/passwd
root 0 /bin/bash
bin 1 /sbin/nologin
daemon 2 /sbin/nologin

[root@longwang ~]# S=;awk -v FS=$S '{print $1FS$3}' /etc/passwd
ro
bn
de
am

[root@longwang ~]# awk -v FS=":" '{print $1FS$3}' /etc/passwd | head -n3
root:0
bin:1
daemon:2
[root@longwang ~]# S=:;awk -F$S '{print $1,$3}' /etc/passwd | head -n3
root 0
bin 1
daemon 2
#-F 和 FS变量功能一样,同时使用会冲突
[root@longwang ~]# awk -v FS=":" -F";" '{print $1FS$3}' /etc/passwd | head -n3
root:x:0:0:root:/root:/bin/bash;
bin:x:1:1:bin:/bin:/sbin/nologin;
daemon:x:2:2:daemon:/sbin:/sbin/nologin;
[root@longwang ~]# awk -F";" -v FS=":" '{print $1FS$3}' /etc/passwd | head -n3
root:0
bin:1
daemon:2
#-F 和 FS变量功能一样,同时使用会 -F 优先级高
[root@longwang ~]# awk -v FS=":" -F";" '{print $1}' /etc/passwd | head -n3
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
[root@longwang ~]# awk -v FS=";" -F":" '{print $1}' /etc/passwd | head -n3
root
bin
daemon

OFS:输出字段分隔符,默认为空白字符

[root@longwang ~]# awk -v FS=':' '{print $1,$3,$7}' /etc/passwd | head -n1
root 0 /bin/bash
[root@longwang ~]# awk -v FS=":" -v OFS=':' '{print $1,$3,$7}' /etc/passwd | head -n1
root:0:/bin/bash

RS:输入记录record分隔符,指定输入时的换行符

[root@longwang ~]# awk -v RS=' ' '{print }' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP
User:/var/ftp:/sbin/nologin
nobody:x:65534:65534:Kernel
Overflow

ORS:输出记录分隔符,输出时用指定符号代替换行符

[root@longwang ~]# awk -v RS=' ' -v ORS='###' '{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin

NF:字段数量

#引用变量时,变量前不需加$
[root@longwang ~]# awk -F: '{print NF}' /etc/passwd
7
7
[root@longwang ~]# awk -F: '{print $(NF-1)}' /etc/passwd
/root
/bin
/sbin

面试题:接数最多的前3个IP

172.20.65.65 - - [24/May/2018:10:13:20 +0800] "GET /centos/6/Packages/python-iwlib-0.1-1.2.el6.x86_64.rpm HTTP/1.1" 200 14724 "-" "CentOS (anaconda)/6.9"
172.20.65.65 - - [24/May/2018:10:13:20 +0800] "GET /centos/6/Packages/hplip-common-3.14.6-4.el6.1.x86_64.rpm HTTP/1.1" 200 81384 "-" "CentOS (anaconda)/6.9"
172.20.65.65 - - [24/May/2018:10:13:20 +0800] "GET /centos/6/Packages/sane-backends-libs-gphoto2-1.0.21-5.el6.x86_64.^C
[root@longwang ~]# awk -F" +|:" '{print $1}' access_log | sort | uniq -c | sort -nr | head -n3
   4870 172.20.116.228
   3429 172.20.116.208
   2834 172.20.0.222
  
[root@iZwz98 ~]# ss -tn
State       Recv-Q Send-Q Local Address:Port                Peer Address:Port              
ESTAB       0      52     172.18.106.169:8222               114.246.99.151:51006              
ESTAB       0      0      172.18.106.169:44128              100.100.30.26:80                 
ESTAB       0      0      172.18.106.169:8222               118.126.89.216:50034              
[root@iZwz98 ~]# ss -tn | grep "^ESTAB" | awk -F"[[:space:]]+|:" '{print $(NF-2)}'
114.246.99.151
100.100.30.26
[root@iZwz98 ~]# ss -tn | awk -F"[[:space:]]+|:" '/^ESTAB/{print $(NF-2)}'
114.246.99.151
100.100.30.26
58.33.35.82

范例:每十分钟检查将连接数超过100个以上的IP放入黑名单拒绝访问

[root@iZwz98 ~]# vim deny_dos.sh
#!/bin/bash
LINK=100
while true;do
    ss -tn | awk -F"[[:space:]]+|:" '/^ESTAB/{print $(NF-2)}' |sort  | uniq -c | while read count ip ;do
        if [ $count -gt $LINK ];then
            iptables -A INPUT -s $ip -j REJECT
        fi
    done
done

[root@iZwz98 ~]# chmod +x deny_dos.sh 
[root@iZwz98 ~]# crontab -e
[root@iZwz98 ~]# crontab -l
*/10 * * * * /root/deny_dos.sh

NR:记录的编号

[root@longwang ~]# awk '{print NR,$0}' /etc/issue /etc/centos-release
1 \S
2 Kernel \r on an \m
3 
4 CentOS Linux release 8.1.1911 (Core) 

范例:取ifconfig输出结果中的IP地址

[root@CentOS-8 ~]# ifconfig eth0 | awk '/netmask/{print $2}'
172.31.0.20
[root@CentOS-8 ~]# ifconfig eth0 | awk 'NR==2{print $2}'
172.31.0.20

范例:

[root@CentOS-8 ~]# awk -F: '{print NR}' /etc/passwd
1
2
3
...
45
[root@CentOS-8 ~]# awk -F: 'END{print NR}' /etc/passwd
45
[root@CentOS-8 ~]# awk -F: 'BEGIN{print NR}' /etc/passwd
0

FNR:各文件分别计数,记录的编号

[root@CentOS-8 ~]# awk  '{print FNR}' /etc/fstab /etc/inittab
1
2
3
4
5
6
7
8
9
10
11
12
13
14
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@CentOS-8 ~]# awk '{print NR,$0}' /etc/issue /etc/redhat-release 
1 \S
2 Kernel \r on an \m
3 
4 CentOS Linux release 8.1.1911 (Core)
[root@CentOS-8 ~]# awk  '{print FNR,$0}' /etc/issue /etc/redhat-release 
1 \S
2 Kernel \r on an \m
3 
1 CentOS Linux release 8.1.1911 (Core)

FILENAME:当前文件名

[root@CentOS-8 ~]# awk '{print FILENAME}' /etc/fstab 
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
[root@CentOS-8 ~]# awk '{print FNR,FILENAME,$0}' /etc/issue /etc/redhat-release 
1 /etc/issue \S
2 /etc/issue Kernel \r on an \m
3 /etc/issue 
1 /etc/redhat-release CentOS Linux release 8.1.1911 (Core)

ARGC:命令行参数的个数

[root@CentOS-8 ~]# awk '{print ARGC}' /etc/issue /etc/redhat-release 
3
3
3
3
[root@CentOS-8 ~]# awk 'BEGIN{print ARGC}' /etc/issue /etc/redhat-release 
3

ARGV:数组,保存的是命令行所给定的各参数,每一个参数:ARGV[0],…

[root@CentOS-8 ~]# awk 'BEGIN{print ARGV[0]}' /etc/issue /etc/redhat-release 
awk
[root@CentOS-8 ~]# awk 'BEGIN{print ARGV[1]}' /etc/issue /etc/redhat-release 
/etc/issue
[root@CentOS-8 ~]# awk 'BEGIN{print ARGV[2]}' /etc/issue /etc/redhat-release 
/etc/redhat-release
[root@CentOS-8 ~]# awk 'BEGIN{print ARGV[3]}' /etc/issue /etc/redhat-release 

自定义变量

自定义变量是区分字符大小写的,使用下面方式进行赋值

-v var=value
在program中直接定义

范例:

[root@CentOS-8 ~]# awk -v test1=test2="hello,gawk" 'BEGIN{print test1,test2}'
test2=hello,gawk
[root@C[root@CentOS-8 ~]# awk -v test1=test2="hello,gawk" 'BEGIN{test1=test2="hello,gawk";print test1,test2}'
hello,gawk hello,gawkentOS-8 ~]# awk -v test1=test2="hello,gawk" 'BEGIN{test1=test2="hello,gawk";print test1,test2}'
hello,gawk hello,gawk
[root@CentOS-8 ~]# awk -v test1=test2="hello,gawk" 'BEGIN{test1=test2="hello,gawk";print test1,test2}'
hello,gawk hello,gawk

范例:

[root@CentOS-8 ~]# awk -v test='hello gawk' '{print test}' /etc/fstab
[root@CentOS-8 ~]# awk -v test='hello gawk' 'BEGIN{print test}'
[root@CentOS-8 ~]# awk 'BEGIN{test="hello,gawk";print test}'
[root@CentOS-8 ~]# awk -F: '{sex="male";print $1,sex,age;age=18}' /etc/passwd
[root@CentOS-8 ~]# cat awkscript
{print script,$1,$2}
[root@CentOS-8 ~]# awk -F: -f awkscript script="awk" /etc/passwd

BEGIN/END模式

BEGIN{}:仅在开始处理文件中的文本之前执行一次

END{}:仅在文本处理完成之后执行一次

动作 printf

printf 可以实现格式化输出

printf “FORMAT”, item1, item2, ...

说明:
必须指定FORMAT

不会自动换行,需要显式给出换行控制符 \n

FORMAT中需要分别为后面每个item指定格式符

格式符:与item一一对应

%s:显示字符串
%d, %i:显示十进制整数
%f:显示为浮点数
%e, %E:显示科学计数法数值
%c:显示字符的ASCII码
%g, %G:以科学计数法或浮点形式显示数值
%u:无符号整数
%%:显示%自身

修饰符

#[.#] 第一个数字控制显示的宽度;第二个#表示小数点后精度,如:%3.1f
- 左对齐(默认右对齐) 如:%-15s
+ 显示数值的正负符号 如:%+d

范例:

awk -F: '{printf "%s",$1}' /etc/passwd
awk -F: '{printf "%s\n",$1}' /etc/passwd
awk -F: '{printf "%20s\n",$1}' /etc/passwd
awk -F: '{printf "%-20s\n",$1}' /etc/passwd
awk -F: '{printf "%-20s %10d\n",$1,$3}' /etc/passwd
awk -F: '{printf "Username: %s\n",$1}' /etc/passwd
awk -F: '{printf “Username: %sUID:%d\n",$1,$3}' /etc/passwd
awk -F: '{printf "Username: %25sUID:%d\n",$1,$3}' /etc/passwd
awk -F: '{printf "Username: %-25sUID:%d\n",$1,$3}' /etc/passwd

你可能感兴趣的:(linux之文本处理三剑客,linux,awk)