0%

awk的几点用法

AWK是常用的数据处理工具,内置的变量名称为:

变量名 含义
ARGC 命令行变元个数
ARGV 命令行变元数组
FILENAME 当前输入文件名
FNR 当前文件中的记录号
FS 输入域分隔符,默认为一个空格
RS 输入记录分隔符
NF 当前记录里域个数
NR 到目前为止记录数
OFS 输出域分隔符
ORS 输出记录分隔
$NF 表示最后一列

这里列出几条常用的命令。

编辑

数据格式如下,下面的数据输入到GMT psxy是无法识别这种数字segment的,因此使用awk处理,将segment分隔符修改为>

1
2
3
4
5
6
7
8
9
10
11
12
13
$ head far_xmd_latlon.dat
0
120.52067 36.022747
120.52073 36.022694
1
120.52075 36.022607
120.52083 36.022572
2
120.52083 36.022554
120.52094 36.022519
120.52102 36.022484
120.52108 36.022397
120.52110 36.022345
1
2
3
4
5
6
7
8
9
10
11
12
13
$ awk '{if(FNR==1){tmp2=$2}if($2==null){$2=$1;$3=$1;$1=">"};tmp2=$2;a[FNR]=$1" "$2; print a[FNR]}'  far_xmd_latlon.dat | head
> 0
120.52067 36.022747
120.52073 36.022694
> 1
120.52075 36.022607
120.52083 36.022572
> 2
120.52083 36.022554
120.52094 36.022519
120.52102 36.022484
120.52108 36.022397
120.52110 36.022345

判断

判断某一列不包含NaN,或者不包含任意其他数字或者字符,替换!/NaN/

1
awk ' !/NaN/ {print $1,$3}' track2.dat >track.dat

判断包含某一个数字

1
2
awk '/101/'    file      显示文件file中包含101的匹配行。 
awk '/101/,/105/' file

按照某一列去掉重复行,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ cat hy.txt |head
3.5424793e+02 -6.9635819e+01 6.3286622e+08 6.0882000e+00 -3.9305000e+00
3.5417193e+02 -6.9587913e+01 6.3286622e+08 5.9665000e+00 -3.9174000e+00
3.5409219e+02 -6.9537385e+01 6.3286622e+08 5.8278000e+00 -3.9236000e+00
3.5401280e+02 -6.9486826e+01 6.3286622e+08 5.7029000e+00 -3.9108000e+00
3.5393376e+02 -6.9436234e+01 6.3286622e+08 5.5313000e+00 -3.9370000e+00
3.5385508e+02 -6.9385611e+01 6.3286622e+08 5.3727000e+00 -3.9158000e+00
3.5377474e+02 -6.9333657e+01 6.3286623e+08 5.1118000e+00 -3.9606000e+00
3.5369676e+02 -6.9282970e+01 6.3286623e+08 4.9405000e+00 -3.9307000e+00
3.5361913e+02 -6.9232252e+01 6.3286623e+08 4.7348000e+00 -3.9374000e+00
3.5354184e+02 -6.9181504e+01 6.3286623e+08 4.6018000e+00 -3.9156000e+00


$ awk '!a[$3]++' hy.txt |head
3.5424793e+02 -6.9635819e+01 6.3286622e+08 6.0882000e+00 -3.9305000e+00
3.5377474e+02 -6.9333657e+01 6.3286623e+08 5.1118000e+00 -3.9606000e+00
3.5301023e+02 -6.8825421e+01 6.3286624e+08 3.8921000e+00 -3.9235000e+00
3.5227822e+02 -6.8314285e+01 6.3286625e+08 2.6547000e+00 -3.9175000e+00
3.5157488e+02 -6.7799132e+01 6.3286626e+08 2.0706000e+00 -3.9096000e+00
3.5090018e+02 -6.7281458e+01 6.3286627e+08 2.1666000e+00 -3.9052000e+00
3.5025396e+02 -6.6762768e+01 6.3286628e+08 2.1938000e+00 -3.9343000e+00
3.4963125e+02 -6.6240561e+01 6.3286629e+08 2.6635000e+00 -3.9052000e+00
3.4903220e+02 -6.5716309e+01 6.3286630e+08 3.1479000e+00 -3.9322000e+00
3.4845540e+02 -6.5190147e+01 6.3286631e+08 3.4762000e+00 -3.8902000e+00

其他判断

1
2
3
4
awk '$1 == 5'    file 
awk '$1 == "CT"' file 注意必须带双引号
awk '$1 * $2 >100 ' file
awk '$2 >5 && $2<=15' file

运算

按照列相加

1
2
3
$ seq 5 |awk 'BEGIN{sum=0;print "sum:"}{if(NR<=4)printf $1"+";sum+=$1; if(NR==5)printf $1 "="}END{print sum}'
sum:
1+2+3+4+5=15

简化:

1
2
$ seq 20 |awk 'BEGIN{sum=0;}{if(NR>1&&NR<=3) sum+=$1;}END{print sum}'
5

文件的列相加

1
awk '{for(i=2;i<=NF;i++)a[i]+=$i;print}END{printf "TOTAL \t";for(j=2;j<=NF;j++)printf a[j]"\t"; print""}'

文件的行相加,不含第一列。

1
awk '{b[NR]=$0; for(i=2;i<=NF;i++)a[NR]+=$i;}END{for(i=1;i<=NR;i++) print b[i]"\t"a[i]}' file

文件的行相加,并计算均值。不含第一列。

1
awk '{b[NR]=$0; for(i=2;i<=NF;i++)a[NR]+=$i;}END{for(i=1;i<=NR;i++) print b[i]"\t"a[i]/(NF-1)}' file

文件两列的均方根,可以使用gmt math。但是-C比较容易出错。

1
2
gmt math -C1 pow5_jizai.txt SQR pow5_jizai_y.txt SQR ADD SQRT = | head # 只有第二列,其他设置0
gmt math pow5_jizai.txt -C1 SQR pow5_jizai_y.txt SQR ADD SQRT = | head # 全部输出,仅第二列计算。

使用awk对任意多个文件计算平均值。具体为有n个文件,具有相同的行列数,然后再文件维度上计算均值。

1
awk '{a[FNR]+=$2;c[FNR]+=$3;d[FNR]+=$1;b[FNR]++;}END{for(i=1;i<=FNR;i++)print d[i]/b[i],a[i]/b[i],c[i]/b[i]}' pow5_jizai1_x*.txt > pow5_jizai1.txt

对两个文件做列的相减:首先对一个文件按照另一个文件的点进行采样,然后使用join合并两个文件,awk作差。

1
2
gmt sample1d pow5_jizai1.txt2 -Tpow5_pass.txt2 -Fc > pow5_jizai1.txt3
join pow5_jizai1.txt3 pow5_pass.txt2 | awk ' NR>2 {print $1,$3-$2}'

gmt math 计算均值,注意STDIN。如果是文件输入则不需要STDIN。

1
2
join pow5_jizai1.txt3 pow5_pass.txt2 | awk ' NR>2 {print sqrt(($3-$2)^2)}' | gmt gmtmath STDIN -Sl MEAN  = 
gmt gmtmath ja_t.d -Sl -Ca STD =

awk多行变1列,并提取奇数行

1
awk BEGIN{RS=EOF}'{gsub(/\n/," ");print}' wind_d.txt | awk '{for(i=0;++i<=NF;)a[i]=a[i]?a[i] FS $i:$i}END{for(i=0;i++<NF;)print a[i]}' |awk '(NR%2)!=0 {print $1}'>d.d

awk换算角度,-180/180换算到0/360

1
2
3
4
5
# 分离
awk '$2<0 {print $1,$2+360}' degree.txt >degree1.txt
awk '$2>=0 {print $1,$2}' degree.txt >degree2.txt
# 合并
cat degree1.txt degree2.txt | sort |

awk内使用变量

大概两种办法,分别是'"var"'和使用-v

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/env bash
gmt math -T1/100/0.01 -N2/0 -C1 T SIN = h_f.txt
gmt psbasemap `gmt gmtinfo h_f.txt -I0.000001` -JX4i/2i -Bxaf -Byaf -BWSne -K -Xc > test.ps
for((i=1;i<=20;i++));
do
r=$(($RANDOM%255))
g=$(($RANDOM%255))
b=$(($RANDOM%255))

((max = $i * 500))
((min = ($i-1) * 500))
awk 'NR<'"$max"' && NR>'"$min"' {print $1,$2}' h_f.txt >pow5.txt
# awk -v m="$max" -v n="$min" 'NR<m && NR>n {print $1,$2}' h_f.txt >pow5.txt2
gmt psxy -R -JX -K pow5.txt -W2.25p,$r/$g/$b -O -i0,1 >> test.ps
done
  • 上面的例子中还包含简单的整数数学运算,语法是(( c=a+b))
  • 浮点预算使用awk
  • 使用math 产生二维的时间序列方法gmt math -T1/100/0.01 -N2/0 -C1 T SIN = h_f.txt
  • 不同颜色的绘图叠加方法r=$(($RANDOM%255)),加上%255表示限制在0~255之间随机整数。

应用

从xml文件中批量提取天宫坐标范围

1
2
3
4
5
6
7
8
9
10
11
12
grep -wf vol.d2 tmp.d > result.d
get location of tiangong2 data
cat *.xml | grep 'CenterPointLat' | awk -F">" '{print $2}' | awk -F"<" '{print $1}' > ../track.dat
cat *.xml | grep 'CenterPointLon' | awk -F">" '{print $2}' | awk -F"<" '{print $1}' > ../track_lon.dat
awk '{print $1}' ../track_lon.dat | paste - ../track.dat > ../trc.dat

cat *.xml | grep -e 'Latitude' -e 'Longitude' | awk -F">" '{print $2}' | awk -F"<" '{print $1}' | head

cat *.xml | grep 'Longitude' | awk -F">" '{print $2}' | awk -F"<" '{print $1}' > ../track2_lon.dat
cat *.xml | grep 'Latitude' | awk -F">" '{print $2}' | awk -F"<" '{print $1}' > ../track2_lat.dat
awk '{print $1}' ../track2_lon.dat | paste - ../track2_lat.dat > ../trc2.dat
cat trc2.dat | awk '{if(NR%8 == 0) printf("%s\n>\n", $0); else print $0}' > trc.new

批量提取GPS结果中测站名称和坐标信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/bin/bash
#date:2020-1-18
cd gamit
pwd
# ls *.xml
# touch ../vol.d
# touch ../track2_lat.dat
touch ../names.txt

for i in `ls *.ios_gamit_detrend.neu`
do
echo $i
# cat $i | grep 'Up stats'| awk -F":" '{print $0}'|awk '{for(i=1;i<13;i=i+1){printf $i" "};printf "\n"}' >> ../vol.d
# echo ">" >> ../vol.d
cat $i | grep '4-character ID'| awk -F":" '{print $0}' >> ../names.txt
# echo ">" >> ../vol.d
done

awk -F":" '{print $2}' ../names.txt | paste - ../vol.d > ../vol.d2
awk '{print $3,$1,$2}' ../../figs/trc.dat > ../tmp.d

# awk 'NR==FNR{a[$1]=$0;next}NR>FNR{if($1 in a)print a[$1],a[$2],$1,$1}' ../vol.d2 ../../figs/trc.dat > ../result.d
# 匹配两个文件中的相同内容,并输出到一个文件夹。
awk 'NR==FNR{S[$1]=$0;next}NR>FNR{print S[$1],$5,$7,$10,$13}' tmp.d vol.d2 > result.d
# 第一列匹配,表示为字母
awk '{if($1 ~ /^[A-Z]+$/) print $0}' result.d > result.d2