使用另一个命令的输出过滤文件

使用另一个命令的输出过滤文件

我有一个外部命令,比如说check_this,它会针对通过管道传输到它的文件输出 YES 或 NO

cat myfile | check_this

YES
NO
YES
YES
...

现在我想获取 myfile 中结果为 YES 的所有行。有没有办法做到这一点?目前我使用临时文件,将其保存到另一个文件,然后使用粘贴+ grep,这很麻烦而且不健壮。

答案1

我会用awk

<myfile check_this | awk '
  !check_processed {if ($1 == "YES") yes[FNR]; next}
  FNR in yes' - check_processed=1 myfile

awk记录 的输出的哪些行号以哈希表中的单词check_this开头,然后打印其编号在该哈希表中的行。YESyesmyfileyes

答案2

我们可以利用该GNU版本直流电基本上实现grep -f功能的实用程序。

dc -e "
$(< myfile check_this | sed -e 's/NO/0/;s/YES/1/' | tac)
[q]sq [p]sp [?z0=qr1=psxz0<?]s?
l?x
" < <(< myfile sed -e 's/.*/[&]/')
  • 第一步,我们加载check_this实用程序的输出,进行适当的布尔化(YES=>1,NO=>0),然后推入堆栈。读取输入文件中的下一行并将其压入堆栈。如果第二个堆栈元素是 1,则打印它。

  • 然后我们清除栈顶的 2 个元素。重复直到 eof。

答案3

GNU awk 又名 gawk+paste:

$ < myfile check_this \
   | paste myfile -      \
   | gawk '/YES$/ && NF--';
$ < myfile check_this \
    |  perl -lpe '
      @ARGV && do{
        /YES/ && $h{$.}++;
        eof && close(ARGV);
        next;
       };
        print if $h{$.};
  ' - myfile

GNU sed模式extended regex开启时:

$ < myfile check_this |
    sed -nE '
        1{:a;H;n;/^(YES|NO)$/ba;}
        G;/\n\nYES/P
        s/.*\n\n(YES|NO)/\n/;h
    ' - myfile

将 check_this 输出存储在hold中,并fir myfile的每一行确定hold的主值为yes。然后打印 myfile 行。从模式空间中剪辑前两个元素并将模式重新存储(请注意,不是“恢复”)到保留空间中。

答案4

@StéphaneChazelas 的完美awk解决方案的一个变体,不太紧凑,但可能更容易阅读,因为它不诉诸外部变量(check_processed用他的表示法),将是:

$ awk 'FNR == NR {if ($1 == "YES") yes[FNR];next} 
       FNR != NR && FNR in yes'   <(check_this <myfile) myfile

笔记:@RakeshSharma 评论说同时使用next(第一行)和测试FNR != NR(第二行)是多余的。该模式的用户可以删除其中之一而不改变输出,如下所示:

$ awk 'FNR == NR {if ($1 == "YES") yes[FNR];next} 
       FNR in yes'   <(check_this <myfile) myfile

相关内容