使用 perl 或 awk 就地编辑文件

使用 perl 或 awk 就地编辑文件

我有一个很大的制表符分隔输入文件,如下所示

SF_0000000555_RDNAU_58_10293    10873   11041   +       ID=match41;Target=SF_0000000005 99 267 168
SF_0000000555_RDNAU_58_10293    188079  188215  +       ID=match2617;Target=SF_0000000020 3 138 135
SF_0000000555_RDNAU_58_10293    137594  137704  -       ID=match4142;Target=SF_0000000048 16 126 110
SF_0000000555_RDNAU_58_10293    70582   71504   -       ID=match45147;Target=SF_0000000350 8970 9886 916
SF_0000000555_RDNAU_58_10293    100212  101204  -       ID=match45148;Target=SF_0000000350 9584 10597 1013
SF_0000000555_RDNAU_58_10293    101165  101747  -       ID=match45149;Target=SF_0000000350 9005 9581 576
SF_0000000555_RDNAU_58_10293    82434   82891   -       ID=match45150;Target=SF_0000000350 9273 9730 457

我想要如下所示的输出

SF_0000000555   10873   11041   +       SF_0000000005 99 267 168
SF_0000000555   188079  188215  +       SF_0000000020 3 138 135
SF_0000000555   137594  137704  -       SF_0000000048 16 126 110
SF_0000000555   70582   71504   -       SF_0000000350 8970 9886 916
SF_0000000555   100212  101204  -       SF_0000000350 9584 10597 1013
SF_0000000555   101165  101747  -       SF_0000000350 9005 9581 576
SF_0000000555   82434   82891   -       SF_0000000350 9273 9730 457

您能否让我知道如何使用 awk 或 perl 就地编辑文件。我尝试使用 cut 命令来编辑每个单独的列,并尝试使用以下命令将它们合并在一起。

awk '{print $1}' |cut -d "_" -f 1-2
awk '{print $5}' |cut -d ";" -f 2- | cut -d "=" -f 2

提前致谢。

答案1

对于就地编辑,按照以下方式做一些事情可能会更容易

sed -i "s/\t/ /g" file.txt \
&& sed -i "s/ID=match[[:digit:]]\+;Target=//g" test.txt \
&& sed -i "s/_RDNAU_[[:digit:]]\+_[[:digit:]]\+//g" test.txt

有点蛮力,但要容易得多。

答案2

$ awk 'BEGIN{FS=OFS="\t"} {sub(/(_[^_]+){3}$/,"",$1); sub(/.*=/,"",$5)}1' file
SF_0000000555   10873   11041   +       SF_0000000005   99      267     168
SF_0000000555   188079  188215  +       SF_0000000020   3       138     135
SF_0000000555   137594  137704  -       SF_0000000048   16      126     110
SF_0000000555   70582   71504   -       SF_0000000350   8970    9886    916
SF_0000000555   100212  101204  -       SF_0000000350   9584    10597   1013
SF_0000000555   101165  101747  -       SF_0000000350   9005    9581    576
SF_0000000555   82434   82891   -       SF_0000000350   9273    9730    457

使用 GNU awk,您可以添加-i inplace“就地”编辑,就像 sed 和 perl 那样-i。对于任何 awk,您当然可以awk 'script' file > tmp && mv tmp file像使用任何其他命令一样执行操作。

答案3

尝试这个:

awk -v FS='\t' -v OFS='\t' '{
    split($1, a, "_"); $1 = a[1]"_"a[2];
    sub(/.*=/, "", $5);
    print
}' input > output

这假设原始文件中的空格实际上是制表符;如果不是这种情况,您可以删除这些-v..选项。

如果k1=v1;k2=v2;...第五个字段中的 可以按任何顺序,或者如果Target=SF..可能不是最后一个,则需要更复杂的东西,但很难从可用信息中猜测什么。

如果您想“就地”编辑文件,请重命名为原始文件:

awk '...' input > tmpfile && mv tmpfile input

答案4

在 Perl 中:

#!/usr/bin/perl

use feature 'say';

while(<>) {
  chomp;                            # strip the trailing end-of-line character(s).
  my (@F) = split;                  # split the input line into fields

  $F[0] =~ s/(^[^_]*_[^_]*)_.*/$1/; # strip everything from 2nd _ from field 1
  $F[4] =~ s/^ID=[^;]*;Target=//;   # strip from ID= to Target= from field 5

  say join("\t",@F);                # print all the fields separated by a tab.
}

如果你想把它作为一句台词:

perl -lane '$F[0] =~ s/(^[^_]*_[^_]*)_.*/$1/;
            $F[4] =~ s/^ID=[^;]*;Target=//;
            print join("\t",@F);' input.txt

perl 的-l选项打开自动行结束处理(chomp)。-a打开类似 awk 的自动字段分割(到 array @F)。 -a也隐式打开-n(自动while(<>){ .. }在 perl 代码周围放置一个循环),但我喜欢显式指定此选项。man perlrun详情请参阅。

请注意,perl 数组从 0 开始,而不是从 1 开始。

示例输出(来自独立版本或单行版本):

SF_0000000555   10873   11041   +       SF_0000000005   99      267     168
SF_0000000555   188079  188215  +       SF_0000000020   3       138     135
SF_0000000555   137594  137704  -       SF_0000000048   16      126     110
SF_0000000555   70582   71504   -       SF_0000000350   8970    9886    916
SF_0000000555   100212  101204  -       SF_0000000350   9584    10597   1013
SF_0000000555   101165  101747  -       SF_0000000350   9005    9581    576
SF_0000000555   82434   82891   -       SF_0000000350   9273    9730    457

相关内容