gpt4 book ai didi

perl - 如何捕获还需要用户从终端输入的命令的所有输出?

转载 作者:行者123 更新时间:2023-12-04 20:33:54 25 4
gpt4 key购买 nike

我想捕获一个命令的所有输出( STDOUTSTDERR ),该命令还需要用户从终端窗口进行交互,即它读取 STDIN 然后打印一些内容到 STDOUT

这是我要从中捕获输出的脚本的最小版本:

用户.pl :

#! /usr/bin/env perl

use feature qw(say);
use strict;
use warnings;

print "Enter URL: ";
my $ans = <STDIN>;
# do something based on $ans
say "Verification code: AIwquj2VVkwlWEBwway";
say "Access Token: bskjZO8iZotv!";

我尝试使用 Capture::Tiny :

p.pl :
#! /usr/bin/env perl

use feature qw(say);
use strict;
use warnings;

use Capture::Tiny qw(tee_merged);

my $output = tee_merged {
#STDOUT->autoflush(1); # This does not work
system "user.pl";
};

if ( $output =~ /Access Token: (.*)$/ ) {
say $1;
}

但它不起作用,因为直到用户在终端中输入输入后才会显示提示。

编辑 :

如果我用 python 脚本替换 user.pl 似乎它工作正常。例如:

用户.py :

#! /usr/bin/env python3

ans = input( 'Enter URL: ' )
# do something based on $ans
print( 'Verification code: AIwquj2VVkwlWEBwway' )
print( 'Access Token: bskjZO8iZotv!' )

最佳答案

TL/DR 有一个解决方案,它有点难看,但它有效。有一些小警告。

这是怎么回事? 问题其实出在user.pl . sample user.pl你提供的作品是这样的:它首先打印字符串 Enter URL:到它的stdout ,然后刷新它的stdout然后它从它的 stdin 中读取一行. stdout 的冲洗perl 自动发生:当您尝试从 stdin 读取时与 <..> (又名 readline ),perl 刷新 stdout .这样做正是为了使这样的程序正确运行。不幸的是,perl 似乎只在 stdout 时实现此行为。是一个 tty(伪终端)。如果没有,它不会刷新 stdout在阅读 stdin 之前.这就是为什么当您在交互式终端 session 中执行脚本时它可以工作,而当您 try catch 其输出时它不能正常工作(因为在这种情况下它的 stdout 连接到管道)。

如何解决这个问题? 由于user.pl如果它的 stdout 行为不端不是tty,我们必须使用tty。阿法克,IPC::Run是唯一可以使用 tty 而不是普通管道捕获子进程输出的 perl 模块。不幸的是,当使用 tty 时,IPC::Run不允许我们重定向 stdout只是,它迫使我们重定向 stdin也。因此,我们必须处理来自 stdin 的读取。在父进程中代表子进程(哎呀!)。这是 p.pl 的示例实现使用 IPC::Run :

#!/usr/bin/perl
use strict;
use warnings;
use IO::Handle;
use IPC::Run;

my $complete_output='';
my $in='';
my $out='';
my $h=IPC::Run::start ['./user.pl'],'<pty<',\$in,'>pty>',\$out;
while ($h->pumpable) {
$h->pump;
print $out;
STDOUT->flush;
if ($out eq 'Enter URL: ') {
$in.=<STDIN>;
}
$complete_output.=$out;
$out='';
}
$h->finish;
# do something with $complete_output here

所以这有点难看。例如,我们尝试检测子进程何时等待用户输入(通过查找字符串 Enter URL:),当它等待时,我们在父进程中读取用户输入,然后将其传递给子进程。另请注意,我们必须自己实现 tee 功能,因为 IPC::Run不提供。

有一些警告。我们处理用户输入的方式,如果子进程使用类似 readline支持行编辑的库,这是行不通的,因为我们在父进程中使用简单的 <STDIN> 进行所有读取.此外,由于在后台使用 tty 而不是管道,所有用户输入都将回显到 stdout。 .因此,无论用户输入什么提示,我们都将其放入 $in将其发送到进程并从进程中取回(通过 $out 变量)。但是由于我们的终端也有回显,所以文本会出现两次。一种解决方案是过滤 $out删除用户输入并阻止我们打印它。

最后,这不适用于 Windows。

关于perl - 如何捕获还需要用户从终端输入的命令的所有输出?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39733314/

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