![使用另一个命令的输出过滤文件](https://linux22.com/image/178180/%E4%BD%BF%E7%94%A8%E5%8F%A6%E4%B8%80%E4%B8%AA%E5%91%BD%E4%BB%A4%E7%9A%84%E8%BE%93%E5%87%BA%E8%BF%87%E6%BB%A4%E6%96%87%E4%BB%B6.png)
我有一个外部命令,比如说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
开头,然后打印其编号在该哈希表中的行。YES
yes
myfile
yes
答案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