如何将数据从一个命令传输到另一只允许文件作为参数的命令?

如何将数据从一个命令传输到另一只允许文件作为参数的命令?

我有一些任意数据作为命令的输出(例如使用输出的二进制数据的片段tail)。我想将它提供给另一个命令/程序,该命令/程序只允许一个文件作为参数(例如rawtopng [filein] [fileout]),不支持破折号(-)参数,并且我无法在两者之间创建临时文件。我怎样才能在 bash 中做到这一点?

会做类似rawtopng <(tail myfile) fileout工作的事情吗?

答案1

进程替换rawtopng <(tail myfile) fileout创建一个管道(就像tail myfile | rawtopng - fileout),并将管道的名称传递给程序。在 Linux 上,rawtopng会看到类似 的名称/dev/fd/42,如果它查询文件类型,则会被告知它是一个管道。不需要写入文件系统(这是匿名管道,而不是命名管道)。您可以通过运行如下命令来了解正在发生的情况ls -ld <(echo foo)

这行得通吗?这取决于rawtopng命令需要什么(我不知道,我不熟悉该命令)。如果它所做的只是从文件中读取,那就没问题。如果它需要在文件中查找(即,如果它没有从头到尾线性地读取输入),或者如果它需要在开始工作之前知道输入的大小,那么这是行不通的。在这种情况下,您将需要一个临时文件。

如果命令需要可查找的输入或预先知道大小的输入,那么您别无选择,您需要创建一个临时文件。如果您想避免写入磁盘,您可以安排将文件放在tmpfs文件系统上,如果您的 Unix 变体提供了该功能(Linux 提供了)。您可以使用以下mktemp命令创建临时文件:

tmp=$(TMPDIR=/tmp mktemp XXXXXXXXXXXX.raw)
rawtopng "$tmp" fileout
rm "$tmp"

在 zsh 中,进程替换变体会rawtopng =(tail myfile) fileout创建一个临时文件,并在命令完成后将其删除。

进程替换无法解决的另一种情况是,如果程序坚持使用具有特定扩展名的文件。在这种情况下,创建命名管道可能会有所帮助:

mkfifo /tmp/foo.raw
tail myfile >/tmp/foo.raw &
rawtopng /tmp/foo.raw fileout
rm /tmp/foo.raw

答案2

我认为你走在正确的道路上!<(tail myfile)将创建一个匿名命名管道,并且是 Bash 的一种类型流程替代

通常,这将/dev/fd/XX作为“文件名”传递,它是正在运行的进程的文件描述符接口。

从链接文档中的示例:

bash$ wc <(cat /usr/share/dict/linux.words)
 483523  483523 4992010 /dev/fd/63

要从进程读取,请使用<(command),要写入进程,请使用>(command)

您可以阅读有关流程替代的更多信息在维基百科上以及。

答案3

您可以创建命名管道。

做一些类似mkfifo input创建管道的事情。

启动您想要读取输出的程序,并将输出重定向到管道,又名myprog > input

然后使用输入作为文件运行其他命令。

请注意,管道是单向的。该程序将能够读取,但不能写入。

相关内容