Scripting 如何使用sed或awk删除符合特定字段条件的行?

Scripting 如何使用sed或awk删除符合特定字段条件的行?,scripting,sed,awk,Scripting,Sed,Awk,我有以下数据: 1 abc xyz - - 2 mno 2 lnm dse - - 3 pqr 3 ebe aaa xhd asw 4 pow 4 abc fww wrw ffp 3 ffw 我想删除满足以下两个条件的行: 第4列和第5列为空 对应行的行号不包含在任何其他行的第6列中 在这种情况下,应删除第1行。在这种情况下,如何使用sed/awk或最合适的脚本语言执行此操作。使用perl的

我有以下数据:

 1  abc    xyz   -    -    2   mno
 2  lnm    dse   -    -    3   pqr
 3  ebe    aaa   xhd  asw  4   pow
 4  abc    fww   wrw  ffp  3   ffw
我想删除满足以下两个条件的行:

  • 第4列和第5列为空
  • 对应行的行号不包含在任何其他行的第6列中

  • 在这种情况下,应删除第1行。在这种情况下,如何使用sed/awk或最合适的脚本语言执行此操作。

    使用
    perl
    的可能解决方案:

    script.pl的内容:

    use warnings;
    use strict;
    
    ## Accept one argument, the input file.
    @ARGV == 1 or die qq[Usage: perl $0 input-file\n];
    
    my ($lines, %hash);
    
    ## Process file.
    while ( <> ) {
            ## Remove leading and trailing spaces for each line.
            s/^\s*//;
            s/\s*$//;
    
            ## Get both indexes.
            my ($idx1, $idx2) = (split)[0,5];
    
            ## Save line and index1.
            push @{$lines}, [$_, $idx1];
    
            ## Save index2.
            $hash{ $idx2 } = 1;
    }
    
    ## Process file for second time.
    for ( @{$lines} ) {
    
            ## Get fields of the line.
            my @f = split /\s+/, $_->[0];
    
            ## If fourth and fifth fields are empty (-) and first index exists as second 
            ## index, go to next line without printing.
            if ( $f[3] eq qq[-] && $f[4] eq qq[-] && ! exists $hash{ $_->[1] } ) {
                    next;
            }
    
            ## Print line.
            printf qq[%s\n], $_->[0];
    }
    
    结果:

    2  lnm    dse   -    -    3   pqr
    3  ebe    aaa   xhd  asw  4   pow
    4  abc    fww   wrw  ffp  3   ffw
    

    也许像这样的事情可以奏效-

    awk 'NR==FNR{a[$6];next} 
    ($4 ~ /[- ]/ && $5 ~ /[- ]/) && !($1 in a){next}1' file file
    
    条件: 如果
    第4列和第5列为空,并且
    第6列中没有索引,我们将跳过该行并打印其他所有内容

    说明: 我们使用
    NR
    FNR
    内置变量,并将同一文件传递两次。在第一次运行中,我们扫描文件并将
    列6
    存储在一个数组中
    next
    用于防止第二个
    pattern{action}
    语句在读取第一个文件之前运行。一旦文件被完全读取,我们将根据您的条件测试同一文件。如果第4列和第5列为空,我们查看索引,如果它不在数组中,则使用
    next
    跳过该行,否则我们将打印它

    测试:
    这可能适合您:

    sed -rn 's/^.*(\S+)\s+\S+$/\1/;H;${x;s/^|\n/:/gp}' file | 
    sed -r '1{h;d};/^(\s*\S*){3}\s*-\s*-/{G;/^\s*(\S*).*:\1:/!d;s/\n.*//}' - file
     2  lnm    dse   -    -    3   pqr
     3  ebe    aaa   xhd  asw  4   pow
     4  abc    fww   wrw  ffp  3   ffw
    
    说明:

  • 读取该文件并从第6列构建一个查找表,该列由
    分隔:
  • 将表格(第一行)读入保持空间(HS),然后再次读取文件
  • 当第5列和第6列仅包含
    -

    • 将查找表追加到模式空间(PS)

    • 使用第一列作为键进行查找,如果失败,则删除该列 线路

    • 对于所有剩余的行,删除查找表


  • 问题的标题是问一些与问题正文正交的问题。根据您的两个标准,应删除示例中的前两行,因为第一列和第六列都不相等。第一个和第二个要求之间的关系是“和”“不”“或”。根据您更新的示例,为什么第2行没有被删除?第4和第5个字段均为“空白”,其“索引值”为2(如果不包含在第6列中)(3)第2行不会被删除,因为其索引2包含在第一行的第6列中。谢谢SiegeX.)圣诞快乐!!实际上,有一个逻辑错误。第二个条件应该是逻辑OR,因为您否定了匹配项
    ($4!~/[-]/| |$5!~/[-]/)
    ,所以我更正了它。而且,我意识到不需要为数组编制索引。简单的
    a[$6]+
    就足够了。谢谢!:)我读了OP最后的评论。已经修改了
    awk
    的第二部分。实际上,您甚至不需要增加它,只要
    a[$6]
    就足够了。当我意识到我需要查看两次文件后,我正在重做我的答案,但我使用的是END{},它太长了,我知道必须有更好的方法。将同一个文件传递两次并使用
    NR==FNR
    绝对是更好的方法。看来你今天键盘玩得不好
    [jaypal:~/Temp] cat file
     1  abc    xyz   -    -    2   mno
     2  lnm    dse   -    -    3   pqr
     3  ebe    aaa   xhd  asw  4   pow
     4  abc    fww   wrw  ffp  3   ffw
    
    [jaypal:~/Temp] awk 'NR==FNR{a[$6];next} ($4 ~ /[- ]/ && $5 ~ /[- ]/) && !($1 in a){next}1' file file
     2  lnm    dse   -    -    3   pqr
     3  ebe    aaa   xhd  asw  4   pow
     4  abc    fww   wrw  ffp  3   ffw
    
    sed -rn 's/^.*(\S+)\s+\S+$/\1/;H;${x;s/^|\n/:/gp}' file | 
    sed -r '1{h;d};/^(\s*\S*){3}\s*-\s*-/{G;/^\s*(\S*).*:\1:/!d;s/\n.*//}' - file
     2  lnm    dse   -    -    3   pqr
     3  ebe    aaa   xhd  asw  4   pow
     4  abc    fww   wrw  ffp  3   ffw