我是 运行 neomutt,正在使用 Perl 进行循环。配置值来自 PostgreSQL,但 neomutt 仅从文件中读取。如何从 Perl 中模仿一个文件?

I'm running neomutt in a loop with Perl. The config values come from PostgreSQL, but neomutt only reads from files. How to imitate a file from Perl?

我运行 while(1) 在 perl 中循环以从 PostgreSQL 表中提取电子邮件地址和每个人的配置值。 现在,我写了一个临时文件并在系统中使用 neomutt -nF the_temp_file 。 然后我取消链接文件。 Neomutt 退出。 然后循环给了我电子邮件地址列表,让我用我 select.

中的任何一个地址再次启动 neomutt

我还没有在 neomutt 邮件列表上问过这个问题,但我会的。 我想知道是否有一种方法可以在不将临时文件写入文件系统的情况下模仿临时文件。

更清楚:

获取配置值,例如:

set beep = 0
set beep_new = 0
set bounce = ask-yes
set check_mbox_size = 1
set check_new = 1

并将其直接发送到 neomutt 期望文件位于 neomutt -F config_file

的位置

这可能吗? 谢谢

它仍然涉及到一个临时文件,但是如果您使用的 OS 像 Linux 有一个 /dev/fd 文件系统,您可以打开一个临时文件,立即删除它为了保持整洁,将 /dev/fd/N 作为文件名传递给 neomutt,其中 N 是 perl 文件句柄的基础文件描述符编号。如果您使用核心 File::Temp 模块来创建临时文件,则可以安全地完成它,而不会出现潜在的竞争条件,也不必手动删除文件。

虽然在 system 执行子程序之前阻止描述符被关闭是一件苦差事。

示例:

#!/usr/bin/env perl
use strict;
use warnings;
use File::Temp qw/tempfile/;
use Fcntl qw/:DEFAULT/;

# Get a handle to an anonymous temporary file
my $fh = tempfile;

print $fh <<EOF;
set beep = 0
set beep_new = 0
set bounce = ask-yes
set check_mbox_size = 1
set check_new = 1
EOF
flush $fh;

# Clear the CLOEXEC bit so the descriptor is available to the program run
# by system
my $flags = fcntl $fh, F_GETFD, 0
    or die "Unable to get descriptor flags: $!";
fcntl $fh, F_SETFD, $flags & ~FD_CLOEXEC
    or die "Unable to set descriptor flags: $!";

my $fd = fileno $fh;
system("cat", "/dev/fd/$fd");

另一种完全避免临时文件(但有点复杂)的方法是打开一个管道,并分叉出一个将数据写入其中的子进程,然后再次使用 /dev/fd/N 接口纽穆特:

#!/usr/bin/env perl
use strict;
use warnings;
use Fcntl qw/:DEFAULT/;

pipe my $reader, my $writer or die "Unable to pipe: $!\n";

my $pid = fork;
die "Unable to fork" unless defined $pid;
if ($pid == 0) { # Child process
    close $reader;
    print $writer <<EOF;
set beep = 0
set beep_new = 0
set bounce = ask-yes
set check_mbox_size = 1
set check_new = 1
EOF
    close $writer;
    exit;
} else { # Parent process
    close $writer;
    # Clear the CLOEXEC bit so the descriptor is available to the program run
    # by system
    my $flags = fcntl $reader, F_GETFD, 0;
    fcntl $reader, F_SETFD, $flags & ~FD_CLOEXEC;
    my $fd = fileno $reader;
    system("cat", "/dev/fd/$fd");
    close $reader;
    waitpid $pid, 0; # Reap the child process
}