我有一个需要访问文件的程序。该文件的内容在变量中,我想避免创建真实文件。是否可以创建某种虚拟文件?

X='some stuff'
Y='other stuff'
echo $X > some_file
echo "$Y" | command --file some_file -

通常,我会将其通过管道传递给命令,但是STDIN已经为"in use"。有什么方法可以将两个变量都传递给命令,而无需创建tmp文件?

分析解答

标准输入为文件描述符0,按照惯例,它用于传递“默认”输入。除标准输入外,大多数命令仅允许您通过传递文件名来指定输入。

Linux和大多数其他现代的unice都有一个“特殊”文件名,表示“此文件描述符上已经打开的所有文件”:/dev/fd/N。因此,要使command从文件描述符3而不是某些磁盘文件中读取,请传递command --file /dev/fd/3。这适用于大多数命令。此时的唯一障碍是某些命令坚持使用具有特定扩展名的文件名。通常,您可以使用符号链接来解决此问题。

由于您要告诉命令从文件描述符3中读取,因此在运行命令时需要将其打开。您可以打开文件描述符3以使用command --file /dev/fd/3 <some_file读取文件,但是如果这样做,则最好运行command --file some_file。有用的地方是文件描述符3可以来自管道。 Shell中的管道始终将left-hand一侧的标准输出连接到right-hand一侧的标准输入,但是您可以使用文件描述符重定向来移动文件描述符。

echo "$X" | {
  echo "$Y" | command --file /dev/fd/3 -
} 3<&0

在此示例中,整个支撑组的文件描述符3从接收$X的管道中读取。因此,当command从其名称传递给--file的文件中读取时,它将看到X的值。

这适用于任何sh变体。

bash,ksh和zsh中,有一种更简单的语法可以使用:流程替代。下面的代码与上面的代码几乎等效:

echo "$Y" | command --file <(echo "$X") -

Shell选择一个空闲文件描述符,并建立从echo "$X"到该描述符的管道,然后用正确的/dev/fd/N替换<(…)

在这两种情况下,传递给--file的文件都是管道。因此,这仅在命令与管道一起使用时才有效。有些命令不适用于管道,因为它们不会从头到尾线性地读取文件。使用此类命令,您必须使用一个临时文件。