从无尽的管道上读取

时间:2015-11-02 21:46:17

标签: linux bash pipe

我想创建一个脚本,为第一个接收管道的每一行运行另一个脚本。 像这样:

journalctl -f | myScript1.sh

这个myScript1.sh会运行另一个这样的:

./myScript2.sh $line_in_pipe

我发现的问题是我测试的每个代码都在有限的管道中运行良好(直到EOF)。 但是,当我管道像tail -f或其他人的程序时,它只是不会执行。我认为只是等待EOF执行循环。

编辑: 无尽的管道是这样的:

tail -f /var/log/apache2/access.log | grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | script_ip_check.sh

所以script_ip_check.sh上的想法是这样的:

#!/bin/bash

for line in $(cat); do
        echo "process:$line"
        nmap -sV -p1234 --open -T4 $line | grep 'open' -B3 | grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' >> list_of_ip_mapped &
done

对于每一行,本例IP,我将生成一个nmap线程来扫描该主机上的特殊内容。 我将用它来扫描试图连接某些"隐藏"的IP。我服务器上的端口。 所以我的脚本必须一直运行,直到我取消它或收到EOF。

EDIT2: 我刚刚发现grep刷新了缓冲区,这就是为什么它无法正常工作。 我使用--line-buffered强制grep输出每一行,因为它正在处理中。

1 个答案:

答案 0 :(得分:3)

我们不能在不知道你的剧本中有什么的情况下明确地说。

例如,如果您这样做:

# DON'T DO THIS: Violates http://mywiki.wooledge.org/DontReadLinesWithFor
for line in $(cat); do
  : ...do something with "$line"...
done

...等待所有标准输入可用,导致您描述的挂起。

但是,如果您遵循最佳做法(每BashFAQ #1),您的代码将更像这样:

while IFS= read -r line; do
  : ...do something with "$line"
done

......并且实际上表现得很好,受制作者执行的任何缓冲。有关控制缓冲的提示,请参阅BashFAQ #9

最后,引用DontReadLinesWithFor

  

使用for读取行的最后一个问题是效率低下。 while read循环从输入流一次读取一行; $(<afile)将整个文件一次性打入内存。对于小文件,这不是问题,但如果您正在阅读大文件,则内存需求将是巨大的。 (Bash必须分配一个字符串来保存文件,另一组字符串用于保存分词结果......实际上,分配的内存将是输入文件大小的两倍。)

显然,如果内容不确定,内存要求和完成时间也是如此。