我有一个具有以下格式的文件,其中每行的字段数是可变的:
NC_000001.11_NM_001005484.2 69270 234 69037 65565 69037
NC_000001.11_NM_001005484.2 69511 475 69037 65565 69037
NC_000001.11_NM_001005484.2 69761 725 69037 65565 69037
NC_000001.11_NM_001385640.1 942155 20 942136 924432 925922 930155 931039 935772 939040 939272 941144 942136 942410 942559 943253 943698 943908
Run Code Online (Sandbox Code Playgroud)
对于每一行,我想打印前四个字段。对于其余字段($5 到 NF),如果这些字段中的值小于 $4 中的值,我想打印该字段。
输出示例:
NC_000001.11_NM_001005484.2 69270 234 69037 65565
NC_000001.11_NM_001005484.2 69511 475 69037 65565
NC_000001.11_NM_001005484.2 69761 725 69037 65565
NC_000001.11_NM_001385640.1 942155 20 942136 924432 925922 930155 931039 935772 939040 939272 941144
Run Code Online (Sandbox Code Playgroud)
我尝试过多种不同的 awk 选项,但都失败了。awk 新手,希望得到任何帮助。
如果您不关心输出中的空白,那么您需要的是:
$ cat tst.awk
{
out = $1 OFS $2 OFS $3 OFS $4
for (i=5; i<=NF; i++) {
if ( $i < $4 ) {
out = out OFS $i
}
}
print out
}
Run Code Online (Sandbox Code Playgroud)
$ awk -f tst.awk file
NC_000001.11_NM_001005484.2 69270 234 69037 65565
NC_000001.11_NM_001005484.2 69511 475 69037 65565
NC_000001.11_NM_001005484.2 69761 725 69037 65565
NC_000001.11_NM_001385640.1 942155 20 942136 924432 925922 930155 931039 935772 939040 939272 941144
Run Code Online (Sandbox Code Playgroud)
column
如果您愿意,您可以通过管道进行视觉对齐:
$ awk -f tst.awk file | column -t
NC_000001.11_NM_001005484.2 69270 234 69037 65565
NC_000001.11_NM_001005484.2 69511 475 69037 65565
NC_000001.11_NM_001005484.2 69761 725 69037 65565
NC_000001.11_NM_001385640.1 942155 20 942136 924432 925922 930155 931039 935772 939040 939272 941144
Run Code Online (Sandbox Code Playgroud)
否则,如果您希望输出中的间距看起来像输入中的间距(即前 4 个字段看起来有 1 个或更多空格,其余字段有 2 个或更多空格)并假设某些行可能只有 4或更少的字段,然后使用任何 POSIX awk(对于字符类和正则表达式间隔):
$ cat tst.awk
BEGIN { OFS="\t" }
match($0,/([^[:space:]]+[[:space:]]+){3}[^[:space:]]+/) {
out = substr($0,RSTART,RLENGTH)
for (i=5; i<=NF; i++) {
if ( $i < $4 ) {
out = out OFS $i
}
}
$0 = out
}
{ print }
Run Code Online (Sandbox Code Playgroud)
如果 $4 之后的字段应以制表符分隔:
$ awk -f tst.awk file
NC_000001.11_NM_001005484.2 69270 234 69037 65565
NC_000001.11_NM_001005484.2 69511 475 69037 65565
NC_000001.11_NM_001005484.2 69761 725 69037 65565
NC_000001.11_NM_001385640.1 942155 20 942136 924432 925922 930155 931039 935772 939040 939272 941144
Run Code Online (Sandbox Code Playgroud)
或者如果它们应该用空格分隔:
$ awk -f tst.awk file | column -s$'\t' -t
NC_000001.11_NM_001005484.2 69270 234 69037 65565
NC_000001.11_NM_001005484.2 69511 475 69037 65565
NC_000001.11_NM_001005484.2 69761 725 69037 65565
NC_000001.11_NM_001385640.1 942155 20 942136 924432 925922 930155 931039 935772 939040 939272 941144
Run Code Online (Sandbox Code Playgroud)
上面保留了前 4 个字段之间的空白,以便它只是您输入中的制表符和/或空格的任何组合,然后在每 5 个及后续字段之前打印一个制表符,您可以使用它来更改为column
等效的如果您愿意,可以留空,两者看起来都像问题中的输入和输出。
我正在构建一个out
在上面的循环中命名的新字符串,并将其分配给$0
循环之后的一次,而不是修改$0
或$i
在循环内,因为每次更改$i
awk 都必须从它的字段重新构建$0
,并且每次更改$0
awk 都必须重新分割$0
为字段,因此两者效率都很低,并且可能会导致意外错误,具体取决于字段的内容,因此您不应在循环内修改$0
或 ,$i
除非您有一个非常具体的目的需要这样做。