Bash 如何缓冲和批量处理tail-f输出?

Bash 如何缓冲和批量处理tail-f输出?,bash,Bash,我需要监视一个文件,并将写入该文件的内容发送到web服务。我正试图通过bash脚本实现一个干净、简单的解决方案,例如: #!/bin/bash # listen for changes on file specified as first argument tail -F "$1" | while read LINE do curl http://service.com/endpoint --data "${LINE}" done 这非常有效,如。。附加的每一行都将被发送到。 然而,我并

我需要监视一个文件,并将写入该文件的内容发送到web服务。我正试图通过bash脚本实现一个干净、简单的解决方案,例如:

#!/bin/bash

# listen for changes on file specified as first argument
tail -F "$1" | while read LINE
do
  curl http://service.com/endpoint --data "${LINE}"
done
这非常有效,如。。附加的每一行都将被发送到。 然而,我并不喜欢这样一个事实,即如果在短时间内追加许多行,我将有同样多的HTTP请求,并且可能会使服务过载

有没有一种聪明的方法来缓冲操作?我能想到这样的事情:

buffer = EMPTY
while LINES are read:
  add LINE to buffer
  if buffer has more than X LINES
    send POST
  fi
done
但是在上面的解决方案中,如果每小时发布一行,我只会每X小时更新一次,这是不可接受的。另一个类似的解决方案是在while循环中“time”:
如果X秒已经过去,则发送缓冲区,否则等待。。但是流的最后一行可能会无限期保留,因为while循环只有在向文件添加新行时才会触发

目标是使用最少的bash脚本和而不使用第二个进程来实现这一点。所谓第二个进程,我的意思是:
进程1从tail-f获取输出并存储它
进程2定期检查存储的内容,如果超过x秒,则发送POST

我很好奇,这是不是有什么巧妙的办法


谢谢

从字面上说,将伪代码转换为代码:

# add stdbuf -oL if you care
tail -F "$1" | {
    # buffer = EMPTY
    buffer=
    # while LINES are read:
    while IFS= read -r line; do
      # add LINE to buffer
      buffer+="$line"$'\n'
      # if buffer has more than X LINES
      # TODO: cache the count of lines in a variable to save cpu
      if [ $(wc -l <<<"$buffer") -gt "$x_lines" ]; then
          # send POST
          # TODO: remove additional newline on the end of buffer, if needed
          curl http://service.com/endpoint --data "${buffer}"
          buffer=
      fi
    done
}
多亏了他的回答,我以一种相当简单的方式实现了我想要的,结合了最大行数和超时。诀窍是发现管道不一定按线路工作,就像我想的那样……我真傻

仅供将来参考,这是我的解决方案,非常具体,并简化到骨骼:

#!/bin/bash
# sends updates to $1 via curl every 15 seconds or every 100 lines
tail -F "$1" | while true; do

    chunk=""
    stop=$((`date +%s` + 15))
    maxlines=100

    while true; do

        if (( `date +%s` >= stop )); then break; fi

        IFS= read -r -t 15 line && ret=$? || ret=$?         
        if (( ret == 0 )); then

                chunk+=$line$'\n'
                maxlines=$((maxlines - 1))
                if (( maxlines == 0 )); then break; fi

        elif (( ret > 128 )); then break; fi

    done

    if (( ${#chunk} != 0 )); then
        curl http://service.com --data "$chunk";
    fi

done

非常感谢,我将看一看您编写的ratelimit.sh脚本,并充分利用它!我认为我的伪代码中提供的解决方案是缺乏的,因为如果只添加x-1行,并且我们有一个x的缓冲区,它们将永远不会被发送!你说得对,需要一条线和一个超时!
#!/bin/bash
# sends updates to $1 via curl every 15 seconds or every 100 lines
tail -F "$1" | while true; do

    chunk=""
    stop=$((`date +%s` + 15))
    maxlines=100

    while true; do

        if (( `date +%s` >= stop )); then break; fi

        IFS= read -r -t 15 line && ret=$? || ret=$?         
        if (( ret == 0 )); then

                chunk+=$line$'\n'
                maxlines=$((maxlines - 1))
                if (( maxlines == 0 )); then break; fi

        elif (( ret > 128 )); then break; fi

    done

    if (( ${#chunk} != 0 )); then
        curl http://service.com --data "$chunk";
    fi

done