如何仅从每列的第一个单词中删除特定字符?

时间:2016-05-26 13:32:39

标签: awk sed append character

文件输入:

1 34566 34765 
2 45678 45789
Scaffold_3 34567 34799
Scaffold_X 67895 66900
Scaffold_Y 34567 34890

注意:有很多行。我想从第一列中的单词中仅删除下划线(_)。除此之外不应该有其他变化。我正在学习sed和awk所以使用这些工具的任何命令都会有所帮助。此外,解释也会有所帮助。

归档:

1 34566 34765 
2 45678 45789
Scaffold3 34567 34799
ScaffoldX 67895 66900
ScaffoldY 34567 34890

3 个答案:

答案 0 :(得分:7)

这个awk单行应该做的工作:

awk '{gsub(/_/,"",$1)}1' input.txt

输出:

1 34566 34765 
2 45678 45789
Scaffold3 34567 34799
ScaffoldX 67895 66900
ScaffoldY 34567 34890

答案 1 :(得分:2)

我稍微修改了您的输入文件,以证明只删除了第一列中的下划线:

1 34_566 34765
2 45678 45_789
Scaffold_3 345_67 34799
Scaffold_X 678_95 66900
Scaffold_Y 345_67 34890

至于删除下划线,我使用了sed:

$ sed 's/^\([^ _]*\)_/\1/' infile 
1 34_566 34765
2 45678 45_789
Scaffold3 345_67 34799
ScaffoldX 678_95 66900
ScaffoldY 345_67 34890

该命令使用替换。我们匹配所有既不是空格也不是下划线的字符并捕获它们:\([^ _]*\)。此表达式锚定在字符串的开头(第一个^),后跟一个下划线。

然后我们用我们捕获的内容替换它,但保留下划线(替换字符串中的\1反向引用)。

第一列中的多个下划线

如果第一列中有多个下划线,那么sed会有点棘手。基本上有两种选择:

  1. 尝试替换第一列中的下划线(如上所述),重复此操作,直到不再发生更改,因此我们知道第一列中的所有下划线都已消失。
  2. 仅保留模式空间中的第一列,全局替换所有下划线,返回整行并将旧的替换为新的第一列。
  3. 以下是第一种方法的实施

    sed '
    :a                  # Label to jump to
    s/^\([^ _]*\)_/\1/  # Replace underscore in first column (like above)
    ta                  # Jump to label if something was changed
    ' infile
    

    这是第二种方法的实施

    sed '
    h                    # Copy pattern space to hold space
    s/^\([^ ]*\).*/\1/   # Remove everything but the first column
    s/_//g               # Delete all underscores
    G                    # Append hold space to pattern space
    
    # Replace old first column with underscore-free first column
    s/^\(.*\)\n[^ ]*\(.*\)/\1\2/
    ' infile
    

    最后一步是最棘手的一步。在它之前,我们的模式空间看起来像这样(假设第一列中有多个下划线的输入文件):

    ScaffoldY\nSca_ffold_Y 345_67 34890$
    ^^^^^^^^^  ^^^^^^^^^^^^^^^^^^^^^^^^
    New col 1      Old complete line
    

    我们通过智能捕获和替换来替换旧的第一列和新的第一列:

    ScaffoldY\nSca_ffold_Y 345_67 34890$
    ^^^^^^^^^             ^^^^^^^^^^^^^
        \1                      \2
    

    因此对于看起来像

    的输入文件
    1 34_566 34765
    2 45678 45_789
    Sca_ffold_3 345_67 34799
    Sca_ffold_X 678_95 66900
    Sca_ffold_Y 345_67 34890
    

    我们得到这样的输出(将命令压缩成一行):

    $ sed 'h;s/^\([^ ]*\).*/\1/;s/_//g;G;s/^\(.*\)\n[^ ]*\(.*\)/\1\2/' infile 
    1 34_566 34765
    2 45678 45_789
    Scaffold3 345_67 34799
    ScaffoldX 678_95 66900
    ScaffoldY 345_67 34890
    

    备注

    请注意,如果输入文件没有空格分隔,则无法正常工作。必须改变括号表达式中的空格以反映例如制表符分隔。第一个解决方案变为

    sed 's/^\([^[:blank:]_]*\)_/\1/' infile
    

    第二个

    sed ':a;s/^\([^[:blank:]_]*\)_/\1/;ta' infile
    

    和第三个

    sed 'h;s/^\([^[:blank:]]*\).*/\1/;s/_//g;G;s/^\(.*\)\n[^[:blank:]]*\(.*\)/\1\2/' infile 
    

答案 2 :(得分:0)

使用下划线作为字段分隔符(-F)而不是默认的空格:

awk -F'_' '{print $1$2}' file.txt