【问题标题】:Read from a endless pipe bash [duplicate]从无尽的管道bash中读取[重复]
【发布时间】:2016-02-02 22:10:25
【问题描述】:

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

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 输出正在处理的每一行。

【问题讨论】:

  • 不太可能它根本不运行。它更有可能在做任何事情之前等待一个完整的缓冲区。
  • 另见 BashFAQ #9:mywiki.wooledge.org/BashFAQ/009
  • ...但是,要确定而不是“可能”和“不太可能”,我们​​需要一个完整的复制器。
  • 请出示myScript1.sh的代码。
  • 是的。 for line in $(cat) 在执行任何操作之前明确收集所有输出。你根本不应该使用那个习语——请参阅mywiki.wooledge.org/DontReadLinesWithFor——但尤其是在从非终止输入流中读取时不应该这样做。

标签: linux bash pipe


【解决方案1】:

如果不知道您的脚本中的内容,我们无法确定。

例如,如果你这样做:

# 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 将必须分配一个字符串来保存文件,并分配另一组字符串来保存分词结果......本质上,分配的内存将是输入文件大小的两倍。)

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-01-26
    • 2018-10-28
    • 1970-01-01
    • 2019-11-18
    • 2010-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多