需要根据文件其他列中的值替换文件的特定列值

时间:2013-09-24 19:23:38

标签: perl shell unix nawk

以下是我的文件内容,以下是我的要求 基于第1列和第5列的值,我想将第7列中的值替换为“1”。

例如:

  1. 如果第1列=“更改”且第5列=“延迟”,则将第7列中的值替换为“1”。
  2. 如果第1列=“更改”且第5列=“defererence”,则将第7列中的值替换为“1”。
  3. 否则不要对行做任何事情,保持原样。
  4. 输入文件:

    Change|sinmg|1234|ewfew|def|fdfd|JAMES|rewr|ROBERT|3|fe
    Change|sinmg|2345|ewfew|defer|VENKTRAAAMMAMAMAMMAMA|3|rewr|BEAEY|3|
    noChange|sinmg|2323|ewfew|def|VENKTRAAAMMAMAMAMMAMA|3|rewr|BEAEY|3|fe
    Change|sinmg|3456|ewfew|defer|VENKTRAAAMMAMAMAMMAMA|3|rewr|BEAEY|3|
    Change|sinmg|2345|ewfew|defererence|VENKTRAAAMMAMAMAMMAMA|3|rewr|BEAEY|3|
    

    上面只是一个示例,使其更容易解释。但是,我想从文件传递第1列和第5列的值以匹配文件中的值。如果它匹配,那么只用值“1”替换第7列,否则不要对行做任何事情,保持原样。

    我尝试了几种选择,但未能达到所需的效果。

    perl -F'\|' -i -lape  'if ($F[0] eq "change" && $F[4] eq "defer") { s/$F[6]/1/g;}' file_name
    

    以上命令正在替换文件中3的所有值,而不考虑字段。但我想通过将不同的值传递给循环中的第1列和第4列,仅基于第1列和第4列替换第6列值。

    添加更多信息:

    正如我上面提到的,上面的例子只是我问题的最简单形式,让每个人都能理解这个要求。我有一个名为“listfile”的文件,其中包含第1列和第5列的值列表以进行匹配。如果源文件中第1列和第5列中的值与从文件“listfile”传递的值匹配,则解决方案应将第7列中的值替换为“1”。否则不要对源文件中的行执行任何操作,保持原样。

    我尝试在下面做,但无法达到要求。

        #!/usr/bin/ksh
        for line in $(cat dir/listfile)
        do
        VAR1=$(echo $line | nawk -F"|" '{print $1}')
        VAR2=$(echo $line | nawk -F"|" '{print $2}')
        nawk -F"|" 'BEGIN {OFS="|"} {if($1!="'"$VAR1"'" && $5!="'"$VAR2"'") {$8="1"; print $0;}      else {print $0;}}' dir/sourcefile >> dir/sourcefile_REVISED
        done
    

    替换No no 7后原始源文件和修订源文件之间的记录数不应相同。唯一的事情是文件列表文件中的第1列和第5列的所有值,我需要将第7列的值替换为“1”。

    谢谢,

6 个答案:

答案 0 :(得分:1)

您可以使用awk执行此操作。

awk -F'|' 'BEGIN{OFS="|"}{if($1=="Change"&&$5=="defer"){$7=1}{print}}' file

我意识到你还需要第5列来匹配“不同”...以下应该有效:

awk -F'|' 'BEGIN{OFS="|"}{if($1=="Change"&&$5=="defer"||$5=="defererence"){$7=1}{print}}' file

答案 1 :(得分:1)

perl -F'\|' -i -lape '
  BEGIN{ $" = "|" }
  $F[6]=1, $_="@F" if $F[0] eq "Change" && $F[4] =~ /^defer(erence)?$/;
' listfile

答案 2 :(得分:0)

替换运算符s///不理解数据列的概念,它只对给定的字符串进行操作。在这种情况下,由于g修饰符,您将替换输入行中出现的第7列到处中的任何内容。

@imauser的答案中的awk解决方案是一个很好的解决方案。

答案 3 :(得分:0)

使用awk,您可以:

$ awk '$1=="Change"&&$5~/^defer(erence)?$/{$7=1}1' FS='|' OFS='|' file
Change|sinmg|1234|ewfew|def|fdfd|JAMES|rewr|ROBERT|3|fe
Change|sinmg|2345|ewfew|defer|VENKTRAAAMMAMAMAMMAMA|1|rewr|BEAEY|3|
noChange|sinmg|2323|ewfew|def|VENKTRAAAMMAMAMAMMAMA|3|rewr|BEAEY|3|fe
Change|sinmg|3456|ewfew|defer|VENKTRAAAMMAMAMAMMAMA|1|rewr|BEAEY|3|
Change|sinmg|2345|ewfew|defererence|VENKTRAAAMMAMAMAMMAMA|1|rewr|BEAEY|

答案 4 :(得分:0)

在替换之前,您仍然可以通过“跳过”前六个字段来使用perl + regexp解决方案:

perl -F'\|' -i -lapE  'if ($F[0] eq "change" && $F[4] =~ m{^defer(erence)?$}) { s{^(?:[^|]*\|){6}\K([^|]*)}{1} }' file_name

优于awk解决方案的优势:您仍然可以在此使用-i开关。

答案 5 :(得分:0)

您可以使用split脚本中的joinperl完成此操作,如下所示:

#!/usr/bin/perl
use warnings;
use strict;

my $infile = "dir/sourcefile";
my $listfile = "dir/listfile";
my $outfile = "dir/sourcefile_REVISED";

my @list;
open LFOPEN, $listfile or die $!;
while (<LFOPEN>) {
    chomp;
    my @col = split /\|/, $_;
    push @list, \@col;
}
close LFOPEN;

open IFOPEN, $infile or die $!;
open OFOPEN, '>', $outfile or die $!;
while (<IFOPEN>) {
    chomp;
    my @col = split /\|/, $_;
    foreach my $lref (@list) {
        $col[6] = '1' if ($col[0] eq $lref->[0] and $col[4] eq $lref->[1]);
    }
    print OFOPEN join ('|', @col) . "\n";
}
close IFOPEN;
close OFOPEN;

输入(dir / sourcefile):

Change|sinmg|1234|ewfew|def|fdfd|JAMES|rewr|ROBERT|3|fe
Change|sinmg|2345|ewfew|defer|VENKTRAAAMMAMAMAMMAMA|3|rewr|BEAEY|3|
noChange|sinmg|2323|ewfew|def|VENKTRAAAMMAMAMAMMAMA|3|rewr|BEAEY|3|fe
Change|sinmg|3456|ewfew|defer|VENKTRAAAMMAMAMAMMAMA|3|rewr|BEAEY|3|
Change|sinmg|2345|ewfew|defererence|VENKTRAAAMMAMAMAMMAMA|3|rewr|BEAEY|3|

列表(目录/列表文件):

Change|defer
Change|defererence

输出(dir / sourcefile_REVISED):

Change|sinmg|1234|ewfew|def|fdfd|JAMES|rewr|ROBERT|3|fe
Change|sinmg|2345|ewfew|defer|VENKTRAAAMMAMAMAMMAMA|1|rewr|BEAEY|3
noChange|sinmg|2323|ewfew|def|VENKTRAAAMMAMAMAMMAMA|3|rewr|BEAEY|3|fe
Change|sinmg|3456|ewfew|defer|VENKTRAAAMMAMAMAMMAMA|1|rewr|BEAEY|3
Change|sinmg|2345|ewfew|defererence|VENKTRAAAMMAMAMAMMAMA|1|rewr|BEAEY|3