$my_-6ren">
gpt4 book ai didi

perl - 如何在没有竞争条件的情况下通过管道传输到同一个临时文件句柄并从中读取?

转载 作者:行者123 更新时间:2023-12-04 00:52:45 25 4
gpt4 key购买 nike

这是我人生中第一次调试 perl 脚本,然后遇到了这个问题:

$my_temp_file = File::Temp->tmpnam();
system("cmd $blah | cmd2 > $my_temp_file");
open(FIL, "$my_temp_file");
...
unlink $my_temp_file;

除了第 1-3 行中明显的竞争条件外,这与我想要的非常相似。即使使用适当的 tempfile() 也没有办法(我能想到)确保在第 2 行流式传输到的文件与在第 3 行打开的文件相同。一种解决方案可能是管道,但 cmd 可能由于有限的管道缓冲而延迟出现,这会使我的错误处理变得复杂(我认为)。

我如何:

  1. 写下 cmd $blah | 的所有输出cmd2 到临时文件打开的文件句柄?
  2. 在不重新打开文件的情况下读取输出(冒竞争条件的风险)?

最佳答案

您可以 open管道到命令并直接读取其内容,无需中间文件:

open my $fh, '-|', 'cmd', $blah;

while( <$fh> ) {
...
}

对于较短的输出,反引号可能会起作用,但在这种情况下,您必须更加小心地删除输入,以免它们被 shell 误解:

my $output = `cmd $blah`;

CPAN 上也有各种模块可以处理这类事情。

对临时文件的一些评论

评论提到了竞争条件,所以我想我应该为那些想知道人们在谈论什么的人写一些东西。

在原始代码中,Andreas 使用 File::Temp , Perl 标准库中的一个模块。但是,他们使用 tmpnam 类 POSIX 调用,在文档中有以下警告:

Implementations of mktemp(), tmpnam(), and tempnam() are provided, but should be used with caution since they return only a filename that was valid when function was called, so cannot guarantee that the file will not exist by the time the caller opens the filename.

这是令人气馁的并且是removed for Perl v5.22's POSIX .

也就是说,您取回了一个尚不存在的文件的名称。获得名称后,您不知道该文件名是否由另一个程序创建。而且,以后的unlink 可能会导致其中一个程序出现问题。

当两个可能彼此不认识的程序在大致相同的时间尝试做同样的事情时,就会出现“竞争条件”。您的程序试图创建一个名为“foo”的临时文件,其他一些程序也是如此。他们可能同时看到名为“foo”的文件不存在,然后尝试创建它。他们都可能成功,并且当他们都写入它时,他们可能会交错或覆盖对方的输出。然后,其中一个程序认为它已完成并调用 unlink。现在另一个程序想知道发生了什么。

在恶意利用案例中,某些不良行为者知道会出现一个临时文件,因此它会识别一个新文件并进入其中读取或写入数据。

但这也可能发生在同一个程序中。同一程序的两个或多个版本同时运行并试图做同样的事情。使用随机文件名,两个正在运行的程序同时选择相同名称的情况可能极为罕见。但是,我们不在乎某样东西有多稀有;我们关心如果发生这种情况会造成多么严重的后果。而且,稀有比没有更常见。

文件::临时

了解所有这些,File::Temp处理确保您获得文件句柄的细节:

my( $fh, $name ) = File::Temp->tempfile;

这使用默认模板来创建名称。当文件句柄超出范围时,File::Temp也能收拾残局。

{
my( $fh, $name ) = File::Temp->tempfile;
print $fh ...;
...;
} # file cleaned up

有些系统可能会自动清理临时文件,虽然我已经好多年不关心这个了。通常是批处理(比如每周一次)。

我经常更进一步,为我的临时文件名提供一个模板,其中 X 是模块识别并用随机字符填充的文字字符:

my( $name, $fh ) = File::Temp->tempfile( 
sprintf "$0-%d-XXXXXX", time );

我在开发东西时经常这样做,这样我就可以观看程序生成文件(以及生成文件的顺序)并查看其中的内容。在生产中我可能想隐藏源程序名称($0)和时间;我不想让人更容易猜出谁在制作哪个文件。

便签簿

我还可以用 open 打开一个临时文件通过不给它一个文件名。当您想在程序外收集时,这很有用。以读写方式打开它意味着您可以输出一些内容然后在该文件中移动(我们在 Learning Perl 中展示了一个固定长度的记录示例):

open(my $tmp, "+>", undef) or die ...

print $tmp "Some stuff\n";
seek $tmp, 0, 0;
my $line = <$tmp>;

关于perl - 如何在没有竞争条件的情况下通过管道传输到同一个临时文件句柄并从中读取?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65187579/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com