临时数据的伪文件


98

我经常想将相对较短的字符串数据(尽管可能是几行)馈送到命令行程序,这些程序仅以重复的方式接受来自文件(例如wdiff)的输入。当然,我可以创建一个或多个临时文件,将字符串保存在那里,然后以文件名作为参数运行命令。但是在我看来,如果将数据实际写入磁盘,此过程似乎效率很低,而且如果我多次重复此过程(例如,如果我要馈送一行长文本),则对磁盘的损害可能超过必要。文件到wdiff。有没有建议的方法来避免这种情况,例如使用伪文件(例如管道)来临时存储数据,而无需实际将其写入磁盘(或仅在超过临界长度时才将其写入)。请注意,wdiff具有两个参数,并且,wdiff <"text"


可以通过解决xargs吗?
NN

不知道,但是对我来说,怎么做并不明显。据我了解,xargs将从命令的文件字符串参数中输入行。但我需要相反。
highsciguy

@rahmu我看了一下,但是我认为那里的问题设置有些不同。至少我看不出答案会有什么帮助。我不希望避免的是正确生成临时文件的答案,如果没有,实际上是某种缓冲实际上阻止了写入文件。我对临时文件的工作方式了解有限!
highsciguy

这有什么错echo $data_are_here | dumb_program
vonbrand

1
这将仅支持一个输入文件,并且并非所有程序都将从stdin中读取。
highsciguy

Answers:


55

使用命名管道。举例说明:

mkfifo fifo
echo -e "hello world\nnext line\nline 3" > fifo

-e告诉回声正确解读换行符逃生(\n)。这将阻塞,即您的外壳将挂起,直到有人从管道读取数据为止。

在同一目录中的某个位置打开另一个shell:

cat fifo

您将阅读回声,它将释放另一个外壳。尽管管道作为磁盘上的文件节点存在,但通过管道的数据却不存在。这一切都发生在内存中。您可以&为回声设置背景()。

该管道(在Linux上)具有64k缓冲区,并且像套接字一样,它将在写满时阻塞编写器,因此,只要不过早地杀死编写器,就不会丢失数据。


好的,谢谢,这也适用于两个命名管道和wdiff。但是我想了解的是,有一定(少量)的内存可用于管道作为缓冲区。如果超过缓冲区大小会怎样?
highsciguy

我添加了关于该问题的最后一段。
goldilocks

3
/tmp在大多数发行版中配置为使用tmpfsRAM中的文件系统。当您在/tmp其中写入文件时,它会直接进入RAM,这对于必须快速访问并多次重写的半弹性文件是一个很好的答案。

129

在Bash中,您可以使用command1 <( command0 )重定向语法,该语法重定向command0的stdout并将其传递给command1采用文件名作为命令行参数的。这称为过程替换

有些使用文件名命令行参数的程序实际上需要一个真正的随机访问文件,因此该技术不适用于那些文件。但是,它可以与wdiff

user@host:/path$ wdiff <( echo hello; echo hello1 ) <( echo hello; echo hello2 )
hello
[-hello1-]
{+hello2+}

在后台,这将创建一个FIFO,将内部的命令<( )通过管道传递到FIFO,然后将FIFO的文件描述符作为参数传递。要查看发生了什么,请尝试将其echo用于打印自变量而不对其进行任何处理:

user@host:/path$ echo <( echo hello )
/dev/fd/63

创建命名管道更加灵活(如果您想使用多个进程编写复杂的重定向逻辑),但是对于许多目的而言,这就足够了,并且显然更易于使用。

>( )当您想将其用作输出时,还有语法,例如

$ someprogram --logfile >( gzip > out.log.gz )

另请参阅Bash重定向备忘单以获取相关技术。


KSH不支持此功能
chanchal1987

5
ksh发明了这个。您正在使用不支持它的ksh 变体
Neil McGuigan

2
有些使用文件名命令行参数的程序实际上需要一个真正的随机访问文件,因此该技术不适用于那些文件。在这些情况下您会怎么做。例如,ssh -F <(vagrant ssh-config) default会很好但是可惜。
Sukima

10

wdiff是一种特殊情况,因为它需要2个文件名参数,但是对于仅需要1个参数并且顽固地拒绝采用文件名参数之外的所有命令的命令,有2个选项:

  • 文件名“-”(即减号)的有效时间约为1/2。它似乎取决于所讨论的命令以及该命令的开发人员是否捕获这种情况并按预期进行处理。例如

    $> ls | 猫 -

  • 在Linux中存在一个名为/ dev / stdin的伪文件,可以在命令绝对需要文件名的情况下使用。因为它不需要命令中的任何特殊文件名处理,所以它更可能起作用。如果fifo有效,或者bash 进程替换方法有效,则这也应该有效,并且不是特定于shell的。例如

    $> ls | 猫/ dev / stdin


1
更少,像/ dev / stdin而不是/ dev / fd / NUM :
eel ghEEz
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.