我有以下文本文件。我正在向您展示前 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)
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)
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 的答案的评论中要求)连接并打印出来。