提问人:David Levner 提问时间:12/18/2022 更新时间:12/20/2022 访问量:132
如何在 Perl 脚本中检测管道上的文件末尾?
How can I detect end of file on a pipe in a Perl script?
问:
在 Perl 脚本中,我正在运行另一个进程 (openssl) 并通过管道与它通信。我用 openssl 运行 .IPC::Run::start
$openssl_stdin_handle = Symbol::gensym();
$openssl_stdout_handle = Symbol::gensym();
$openssl_stderr_handle = Symbol::gensym();
$harness = IPC::Run::start(\@openssl_command_words, '<pipe', $openssl_stdin_handle, '>pipe', $openssl_stdout_handle, '2>pipe', $openssl_stderr_handle);
my $io_select_for_stdin = IO::Select->new($openssl_stdin_handle);
my $io_select_for_stdout = IO::Select->new($openssl_stdout_handle);
my $io_select_for_stderr = IO::Select->new($openssl_stderr_handle);
我用 和 将明文数据写入 openssl。
我用 和 从 openssl 读取加密数据。我无法写入所有明文数据,然后读取所有加密数据,因为如果有很多明文数据,openssl 标准输出的管道会填满并且 openssl 挂起。相反,我必须写一些明文,看看是否有任何加密数据要读取,如果可用,请读取它,然后回去再写一些。$io_select_for_stdin->can_write(4)
syswrite
$io_select_for_stdout->can_read($timeout)
sysread
一旦我完成对 openssl 的明文编写,我关闭并调用 .这是代码(它位于标记为 的循环中):$openssl_stdin_handle
$io_select_for_stdout->can_read(1)
READ_WRITE_LOOP
$OS_ERROR = 0
if (not $io_select_for_stdout->can_read(1))
{
if ($OS_ERROR == 0) {last READ_WRITE_LOOP;} # nothing to read -- not an error
return "error";
}
my $number_of_cyphertext_bytes_read = sysread($openssl_stdout_handle, $cyphertext_block, $block_size);
问题是可能会返回 false,因为 openssl 还没有准备好写入,或者因为 openssl 已经完成了写入并关闭了其标准输出。在第一种情况下,我想重试读取,在第二种情况下,我想关闭并进入程序的下一阶段。如何区分这两种情况?can_read
$openssl_stdout_handle
上面的代码可以正常工作,因为我将超时设置为一秒。如果我将超时缩短到 0.01 秒,代码有时会起作用,而其他时候则不起作用。我想要更短的超时时间,但我每次都需要代码才能工作。can_read
我知道呼唤不是答案。不能混合调用 和 。有没有一种干净的方法来检测 openssl 是否关闭了我通过访问的管道的一侧?eof($openssl_stdout_handle)
sysread
eof
$openssl_stdout_handle
答:
要回答标题问题,请在 EOF 上返回零(不要与错误返回的零混淆)、管道或非管道。sysread
undef
至于实际问题,在我看来,您可以使用以下内容:
run \@cmd, '<', \$unencrypted, '>', \my $encrypted;
如果您不想将整个文件保存在内存中,则可以使用回调 () 而不是管道作为输出。sub { }
run \@cmd,
'<', sub {
# Called repeatedly until it returns `undef`.
# Return a string of bytes to send, or `undef` to signal eof...
},
'>', sub {
# Do something with the string of bytes provided as argument...
};
评论
上一个:通过 ssh 使用 heredoc 在本地保存远程变量
下一个:如何模拟EOF?
评论
%!
$!
$OS_ERROR
can_read
$!
$!
can_read
$!
$!