如何在一个流中传递多个文件,以便在接收端像管道一样处理它们(不保存)?

如何在一个流中传递多个文件,以便在接收端像管道一样处理它们(不保存)?

我需要确定来自 stdin 的不确定数量的 Base64 编码文件流(图像文件 Base64 编码和 cat'ed)的文件类型。

单个文件就是... | base64 -d | identify -.

多个文件的问题是确定流中每个文件的 EOF。即使我在将文件\004发送到 stdout 之前将它们分开,管道的接收端(identifyfile等)似乎无法识别流中存在多个文件(是的,我知道流是文件,但我希望 en EOF 中流能够以某种方式,对于“某种方式”的各种值,起作用。

我尝试过循环读取标准输入while read REPLY,但read它是基于行的,而不是基于文件的,所以似乎无法按我想要的方式工作。

[稍后编辑] 有 3-10 个文件均小于 400KB,因此大小和处理对于我的用例来说不是问题,但我总体上对这个问题感兴趣。

[eidt,稍后]我试图避免使用 tmp 文件(这是我当前的解决方案),主要是因为我在哲学上反对在进程间流效率更高时使用文件系统作为两个相邻进程之间的缓冲区。我知道这听起来很浮夸,所以对于现在需要工作的解决方案,我当然使用 tmp 文件。然而,我意识到我的知识存在差距,我正在努力寻找一般情况的答案。

答案1

即使我在将文件\004发送到之前将它们分开stdout...

好消息是您可以修改发送过程。我的解决方案如下:

for f in *.jpg; do echo S; base64 "$f"; echo ""; done |
# the above is just an example sending process
while read dummy; do
  sed -u '/^$/q' | base64 -d | identify -
done

澄清:

  • 单个“文件块”以不携带数据的消耗行(本例中为“S”)开头。如果read找不到一行,则整个命令结束。
  • sed将数据传递到解码器,直到出现空行(注意:额外的空行不会更改 的输出base64 -d)。
  • sed使用无缓冲(-u标志)至关重要;否则,人们sed可能会读得太多,并最终丢弃它认为过多的数据;那么下一个sed(因此下一个identify)将无法获得应有的所有数据。

提示:

  • 额外的行可以携带元数据而不是“S”,例如文件名等(但要注意名称中的换行符等)。
  • 由于base64产生的输出大于输入,因此您可能需要gzip在两侧使用,特别是当您的流通过互联网传输时。

答案2

while read如果您将输入通过管道传输并将分隔符设置为\004(使用$'...'扩展,因为read不解释反斜杠转义),它会起作用

for x in *.jpg ; do base64 < "$x" ; echo -e '\004';  done | 
    while read -rd $'\004' file ; do 
        echo "$file" | base64 -d | identify - 
    done

不过,对于较大的文件来说,速度非常慢,因为 shell 无法知道循环内的某些内容是否要读取管道,因此read需要逐字节读取。这可能应该用 Perl 或其他一些实际的编程语言来实现,以便可以准确地控制缓冲。

相关内容