我有一个具有非固定列号的输入文件,我想对其进行一些算术计算:
input.txt
ID1 4651455 234 4651765 392 4652423 470
ID2 16181020 176 16184958 869 16185889 347 16187777 231
输入文件具有制表符分隔的字段,该ID
字段在列中始终是唯一的$1
(不重复)。并非所有行都具有相同的列数。
我想要实现的是一个制表符分隔的文件,如下所示:
output1.txt
ID1 76 266
ID2 3762 62 1541
基本上它会打印$1
原始文件的,然后从文件的第二个偶数列开始($4
)并减去前两列的值($4
- $3
- $2
),然后对输入文件的所有偶数列执行相同的操作(例如,$6
- $5
- $4
; $8
- $7
- $6
; ...)。据我所知,这可以通过 来完成awk print
,但我只知道当我的文件每行都有固定数量的列时如何处理它。
满足我的需求的更理想的输出如下:
output2.txt
ID1 234 76 392 266 470
ID2 176 3762 869 62 347 1541 231
基本上它会打印$1
原始文件的 ,然后将输入文件中的奇数列交错打印到列中,如output1.txt
.
答案1
$ awk -v OFS='\t' -f script.awk file
ID1 76 266
ID2 3762 62 1541
哪里script.awk
{ printf("%s", $1) }
{ for (i=4; i<=NF; i+=2) { printf("%s%d", OFS, $i - $(i-1) - $(i-2)) } }
{ printf("%s", RS) }
将对文件的每一行输入执行所有块。
第一个块输出 ID。
第二个块按照您的描述迭代字段,并输出由OFS
(输出字段分隔符,设置为命令行上的选项卡)分隔的数据。
最后一个块只是输出记录分隔符RS
,默认情况下是换行符。
或者,
BEGIN { OFS = "\t" }
{ printf("%s", $1) }
{ for (i=4; i<=NF; i+=2) { printf("%s%d", OFS, $i - $(i-1) - $(i-2)) } }
{ printf("%s", RS) }
摆脱对 的需要-v OFS='\t'
。
作为“一行”:
$ awk 'BEGIN { OFS = "\t" }
{ printf("%s", $1) }
{ for (i=4; i<=NF; i+=2) { printf("%s%d", OFS, $i - $(i-1) - $(i-2)) } }
{ printf("%s", RS) }' file
对于扩展问题:
{ printf("%s", $1) }
{ for (i=4; i<=NF; i+=2) { printf("%s%d%s%d", OFS, $(i-1), OFS, $i - $(i-1) - $(i-2)) } }
{ printf("%s%d%s%s", OFS, $NF, OFS, RS) }
这将直接从原始文件生成以下内容:
ID1 234 76 392 266 470
ID2 176 3762 869 62 347 1541 231
答案2
awk解决方案:
awk '{ r=$1; for(i=4;i<=NF;i+=2) r=r"\t"$i-$(i-1)-$(i-2); printf "%s\n",r }' OFS='\t' file
r=$1
- 捕获第一个字段for(i=4;i<=NF;i+=2)
- 迭代甚至字段$i-$(i-1)-$(i-2)
- 执行所需的减法
输出:
ID1 76 266
ID2 3762 62 1541