shell,awk编辑器的使用方法
gawk编辑器使用格式:
gawk options program file
-F 指定分隔符
-f 指定文件中读取程序
-v var-value 定义一个变量及其默认值
-mf 指定最大字段数 max field
-mr 指定最大数据行 max record,可以用'NR<10{print $1}'代替
-W 指定兼容模式或警告等级
program的语法格式 '{language}'
例:
gawk '{print "hello world"}'
注意:程序会等待你的输入,但是输出都是hello world,使用Ctrl+D结束
一、基本使用
使用数据字段变量:
$1 $2 $3 分别代表第一二三个数据字段,$0 代表一整行数据,分隔符为空格或制表符,使用-F可以指定分割符
例1:
cat data.txt The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. gawk '{print $1 $2}' data.txt Thequick Thequick
例2:
gawk -F: '{print $1 $2}' /etc/passwd
在程序脚本中使用多个命令:
用分号分割,如:'{one; two; three}'
例:
echo "My name is Rich" | gawk '{$4="Christine"; prinrt $0}'
My name is Christine
先给$4赋值,然后将整行文本输出,输出时第四个字段替换成了新值
从文件中读取程序:
cat script.gawk { text = "'s home directory is " print $1 text $6 } gawk -F: -f script.gawk /etc/passwd
BEGIN、END的使用:
BEGIN 读取数据之前执行一段脚本
END 处理完数据之后执行一段脚本
例:
gawk 'BEGIN{ print "This is Title" } { print $0 } END{ print "This is end"}' demo.txt
This is Title #先输出了标题
The quick brown fox jumps over the lazy dog.
This is end #最后输出页脚
注意:几个脚本要在引号之内
二、使用变量
内置变量:
gawk数据字段和记录变量
FILEWIDTHS 定义每个数据字段的确切宽度,由空格分割的一列数字
FS 输入字段分格符,默认空格
OFS 输出字段分格符,默认空格
RS 输入记录分隔符,默认一行为一条记录
ORS 输出记录分格符
FS:指定字段分隔符,-F优先级高于FS,不建议混用
]# awk -v FS=':' '{print $1,$3}' /etc/passwd root 0 bin 1 daemon 2 adm 3 lp 4 sync 5 shutdown 6 halt 7 mail 8 operator 11 games 12 ftp 14 nobody 99 systemd-network 192 dbus 81 polkitd 999 libstoragemgmt 998 abrt 173 rpc 32 sshd 74 postfix 89 chrony 997 ntp 38
引用FS变量:
]# awk -v FS=':' '{print $1FS$3}' /etc/passwd root:0 bin:1 daemon:2 adm:3 lp:4 sync:5 shutdown:6 halt:7 mail:8 operator:11 games:12 ftp:14 nobody:99 systemd-network:192 dbus:81 polkitd:999 libstoragemgmt:998 abrt:173 rpc:32 sshd:74 postfix:89 chrony:997 ntp:38
OFS(output field string):输出字段分隔符
]# awk -v FS=':' -v OFS='=' '{print $1,$3}' /etc/passwd root=0 bin=1 daemon=2 adm=3 lp=4 sync=5 shutdown=6 halt=7 mail=8 operator=11 games=12 ftp=14 nobody=99 systemd-network=192 dbus=81 polkitd=999 libstoragemgmt=998 abrt=173 rpc=32 sshd=74 postfix=89 chrony=997 ntp=38
FIELDWIDTHS:字段分割长度,定义字段宽度,并依此分割字符串。
cat data.txt 21.2133.34.55.555 43.4433.55564.2.6 gawk 'BEGIN{FIELDWIDTHS="1 4 4 3"}{print $1,$2,$3,$4}' test.txt 2 1.21 33.3 4.5 4 3.44 33.5 556
RS(record string):行分隔符,一般结尾都是换行符作为换行符,但是可以用RS指定换行符
]# echo {a..z} a b c d e f g h i j k l m n o p q r s t u v w x y z [root@k8stest-01 ~]# [root@k8stest-01 ~]# [root@k8stest-01 ~]# [root@k8stest-01 ~]# echo {a..z} | awk -v RS=' ' '{print $0}' a b c d e f g h i j k l m n o p q r s t u v w x y z
例2:
cat data.txt Riley 123-456-789 Frank 234-567-890 gawk 'BEGIN{FS="\n"; RS=""} {print $1,$2}' data.txt
输入记录分隔符RS设置为一个空行为一条记录:RS="",字段分隔符设置为换行FS="\n"
处理结果如下:
Riley 123-456-789 Frank 234-567-890
ORS:输出换行分隔符
]# echo {a..z} | awk -v RS=' ' -v ORS='=' '{print $0}' a=b=c=d=e=f=g=h=i=j=k=l=m=n=o=p=q=r=s=t=u=v=w=x=y=z
数据变量:更多的awk内建变量
ARGC 当前命令行参数个数
ARGIND 当前文件在ARGV中的位置
ARGV 包含命令行参数的数组
COMVFMT 数字的转换格式,同printf,默认值%.6 g
ENVIRON 当前环境变量和值组成的关联数组
ERRON 读取或关闭输入文件的错误号
FILENAME 输入数据文件的文件名,要处理文件的文件名
IGNORECASE 值为非零时,忽略命令中字符串的大小写
NF 数据文件中的字段总数 number field,一共有多少个字段
NR 已近处理的输入记录数 number record,当前处理的行号
FNR 当前数据文件的数据行 file number record,多个文件情况下每个文件单独统计行号
OFMT 数字的输出格式,默认值为%.6 g
RLENGTH 由match函数所匹配的子字符串长度
RSTART 由match函数所匹配的子字符串的起始位置
输出环境变量ENVIRON:
例:
gawk 'BEGIN{ print ENVIRON["HOME"] #读取环境变量中的HOME环境变量 print ENVIRON["PATH"] #读取环境变量中的PATH环境变量 }'
NF:列数,一共有多少列
]# awk -v FS=":" '{print NF}' /etc/passwd 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 [root@k8stest-01 ~]# awk -v FS=":" '{print $NF}' /etc/passwd /bin/bash /sbin/nologin /sbin/nologin /sbin/nologin /sbin/nologin /bin/sync /sbin/shutdown /sbin/halt /sbin/nologin /sbin/nologin /sbin/nologin /sbin/nologin /sbin/nologin /sbin/nologin /sbin/nologin /sbin/nologin /sbin/nologin /sbin/nologin /sbin/nologin /sbin/nologin /sbin/nologin /sbin/nologin /sbin/nologin /sbin/nologin /sbin/nologin /sbin/nologin
取列值:
]# df -h | awk -F'[ %]+' '{print $(NF-1)}' 已用 0 0 12 0 5 30 0
NR:标记行号
]# awk -F: '{print NR,$1}' /etc/passwd 1 root 2 bin 3 daemon 4 adm 5 lp 6 sync 7 shutdown 8 halt 9 mail 10 operator 11 games 12 ftp 13 nobody 14 systemd-network 15 dbus 16 polkitd 17 libstoragemgmt 18 abrt 19 rpc 20 sshd 21 postfix 22 chrony 23 ntp 24 tcpdump
NR:取IP值
]# ifconfig eth0 | awk 'NR==2{print $2}' 192.168.199.15
NR:记录处理过的所有行的行数
]# awk '{print NR,FILENAME}' /etc/issue /etc/os-release 1 /etc/issue 2 /etc/issue 3 /etc/issue 4 /etc/os-release 5 /etc/os-release 6 /etc/os-release 7 /etc/os-release 8 /etc/os-release 9 /etc/os-release 10 /etc/os-release 11 /etc/os-release 12 /etc/os-release 13 /etc/os-release 14 /etc/os-release 15 /etc/os-release 16 /etc/os-release 17 /etc/os-release 18 /etc/os-release 19 /etc/os-release
FNR:每处理一个文件就重新计数
]# awk '{print FNR,FILENAME}' /etc/issue /etc/os-release 1 /etc/issue 2 /etc/issue 3 /etc/issue 1 /etc/os-release 2 /etc/os-release 3 /etc/os-release 4 /etc/os-release 5 /etc/os-release 6 /etc/os-release 7 /etc/os-release 8 /etc/os-release 9 /etc/os-release 10 /etc/os-release 11 /etc/os-release 12 /etc/os-release 13 /etc/os-release 14 /etc/os-release 15 /etc/os-release 16 /etc/os-release
ARGC:当前命令行参数个数
]# awk '{print ARGC}' /etc/issue /etc/redhat-release 3 3 3 3
ARGV:包含命令行参数的数组
]# awk '{print ARGV[0]}' /etc/issue /etc/redhat-release awk awk awk awk ~]# awk '{print ARGV[1]}' /etc/issue /etc/redhat-release /etc/issue /etc/issue /etc/issue /etc/issue ~]# awk '{print ARGV[2]}' /etc/issue /etc/redhat-release /etc/redhat-release /etc/redhat-release /etc/redhat-release /etc/redhat-release
printf格式化输出:
%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
示例:
]# awk -F: '{printf "%s",$1}' /etc/passwd rootbindaemonadmlpsyncshutdownhaltmailoperatorgamesftpnobodysystemd-networkdbuspolkitdlibstoragemgmtabrtrpcsshdpostfixchronyntptcpdumpnginx[root@nginx ~]# [root@nginx ~]# [root@nginx ~]# [root@nginx ~]# awk -F: '{printf "%s\n",$1}' /etc/passwd root bin daemon adm lp sync shutdown halt mail operator games ftp nobody systemd-network dbus polkitd libstoragemgmt abrt rpc sshd postfix chrony ntp tcpdump
示例:
]# awk -F: '{printf "%20s\n",$1}' /etc/passwd root bin daemon adm lp sync shutdown halt mail operator games ftp nobody systemd-network dbus polkitd libstoragemgmt abrt rpc sshd postfix chrony ntp
示例:
]# awk -F: '{printf "%-20s %-10d\n",$1,$3}' /etc/passwd root 0 bin 1 daemon 2 adm 3 lp 4 sync 5 shutdown 6 halt 7 mail 8 operator 11 games 12 ftp 14 nobody 99 systemd-network 192 dbus 81 polkitd 999 libstoragemgmt 998 abrt 173 rpc 32 sshd 74 postfix 89 chrony 997 ntp 38
打印表头:
]# awk -F: 'BEGIN{print "USER UID \n---------------------------"}{print $1,$3}' /etc/passwd USER UID --------------------------- root 0 bin 1 daemon 2 adm 3 lp 4 sync 5 shutdown 6 halt 7 mail 8 operator 11 games 12 ftp 14 nobody 99 systemd-network 192 dbus 81 polkitd 999 sshd 74 postfix 89 chrony 998
打印表格:
]# awk -F: 'BEGIN{printf "--------------------------------\n%-20s|%10s|\n--------------------------------\n","username","uid"} {printf "%-20s|%10d|\n--------------------------------\n",$1,$3} END{print "finished"}' /etc/passwd -------------------------------- username | uid| -------------------------------- root | 0| -------------------------------- bin | 1| -------------------------------- daemon | 2| -------------------------------- adm | 3| -------------------------------- lp | 4| -------------------------------- sync | 5| -------------------------------- shutdown | 6| -------------------------------- halt | 7| -------------------------------- mail | 8| -------------------------------- operator | 11| -------------------------------- games | 12| -------------------------------- ftp | 14| -------------------------------- finished
使用正则:
]# ifconfig eth0 | awk '/netmask/{print $2}' 192.168.199.15
取区间值:
]# seq 10 | awk 'NR>=5 && NR<=8' 5 6 7 8
取某个字符开头到某个字符结尾区间的值:
]# awk '/^b/,/^s/' /etc/passwd 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
自定义变量:
赋值:
gawk 'BEGIN{ test = "This is a test" print test }'
运算:
gawk 'BEGIN{x = 4; x = x * 4; print x}' #在BEGIN里面的变量不用$符号
gawk编辑器包含了标准的算术运算符
在命令行上给变量赋值:
例1:
cat script.gawk BEGIN{FS=" "} {print $n} gawk -f script.gawk n=2 data.txt #在命令行上直接给脚本中的变量赋值
处理结果,输出了第二列:
xxx2 xxx2 xxx2
命令行赋值在BEGIN部分变量不可用,-v参数可以解决这个问题。
例2:使用-v参数
cat script.gawk
BEGIN{ print "The value is ",n ; FS=" "}{print $n}
gawk -v n=2 -f script.gawk test.txt # 使用-v方法赋值要提前
处理结果:
The value is 2 xxx2 xxx2 xxx2
定义数组变量:
gawk只有关联数组
例:
gawk 'BEGIN{ test[a]="this is a test" ; print test[a] ; }' this is a test
数组可以直接参与运算:
gawk 'BEGIN{ test[1] = 12 ; test[2] = 3 ; print value = test[1] + test[2]; }' 15
遍历数组:
gawk 'BEGIN{ test["a"] = 1 test["b"] = 2 for(val in test){ print "The value is ",test[val] } }' The value is 1 The value is 2
删除数组命令:
delete array[index] 删除数组元素
gawk 'BEGIN{ test["a"] = 1 ; test["b"] = 2 ; for (key in test){ print "The value is ",test[key] ; } delete test["b"] ; for ( key in test){ print test[key] ; } }' The value is 1 The value is 2 1
三、表达式
使用模式:和BEGIN、END关键字一样,/hello/也是一种模式。
正则表达式:
gawk 'BEGIN{FS=","} /hello/{print $0}' data.txt #会匹配含有hello的行
匹配操作符:
$1 ~ /^data/ 第一个字段是以data开头的记录。$1表示第一个数据字段,/^data/表示以data开头的记录
例:
gawk 'BEGIN{FS=","} $1 ~ /^xxx/{print $0}' test.txt
ccc1,xxx2,xxx3,xxx4
排除表达式:
$1 !~ /expression/ 除了这个表达式之外的全部
gawk -F: '$1 !~ /root/{print $1,$NF}' /etc/passwd
除了第一个字段为root的记录之外的全部打印出第一字段和最后一个字段。
处理结果:
bin /sbin/nologin daemon /sbin/nologin adm /sbin/nologin lp /sbin/nologin
数学表达式:
例 :
gawk -F: '$4 == 0{ print $1 }' /etc/passwd #这个例子显示了属于root组的用户
可用的表达式有:== <= >= < >
也可以用字符串比较:
gawk -F, '$1 == "data"{ print $1 }' data.txt
四:结构化命令
if语句:
gawk '{ if ($1 > 20 ) print $1}' data.txt
长格式:
gawk '{ if ($1 > 20){ print $1 }else{ print $2 } }'
缩成一行:
gawk '{ if () print $1 ; else print $2 }' data.txt
while语句:
gawk '{ i = 0 while ( i < 4 ){ i++ } print "the value is ",i }'
do-while语句:
gawk '{ x = 0; do{ x++; }while( x < 20 ); print $x ; }'
for语句:
gawk '{ for(i = 0 ; i < 10 ; i++){ print i ; } }'
格式化输出:
格式化指定符的控制字母:
c 将一个数作为ASCII字符显示
d 显示一个整数值
i 同d
e 科学计数法显示一个数
f 显示一个浮点值
g 用科学计数法或浮点数显示(选择较短的格式)
o 显示一个八进制值
s 显示文本字符串
x 显示一个十六进制值
X 显示一个十六进制值,但用大写字母A-F
例:
printf "%16s %s\n" , $1 , $4 printf "%-16 %s\n" , $1 , $4 #“-”表示左对齐
五、函数
数学函数:
atan2(x, y) x/y的反正切,x和y以弧度为单位
cos(x) x的余弦,x以弧度为单位
exp(x) x的指数函数
int(x) x的整数部分,取整
log(x) x的自然对数
rand() 0到1之间的随机数
sin(x) x的正弦,x以弧度为单位
sqrt(x) x的平方根
srand(x) 为计算随机数指定一个种子值
位运算函数:
and(v1, v2) 位与运算
compl(val) val的补运算
lshift(val, count) 将值val左移count位
or(v1, v2) 位或运算
rshift(val, count) 右移count位
xor(v1, v2) v1和v2的按位异或运算
字符串运算:
asort(s, [d]) 排序
asorti(s, [d]) 排序
gensub(r, s, h, [t]) 匹配替换
gsub(r, s, [t]) 匹配替换
length:统计字符长度
]# awk 'BEGIN{print length("aaa")}' 3
asort
排序后,建名为数字索引1,2,3等等,值为排序后的值。
例:
gawk 'BEGIN{ var["a"]=1 var["g"]=2 var["b"]=3 asort(var, test) for(x in test){ print x,test[x] } print test[1] }'
键名和键值
1 1 2 2 3 3
asorti
键名为索引1,2,3等等,键值为原来的键名
例:
gawk 'BEGIN{ var["a"]=1 var["g"]=2 var["b"]=3 asorti(var, test) for(x in test){ print x,test[x] } print test[1] }' 1 a 2 b 3 g
split
用FS或正则分格字段,放入第二个参数
例:
gawk 'BEGIN{FS=","}{ split($0, var) print var[1], var[3] #索引从1开始 }' test.txt xxx1 xxx3 ccc1 xxx3 xxx1 xxx3
调用内置命令:
]# awk 'BEGIN{system("hostname")}' nginx
时间函数:
mktime() 将一个按YYYY MM DD HH MM SS格式的日期转换成时间戳,STD格式
strftime() 将时间戳转换成格式化的日期
systime() 返回当前时间的时间戳
例:
gawk 'BEGIN{ date = systime() day = strftime("%A, %B, %d, %Y", date) print day }' 星期一, 十一月, 13, 2017
自定义函数:
函数必须放在所有代码块之前,如下:
gawk ' function myprint(){ printf "%-16s - %s\n", $1,$2 } BEGIN{FS="\n" ; RS=""} { myprint() }' test.txt Rion - 213-234-455 Stephone - 543-178-234
创建函数库:
例:
函数库的内容:cat funclib.gawk
function myprint(){ printf "%-16s - %s\n", $1,$2 } function hello{ print $4 }
脚本中的内容:cat script.gawk
BEGIN{FS="\n" ; RS=""} { myprint() }
使用-f命令来引入函数库和处理脚本,但是两个脚本不可以放在一起:
gawk -f funclib.gawk -f script.gawk test.txt
实例:
处理这样一个脚本:
name1,team1,100,123,109
name2,team2,130,140,122
name3,team3,129,123,109
处理脚本如下:
#!/bin/bash for team in $(gawk -F, '{print $2}' test.txt |uniq) do echo $team; gawk -v team=$team 'BEGIN{FS="," ; total=0}{ if($2==team){ total += $3 + $4 + $5; } } END{ avg = total / 6; print "total for", team, "is", total, ",the avgrage is ",avg }' test.txt done
处理结果如下:
total for team1 is 332 ,the avgrage is 55.3333 total for team2 is 392 ,the avgrage is 65.3333 total for team3 is 361 ,the avgrage is 60.1667