用于解析文件的 awk 命令

use*_*373 4 awk

我有以下文本文件。我正在向您展示前 3 行。

chrom   st  end gene    strand  c1  c2  c3  c4  c5  c6  c7  c8  c9  c10 c11 c12 c13 c14
chr6    3345    3543    geneA   +   36  -23 -1  3   1250    946 416 458 475 417 58  80  2   14
chr9    1302    1389    geneB   -   8   -10 -18 -8  2896    2128    635 955 372 385 -20 31  -7  -7
Run Code Online (Sandbox Code Playgroud)

我想按原样打印第一行,因为它是标题行。

然后对于后续行(即从第 2 行开始),我想按原样打印前 5 个字段(直到链信息),然后如果该字段(从第 6 个字段开始)具有值 >= 100 打印该值照原样,如果该字段的值 < 100,只需将其替换为 NA。

所以我的输出文件应该看起来像这样(理想情况下,制表符分隔)

chrom   st  end gene    strand  c1  c2  c3  c4  c5  c6  c7  c8  c9  c10 c11 c12 c13 c14
chr6    3345    3543    geneA   +   NA  NA  NA  NA  1250    946 416 458 475 417 NA  NA  NA  NA
chr9    1302    1389    geneB   -   NA  NA  NA  NA  2896    2128    635 955 372 385 NA  NA  NA  NA
Run Code Online (Sandbox Code Playgroud)

jw0*_*013 9

awk 'NR > 1 { for (i = 6; i <= NF; i++) if ($i < 100) $i = "NA" }; 1' yourfile.txt
Run Code Online (Sandbox Code Playgroud)

扩展与评论:

NR > 1 {                         # skipping NR == 1, the first line
    for (i = 6; i <= NF; i++)    # column 6 to the end, skipping first 5
        if ($i < 100) $i = "NA"  # self-explanatory
}

1 # print all lines; 1 evaluates to true, and default action is print
Run Code Online (Sandbox Code Playgroud)

编辑:有多种方法可以设置OFS. 我能想到的最简洁的方法是OFS='\t'在文件名之前添加。

awk '...' OFS='\t' file.txt
awk -v OFS='\t' '...' file.txt
awk 'BEGIN { OFS="\t" }; ...' file.txt
Run Code Online (Sandbox Code Playgroud)


ter*_*don 5

jw013 已经给了你一个很好的 awk 解决方案,但既然你提到了 Perl:

perl -lane 'map{$_="NA" if $_<100}@F[5..$#F] if $.>1; print join "\t", "@F"' file 
Run Code Online (Sandbox Code Playgroud)

解释

  • perl -lane: 处理每个输入行 ( -n) 并将其在空白处拆分为@F数组 ( -a),然后运行由 给出的脚本-e。在-l移除了尾随从每行换行,并添加\n到每个print语句。

  • map{$_="NA" if $_<100}@F[5..$#F]:对于数组的每个元素@F (字段)从第 6 个到最后,如果小于 100,则将该元素更改为“NA”。

  • if $.>1;: 前面map{}只会运行这不是第一行。

  • print join "\t", "@F"':将@F数组的每个元素与一个选项卡(在您对 jw013 的答案的评论中要求)连接并打印出来。