shell入门学习笔记-15-命令详解: 三剑客之一awk-内置变量、运算符

系列目录与参考文献传送门: shell入门学习笔记-序章

awk内置变量

变量名 速记 描述
FS File Separator 输入字段分隔符,默认是空格或制表符
OFS Output File Separator 输出字段分隔符,默认是空格
RS Row Separator 输入记录分隔符,默认是换行符\n
ORS Output Row Separator 输出记录分隔符,默认是换行符\n
NF Number of Fields 统计当前记录中字段个数
NR Number of current Row 统计记录编号,每处理一行记录,编号就会+1
FNR in current File, the Number of current Row 统计记录编号,每处理一行记录,编号也会+1,
与NR不同的是,处理第二个文件时,编号会重新计数。
ARGV ARGument Array 命令行参数数组序列数组,下标从0开始,ARGV[0]是awk
ARGC ARGument Count 命令行参数数量
ARGIND ARGument INDex 当前正在处理的文件索引值。第一个文件是1,第二个文件是2,以此类推
ENVIRON ENVIRONment variables 当前系统的环境变量
FILENAME FILENAME for current file 输出当前处理的文件名
IGNORECASE IGNORECASE 忽略大小写
SUBSEP arrays’s SUBscripts’s SEParates 数组中下标的分隔符,默认为"\034"

输入输出字段分隔符FS与OFS

在之前的章节,学习过以-F fs设置输入字段的分隔符。

# 格式化打印时间
admindeMacBook-Pro:~ admin$ echo "12:28:59" |awk -F':' '{print $1"时"$2"分"$3"秒"}'
12时28分59秒

上面的功能功能也可以通过下面的命令实现:

# 格式化打印时间
admindeMacBook-Pro:~ admin$ echo "12:28:59" |awk 'BEGIN{FS=":"}{print $1"时"$2"分"$3"秒"}'
12时28分59秒
admindeMacBook-Pro:~ admin$ echo "12:28:59" |awk -vFS=':' '{print $1"时"$2"分"$3"秒"}'
12时28分59秒
  • FS可以放在BEGIN模块中设置。
  • FS可以通过-vVar=value设置。
  • FS可以通过-F fs设置。

同理,对于输出分隔符,也有以下操作:

# 格式化打印时间
admindeMacBook-Pro:~ admin$ echo "12:28:59" |awk 'BEGIN{FS=":";OFS="-"}{print $1,$2,$3}'
12-28-59
admindeMacBook-Pro:~ admin$ echo "12:28:59" |awk -vFS=':' -vOFS='-' '{print $1,$2,$3}'
12-28-59
admindeMacBook-Pro:~ admin$ echo "12:28:59" |awk -vFS=':' '{print $1"-"$2"-"$3}'
12-28-59
  • OFS可以在BEGIN模块中设置。
  • OFS可以通过-vVar=value设置。
  • OFS可以通过手动拼接字符串"str"实现。

输入输出换行符RS和ORS

``RSORSFSOFS`的用法类型,举例如下:

admindeMacBook-Pro:~ admin$ echo "A-B-C" | awk 'BEGIN{RS="-"}{print $0}'
A
B
C

admindeMacBook-Pro:~ admin$ echo "A-B-C" | awk -vRS='-' '{print $0}'
A
B
C

admindeMacBook-Pro:~ admin$ echo "A-B-C" | awk -vRS='-' -vORS=',' '{print $0}'
A,B,C
admindeMacBook-Pro:~ admin$ echo "A-B-C" | awk 'BEGION{RS="-";ORS=","}{print $0}'
A-B-C

字段数量NF

# NF即当前行字段数量
admindeMacBook-Pro:~ admin$ echo "a b   c" |awk '{print NF}'
3

# $NF即最后一个字段
admindeMacBook-Pro:~ admin$ echo "a b   c" |awk '{print $NF}'
c

# $(NF-1)即倒数第二个字段
admindeMacBook-Pro:~ admin$ echo "a b   c" |awk '{print $NF-1}'
-1
admindeMacBook-Pro:~ admin$ echo "a b   c" |awk '{print $(NF-1)}'
b

# ${number}=""可以排除某个字段
admindeMacBook-Pro:~ admin$ echo "a b   c" |awk '{print $0}'
a b   c
admindeMacBook-Pro:~ admin$ echo "a b   c" |awk '$1=""{print $0}'
admindeMacBook-Pro:~ admin$ echo "a b   c" |awk '$1="";{print $0}'
 b c
admindeMacBook-Pro:~ admin$ echo "a b   c" |awk '$NF="";{print $0}'
a b
admindeMacBook-Pro:~ admin$ echo "a b   c" |awk '$(NF-1)="";{print $0}'
a  c

当前行数NR和当前文件的当前行数FNR

admindeMacBook-Pro:~ admin$ seq 3 |sed 's/.*/name&/'
name1
name2
name3
# 通过NR打印行号
admindeMacBook-Pro:~ admin$ seq 3 |sed 's/.*/name&/' |awk '{print NR,$0}'
1 name1
2 name2
3 name3

# 通过END{print NR}打印总行数
admindeMacBook-Pro:~ admin$ seq 3 |sed 's/.*/name&/' |awk 'END{print NR}'
3

# 通过NR=number打印指定行
admindeMacBook-Pro:~ admin$ seq 3 |sed 's/.*/name&/' |awk 'NR==2'
name2
# 打印指定行的指定列
admindeMacBook-Pro:~ admin$ seq 3 |sed 's/.*/name&/;s/.*/& male/'
name1 male
name2 male
name3 male
admindeMacBook-Pro:~ admin$ seq 3 |sed 's/.*/name&/;s/.*/& male/' |awk 'NR==1{print $1}'
name1
# 通过NR>number/NR=2{print NR,$1}'
2 name2
3 name3

# FNR与NR的区别
admindeMacBook-Pro:myshell admin$ cat m.txt
m1
m2
m3
admindeMacBook-Pro:myshell admin$ cat n.txt
n1
n2
n3
admindeMacBook-Pro:myshell admin$ awk '{print "单个文件第"FNR"行,总计第"NR"行: ",$0}' m.txt n.txt
单个文件第1行,总计第1行:  m1
单个文件第2行,总计第2行:  m2
单个文件第3行,总计第3行:  m3
单个文件第1行,总计第4行:  n1
单个文件第2行,总计第5行:  n2
单个文件第3行,总计第6行:  n3

当前文件所有ARGIND

admindeMacBook-Pro:~ admin$ cat m.txt
m1
m2
m3
admindeMacBook-Pro:~ admin$ cat n.txt
n1
n2
admindeMacBook-Pro:~ admin$ awk '{print "当前第"ARGIND"个文件,第"FNR"行,总记第"NR"行,内容是:",$0}' m.txt n.txt
当前第1个文件,第1行,总记第1行,内容是: m1
当前第1个文件,第2行,总记第2行,内容是: m2
当前第1个文件,第3行,总记第3行,内容是: m3
当前第2个文件,第1行,总记第4行,内容是: n1
当前第2个文件,第2行,总记第5行,内容是: n2
admindeMacBook-Pro:~ admin$ awk '{if(ARGIND==1){print "处理m.txt,第"FNR"行:",$0} if(ARGIND==2){print "处理n.txt,第"FNR"行:",$0}}' m.txt n.txt
处理m.txt,第1行: m1
处理m.txt,第2行: m2
处理m.txt,第3行: m3
处理n.txt,第1行: n1
处理n.txt,第2行: n2

命令行参数及个数ARGV和ARGC

# ARGC和ARGV用在BEGIN模块中
admindeMacBook-Pro:~ admin$ awk '{print ARGC}'
^C
admindeMacBook-Pro:~ admin$ awk '{print ARGV[0]}'
^C
# ARGV下标从0开始
admindeMacBook-Pro:~ admin$ awk 'BEGIN{print ARGC}'
1
admindeMacBook-Pro:~ admin$ awk 'BEGIN{print ARGV[0]}'
awk
admindeMacBook-Pro:~ admin$ awk 'BEGIN{print ARGV[1]}'

admindeMacBook-Pro:~ admin$ awk 'BEGIN{print ARGC}' 1
2
admindeMacBook-Pro:~ admin$ awk 1 'BEGIN{print ARGC}' 1
awk: can't open file BEGIN{print ARGC}
 source line number 1
admindeMacBook-Pro:~ admin$ awk 'BEGIN{print ARGC}' 1 2
3
admindeMacBook-Pro:~ admin$ awk 'BEGIN{print ARGV[2]}' 1 2
2
  • ARGCARGV用在BEGIN模块中。
  • ARGV下标从0开始,ARGV[0]=awkARGV[1]是第一个参数。

环境变量ENVIRON

# 在BEGIN模块中使用ENVIRON
admindeMacBook-Pro:~ admin$ awk '{print ENVIRON["HOME"]}'
^C
admindeMacBook-Pro:~ admin$ awk 'BEGIN{print ENVIRON["HOME"]}'
/home/hanchao
# 环境变量需要export
admindeMacBook-Pro:~ admin$ aaaaa=123456
admindeMacBook-Pro:~ admin$ echo $aaaaa
123456
admindeMacBook-Pro:~ admin$ awk 'BEGIN{print ENVIRON["aaaaa"]}'

admindeMacBook-Pro:~ admin$ export aaaaa
admindeMacBook-Pro:~ admin$ awk 'BEGIN{print ENVIRON["aaaaa"]}'
123456
  • ENVIRON需要在BEGIN模块中使用。
  • ENVIRON只针对环境变量,关于环境变量,请参考之前的作用域章节。

当前处理的文件名FILENAME

admindeMacBook-Pro:~ admin$ awk '{if(ARGIND==1){print "m.txt",$0} if(ARGIND==2){print "n.txt",$0}}' m.txt n.txt
m.txt m1
m.txt m2
m.txt m3
n.txt n1
n.txt n2
admindeMacBook-Pro:~ admin$ awk '{print FILENAME,$0}' m.txt n.txt
m.txt m1
m.txt m2
m.txt m3
n.txt n1
n.txt n2
  • FILENAME打印的是当前正在处理的文件。

awk运算符

运算符 描述
(....) 分组
$ 字段引用
++ -- 一元运算符:递增和递减
+ - 一元运算符:取正,取负。负负为正。
+ - * / % ^ 二元运算符:加减乘除、取余和幂
< > <= >= != == 关系运算符
= += -= *= /= %= ^= 变量赋值运算符
&& || ! 逻辑运算符:逻辑与 逻辑或 逻辑否定
expr1 ? expr2 : expr3 三元运算符:条件表达式,如果expr1为真,则执行expr2,否则执行expr3
var~// var!~// 正则表达式匹配,否定正则表达式匹配
in 数组成员
| 管道,用于getline,print和printf

变量初始值与表达式为空的情况

  • 数值运算,未定义的变量的初始值是0
  • 字符运算,未定义的变量的初始值为
  • awk中,以下三种情况,表达式为false:
    • 数字等于0
    • 字符串为
    • 未定义的值
admindeMacBook-Pro:~ admin$ awk 'BEGIN{num=0;if(!num) print "0 is false";
> str="";if(!str) print "blank is false";
> if(!unk) print "unknown is false"}'
0 is false
blank is false
unknown is false

分组(…)

admindeMacBook-Pro:~ admin$ awk 'BEGIN{a=1;b=2;c=3;d=a+b*c;print d}'
7
admindeMacBook-Pro:~ admin$ awk 'BEGIN{a=1;b=2;c=3;d=(a+b)*c;print d}'
9

字段引用$

admindeMacBook-Pro:~ admin$ echo "aa bb" |awk '{print $0}'
aa bb
admindeMacBook-Pro:~ admin$ echo "aa bb" |awk '{print $1}'
aa
admindeMacBook-Pro:~ admin$ echo "aa bb" |awk '{print $2}'
bb

递增++和递减–

admindeMacBook-Pro:~ admin$ awk 'BEGIN{a=2;print a;print a++;print a--}'
2
2
3
admindeMacBook-Pro:~ admin$ awk 'BEGIN{a=2;print a;print ++a;print --a}'
2
3
2
  • 自增和自减需要注意操作符与变量的前后位置。

取正+和取负-

# 取正与取负
admindeMacBook-Pro:~ admin$ awk 'BEGIN{a=1;b=-2;print -a;print -b;}'
-1
2
admindeMacBook-Pro:~ admin$ awk 'BEGIN{a=1;b=-2;print +a;print +b;}'
1
-2
# 只能位于变量之前
admindeMacBook-Pro:~ admin$ awk 'BEGIN{a=1;b=-2;print a+;print b+;}'
awk: cmd. line:1: BEGIN{a=1;b=-2;print a+;print b+;}
awk: cmd. line:1:                        ^ syntax error
awk: cmd. line:1: BEGIN{a=1;b=-2;print a+;print b+;}
awk: cmd. line:1:                                 ^ syntax error
admindeMacBook-Pro:~ admin$ awk 'BEGIN{a=1;b=-2;print a-;print b-;}'
awk: cmd. line:1: BEGIN{a=1;b=-2;print a-;print b-;}
awk: cmd. line:1:                        ^ syntax error
awk: cmd. line:1: BEGIN{a=1;b=-2;print a-;print b-;}
awk: cmd. line:1:                                 ^ syntax error
#可以用于获取字符串变量中的数值
admindeMacBook-Pro:~ admin$ awk 'BEGIN{a=11b;print +a}'
11
admindeMacBook-Pro:~ admin$ awk 'BEGIN{a=11b;print -a}'
-11
admindeMacBook-Pro:~ admin$ echo "11ww" |awk '{print +$0}'
11
admindeMacBook-Pro:~ admin$ echo "11ww22" |awk '{print +$0}'
11
  • +-在作为一元运算符时,需要放在变量之前。
  • +var:表示(+1) * var
  • -var:表示(-1) * var
  • +-可以用于获取字符串变量中的数值,但仅限于首个数值。
  • +不会改变量的正负:正正得正,正负得负。
  • -会改变变量的正负:负正得负,负负得正。

加减乘除、取余和幂

awk支持,加减乘除和取余,即:+ - * / % ^

admindeMacBook-Pro:~ admin$ awk 'BEGIN{a=1;b=2;c=3;d=4;print a+b-c*d;print 3%2;}'
-9
1
admindeMacBook-Pro:~ admin$ awk 'BEGIN{a=3;print a^2}'
9

通过%对应奇偶行

admindeMacBook-Pro:~ admin$ seq 6 |awk '$0%2==1{print $0}'
1
3
5
admindeMacBook-Pro:~ admin$ seq 6 |awk '$0%2==0{print $0}'
2
4
6

关系运算符

awk支持的关系运算符为:< > <= >= != ==

admindeMacBook-Pro:~ admin$ awk 'BEGIN{if(1==1 && 1!=2) print "1==1 && 1!=2"}'
1==1 && 1!=2
admindeMacBook-Pro:~ admin$ awk 'BEGIN{if(2>=1 && 1<2) print "2>=1 && 1<2"}'
2>=1 && 1<2

赋值运算符

awk支持变量赋值运算符,即:= += -= *= /= %= ^=

admindeMacBook-Pro:~ admin$ awk 'BEGIN{a=1;a+=1;b=2;b-=2;c=3;c*=3;d=4;d/=4;e=5;e%=5;print a,b,c,d,e}'
2 0 9 1 0
admindeMacBook-Pro:~ admin$ awk 'BEGIN{a=3;a^=2;print a}'
9

逻辑运算符

awk支持逻辑运算符,即:逻辑与&&,逻辑或||,逻辑非!

admindeMacBook-Pro:~ admin$ awk 'BEGIN{if(1 && 2) print "true"}'
true
admindeMacBook-Pro:~ admin$ awk 'BEGIN{if(0 || 1) print "true"}'
true
admindeMacBook-Pro:~ admin$ awk 'BEGIN{if(!0) print "true"}'
true

admindeMacBook-Pro:~ admin$ seq 9 11 |awk '/1/{print $0}'
10
11
admindeMacBook-Pro:~ admin$ seq 9 11 |awk '!/1/{print $0}'
9

通过!打印奇数行和偶数行

admindeMacBook-Pro:~ admin$ echo good |awk '0'
admindeMacBook-Pro:~ admin$ echo good |awk '1'
good

admindeMacBook-Pro:~ admin$ echo good |awk 'a=0;a'
admindeMacBook-Pro:~ admin$ echo good |awk 'a=1;a'
good
good

# 奇数行
admindeMacBook-Pro:~ admin$ seq 6 |awk 'i=!i'
1
3
5
# 偶数行
admindeMacBook-Pro:~ admin$ seq 6 |awk '!(i=!i)'
2
4
6
  • awk '0':因为0表示false,不会打印任何信息。
  • awk '1':因为1表示true,会打印当前行。
  • awk 'a=1':等价于awk 'a',因为a=1,所以条件为真,会打印当前行。

关于seq 6 |awk 'i=!i'的解析:

  • 第一行:已知未定义数值变量默认为0,所以i=!i==>i=!0,即i=1,条件为真,打印第一行。
  • 第二行:第一行运行结果:i=1。此时i=!i,则i=0,条件为false,不打印第2行。
  • 以此类推。

三元运算符?:

admindeMacBook-Pro:~ admin$ awk 'BEGIN{print 1?1:2}'
1

替换换行符为空格

admindeMacBook-Pro:~ admin$ seq 3 |awk '{n=(n?n" "$0:$0)}END{print n}'
1 2 3
  • 第一行:n=(n?n" "$0:$0),因为n初始化为0,所以,最终n=$0 ==> n=1
  • 第二行:n=(n?n" "$0:$0),因为n=1,所以n=n" "$0 ==> n=2 1
  • 以此类推。

每两行后面新增一行

admindeMacBook-Pro:~ admin$ seq 5 |awk '{print NR%2?$0:$0"\n----"}'
1
2
----
3
4
----
5

每三行合并为一行

admindeMacBook-Pro:~ admin$ seq 6 |awk '{printf NR%3?$0" ":$0"\n"}'
1 2 3
4 5 6

正则表达式匹配

admindeMacBook-Pro:~ admin$ echo "123hah 999kk" |awk '$0~/12/{print $0}'
123hah 999kk
admindeMacBook-Pro:~ admin$ echo "123hah 999kk" |awk '$1~/12/{print $0}'
123hah 999kk
admindeMacBook-Pro:~ admin$ echo "123hah 999kk" |awk '$2~/12/{print $0}'
admindeMacBook-Pro:~ admin$ echo "123hah 999kk" |awk '$2~/99/{print $0}'
123hah 999kk

admindeMacBook-Pro:~ admin$ echo "123hah 999kk" |awk '$2!~/99/{print $0}'
admindeMacBook-Pro:~ admin$ echo "123hah 999kk" |awk '$2!~/12/{print $0}'
123hah 999kk
  • var~//var!~//

数组成员in

admindeMacBook-Pro:~ admin$ awk 'BEGIN { arr[0] = 1; arr[1] = 2; arr[2] = 3; for (i in arr) print i}'
0
1
2

管道|

admindeMacBook-Pro:~ admin$ seq 5
1
2
3
4
5
admindeMacBook-Pro:~ admin$ seq 5|shuf
2
5
1
4
3
admindeMacBook-Pro:~ admin$ seq 5|shuf
1
2
5
3
4
admindeMacBook-Pro:~ admin$ seq 5|shuf|awk '{print $0 |"sort"}'
1
2
3
4
5
  • shuf:把输入行随机输出。

你可能感兴趣的:(Shell,shell学习笔记)