【问题标题】:Asynchronously consuming pipe with bash使用 bash 异步消费管道
【发布时间】:2014-09-24 14:39:56
【问题描述】:

我有一个这样的 bash 脚本

data_generator_that_never_guits | while read data 
do
 an_expensive_process_with data
done

第一个进程连续生成事件(以不规则的时间间隔),当它们可用时需要对其进行处理。这个脚本的一个问题是 read on 会消耗一行输出;并且由于处理非常昂贵,我希望它消耗当前可用的所有数据。另一方面,如果有新数据可用,则必须立即开始处理。简而言之,我想做这样的事情

data_generator_that_never_guits | while read_all_available data 
do
 an_expensive_process_with data
done

如果没有数据可供消费,命令 read_all_available 将等待,或者将所有当前可用的数据复制到变量中。如果数据不包含完整的行,那很好。基本上,我正在寻找读取的模拟,它将读取整个管道缓冲区,而不是从管道中读取一行。

对于你们中间的好奇,我有一个构建脚本需要在源文件更改时触发重建的问题的背景。我想避免过于频繁地触发重建。请不要建议我使用 grunt、gulp 或其他可用的构建系统,它们不适合我的目的。

谢谢!

【问题讨论】:

    标签: shell pipe producer-consumer


    【解决方案1】:

    我想在我更好地了解 subshel​​l 的工作原理后,我找到了解决方案。这个脚本似乎可以满足我的需要:

    data_generator_that_never_guits | while true 
    do
     # wait until next element becomes available
     read LINE
     # consume any remaining elements — a small timeout ensures that 
     # rapidly fired events are batched together
     while read -t 1 LINE; do true; done
     # the data buffer is empty, launch the process
     an_expensive_process
    done
    

    可以将所有读取的行收集到一个批次中,但我现在并不真正关心它们的内容,所以我没有费心去弄清楚那部分:)

    添加于 25.09.2014

    这是一个最终的子程序,以防有一天它对某人有用:

    flushpipe() {
     # wait until the next line becomes available
     read -d "" buffer
     # consume any remaining elements — a small timeout ensures that 
      # rapidly fired events are batched together
     while read -d "" -t 1 line; do buffer="$buffer\n$line"; done
     echo $buffer   
    }
    

    这样使用:

    data_generator_that_never_guits | while true 
    do
     # wait until data becomes available
     data=$(flushpipe)
     # the data buffer is empty, launch the process
     an_expensive_process_with data
    done
    

    【讨论】:

      【解决方案2】:

      read -N 4096 -t 1 这样的东西可能会起作用,或者read -t 0 可能会加上额外的逻辑。有关详细信息,请参阅 Bash 参考手册。否则,您可能必须从 Bash 转移到例如Perl。

      【讨论】:

      • 感谢您的回答,塞巴斯蒂安。不过,我不太确定这在我的情况下应该如何工作。我的印象是,如果没有产生输入,读取将失败,终止循环?在任何情况下,我都想等待输入(如果必须的话,可以无限期地等待)。只是我想在出现一些数据后清除整个管道。我已经有一个运行良好的 Python 版本,但是它过于冗长和繁琐,因为它必须执行一堆 shell 命令。
      猜你喜欢
      • 2023-03-29
      • 1970-01-01
      • 1970-01-01
      • 2019-05-06
      • 2020-03-02
      • 2017-09-09
      • 2016-02-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多