我有一个以下文本文件。我正在向您展示前 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
我想按原样打印出第一行,因为它是标题行。
然后对于后续行(即从第 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
答案1
awk 'NR > 1 { for (i = 6; i <= NF; i++) if ($i < 100) $i = "NA" }; 1' yourfile.txt
扩展评论:
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
编辑:有多种设置方法OFS
。我能想到的最简洁的方法是OFS='\t'
在文件名之前添加。
awk '...' OFS='\t' file.txt
awk -v OFS='\t' '...' file.txt
awk 'BEGIN { OFS="\t" }; ...' file.txt
答案2
jw013 已经为您提供了一个很好的 awk 解决方案,但是自从您提到 Perl 以来:
perl -lane 'map{$_="NA" if $_<100}@F[5..$#F] if $.>1; print join "\t", "@F"' file
解释
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 的答案的评论中要求)并打印它。
答案3
sed '1n;s|$| |;:na
s|\([+-] .*\) [+-]*[0-9]\{1,2\} |\1 NA |
t na;s| $||'
从您显示的数据来看,sed
s///;t
我认为这个小功能没有理由不起作用。(感谢 jw013 指出可能错过的最后一栏。)这只是将+/-
一行中 a 后面的每 1 或 2 个字符的数字字符串替换为它之前的所有内容,
NA
直到没有更多的内容可以替换。
这是另一个没有递归的版本,它利用了sed
旧h
空间:
sed '1n;h;s|.*[+-] ||;s|$| |
s| [+-]*[0-9]\{1,2\} | NA |g
x;G;s|\([+-] *\).*\n|\1|;s| $||'
它依赖于相同的标记,并在那里分割线 - 前半部分在h
旧空间中保持不变,而从模式空间中完全删除。然后,我们对所有 1,2 个数字字符单词进行全局替换,附加到h
旧空格,更改x
模式和旧空格,并删除作为附加操作结果插入的h
标记和 ewline 之间的所有内容。\n