用bash替换每列中的第一个匹配项

时间:2018-04-11 09:27:13

标签: regex bash awk sed replace

我的输入看起来像这样(制表符分隔文件)

CHROM POS ID REF ALT 76_BRS_AMC_00D2282 c21_BE_MS1038U_BE_MS1038U_c30 93_BRS_MST_DNA17_53119M 94_BRS_MST_DNA17_53120M 100_BRS_BRU_D14_0867
01 12153 rs2454 A G 1,0,0 1,0,0 1,0,0 1,0,0 1,0,0
01 12154 rs2455 C G 1,0,0 1,0,0 1,0,0 1,0,0 1,0,0

我想要一个“#”而不是每个列名中的第一个“_”

CHROM POS ID REF ALT 76#BRS_AMC_00D2282 c21#BE_MS1038U_BE_MS1038U_c30 93#BRS_MST_DNA17_53119M 94#BRS_MST_DNA17_53120M 100#BRS_BRU_D14_0867
01 12153 rs2454 A G 1,0,0 1,0,0 1,0,0 1,0,0 1,0,0
01 12154 rs2455 C G 1,0,0 1,0,0 1,0,0 1,0,0 1,0,0

我不知道如何使用sed处理表格,我尝试使用awk

awk -F "\t" '/_/ && count < 2 {gsub("_","#");count++} {print $0}'

但它只是替换所有“_”而不仅仅是第一次出现

我想要一个awk或sed解决方案。

(对不起,如果这是一个复制的问题,我没有找到答案)

2 个答案:

答案 0 :(得分:1)

sub将替换第一次出现,因此只需将要修改的记录限制为NR==1,循环其中的每一列,替换为subprint其余原样:

$ awk 'NR==1{for(i=1;i<=NF;i++)sub(/_/,"#",$i)}1' file
CHROM POS ID REF ALT 76#BRS_AMC_00D2282 c21#BE_MS1038U_BE_MS1038U_c30 93#BRS_MST_DNA17_53119M 94#BRS_MST_DNA17_53120M 100#BRS_BRU_D14_0867
01 12153 rs2454 A G 1,0,0 1,0,0 1,0,0 1,0,0 1,0,0
01 12154 rs2455 C G 1,0,0 1,0,0 1,0,0 1,0,0 1,0,0

(如果您希望输出也以制表符分隔,您可能需要定义BEGIN{FS=OFS="\t"}。解释:

$ awk '
#BEGIN{FS=OFS="\t"}       # incase you want output tab-delimited also (not in above script)
NR==1 {                  # process the header record only
    for(i=1;i<=NF;i++)   # loop every column header
        sub(/_/,"#",$i)  # replace the first _ with #
}1' file                 # output

答案 1 :(得分:1)

你可以试试这个gnu sed

sed -E '1s/(\t?[^\t_]+)_([^\t]+)/\1#\2/g' infile

解释:

-E使用扩展正则表达式

1仅在第1行上运行

RE(\ t?[^ \ t _] +)_([^ \ t] +)捕获每一列

(\ t?[^ \ t _] +)抓住第1组

\吨?从可选标签开始(第一列可选)

[^ \ t _] +后跟至少一个不是制表符或_

的字符

后跟_

其次是另一组

([^ \ t] +)抓住第2组

所有不是标签的字符

\ 1#\ 2用group1替换列,然后用#后跟group2

g表示对每列进行操作。