Perl에서 외부 명령의 오류 출력을 어떻게 읽을 수 있습니까?

StackOverflow https://stackoverflow.com/questions/777543

  •  13-09-2019
  •  | 
  •  

문제

더 큰 Perl 프로그램의 일부로 나는 다음의 출력을 확인하고 있습니다. diff 참조 파일에 대한 폴더의 입력 파일 명령. 여기서 빈 출력(일치)은 통과 결과이고 diff의 모든 출력은 실패 결과입니다.

문제는 대상 폴더에 예상 파일 수가 부족한 경우 diff 예외 발생이 출력으로 제공되지 않아 잘못된 패스가 생성된다는 것입니다.

출력 예:

diff: /testfolder/Test-02/test-output.2: No such file or directory

테스트-01:통과하다

테스트-02:통과하다

코드는 다음과 같습니다.

$command = "(diff call on 2 files)";
my @output = `$command`;
print "Test-02: ";
$toPrint = "PASS";
foreach my $x (@output) {
    if ($x =~ /./) {
        $toPrint = "FAIL";
    }
}

이것은 출력이 있는 경우 실패할 수 있는 빠른 해커 작업입니다. diff 부르다.호출된 명령에 의해 발생한 예외를 확인하는 방법이 있습니까? backticks?

도움이 되었습니까?

해결책

프로그램 자체는 "예외"를 던질 수는 없지만 0이 아닌 오류 코드를 반환 할 수 있습니다. 백 티크로 실행되는 프로그램의 오류 코드를 확인하거나 system() $?를 사용하는 Perl에서

$toPrint = "FAIL" if $?;

(테스트하는 루프 전에이 줄을 추가하십시오 @output.)

다른 팁

답이 있습니다 perlfaq8 : 외부 명령에서 stderr를 어떻게 캡처 할 수 있습니까?


외부 명령을 실행하는 세 가지 기본 방법이 있습니다.

system $cmd;        # using system()
$output = `$cmd`;       # using backticks (``)
open (PIPE, "cmd |");   # using open()

System ()을 사용하면 systdout과 stderr가 system () 명령이 리디렉션되지 않는 한 스크립트의 stdout 및 stderr와 같은 장소로 이동합니다. Backticks and Open () 명령의 stdout 만 읽으십시오.

IPC :: Open3에서 Open3 () 함수를 사용할 수도 있습니다. Benjamin Goldberg는 몇 가지 샘플 코드를 제공합니다.

프로그램의 stdout을 캡처하려면 stderr를 버립니다.

use IPC::Open3;
use File::Spec;
use Symbol qw(gensym);
open(NULL, ">", File::Spec->devnull);
my $pid = open3(gensym, \*PH, ">&NULL", "cmd");
while( <PH> ) { }
waitpid($pid, 0);

프로그램의 stderr를 캡처하려면 stdout을 버립니다.

use IPC::Open3;
use File::Spec;
use Symbol qw(gensym);
open(NULL, ">", File::Spec->devnull);
my $pid = open3(gensym, ">&NULL", \*PH, "cmd");
while( <PH> ) { }
waitpid($pid, 0);

프로그램의 stderr를 캡처하고 Stdout을 우리 자신의 stderr로 보내십시오.

use IPC::Open3;
use Symbol qw(gensym);
my $pid = open3(gensym, ">&STDERR", \*PH, "cmd");
while( <PH> ) { }
waitpid($pid, 0);

명령의 stdout과 그 stderr를 별도로 읽으려면 그것들을 임시 파일로 리디렉션하고 명령을 실행 한 다음 Temp 파일을 읽을 수 있습니다.

use IPC::Open3;
use Symbol qw(gensym);
use IO::File;
local *CATCHOUT = IO::File->new_tmpfile;
local *CATCHERR = IO::File->new_tmpfile;
my $pid = open3(gensym, ">&CATCHOUT", ">&CATCHERR", "cmd");
waitpid($pid, 0);
seek $_, 0, 0 for \*CATCHOUT, \*CATCHERR;
while( <CATCHOUT> ) {}
while( <CATCHERR> ) {}

그러나 실제로는 필요하지 않습니다 둘 다 템 파일이 되려면 ... 다음은 교착 상태 없이도 작동해야합니다.

use IPC::Open3;
use Symbol qw(gensym);
use IO::File;
local *CATCHERR = IO::File->new_tmpfile;
my $pid = open3(gensym, \*CATCHOUT, ">&CATCHERR", "cmd");
while( <CATCHOUT> ) {}
waitpid($pid, 0);
seek CATCHERR, 0, 0;
while( <CATCHERR> ) {}

프로그램이 완료되기를 기다리는 대신 프로그램의 STDOUT를 즉시 처리하기 시작할 수 있기 때문에 더 빠릅니다.

이 중 하나를 사용하면 호출 전에 파일 설명자를 변경할 수 있습니다.

open(STDOUT, ">logfile");
system("ls");

또는 Bourne Shell 파일 설명서 리디렉션을 사용할 수 있습니다.

$output = `$cmd 2>some_file`;
open (PIPE, "cmd 2>some_file |");

파일 설명서 리디렉션을 사용하여 stderr가 stdout의 복제품으로 만들 수도 있습니다.

$output = `$cmd 2>&1`;
open (PIPE, "cmd 2>&1 |");

Perl 프로그램에서 STDOUT의 DUP로 Stderr을 열 수 없으며 쉘을 호출하여 리디렉션을 수행하지 않아도됩니다. 이것은 작동하지 않습니다 :

open(STDERR, ">&STDOUT");
$alloutput = `cmd args`;  # stderr still escapes

Open ()이 Stderr가 Open () 시점에 Stdout가 진행되는 곳으로 이동하기 때문에 실패합니다. 그런 다음 백 티크는 stdout을 문자열로 이동하지만 stderr를 변경하지 마십시오 (여전히 오래된 stdout으로 이동).

CSH (1)가 아닌 백 티크에서 Bourne Shell (SH (1)) 리디렉션 구문을 사용해야합니다! Perl의 System () 및 Backtick and Pipe가 열리는 이유에 대한 자세한 내용은 Bourne Shell을 사용하는 모든 사용이 "whynot"컬렉션의 versus. whynot 기사에 있습니다. http://www.cpan.org/misc/olddoc/fmteyewtk.tgz . 명령의 stderr와 stdout을 함께 캡처하려면 :

$output = `cmd 2>&1`;                       # either with backticks
$pid = open(PH, "cmd 2>&1 |");              # or with an open pipe
while (<PH>) { }                            #    plus a read

명령의 stdout을 캡처하려면 stderr를 버립니다.

$output = `cmd 2>/dev/null`;                # either with backticks
$pid = open(PH, "cmd 2>/dev/null |");       # or with an open pipe
while (<PH>) { }                            #    plus a read

명령의 stderr를 캡처하지만 stdout을 버립니다.

$output = `cmd 2>&1 1>/dev/null`;           # either with backticks
$pid = open(PH, "cmd 2>&1 1>/dev/null |");  # or with an open pipe
while (<PH>) { }                            #    plus a read

stderr를 포착하기 위해 명령의 stdout과 stderr를 교환하려면 stdout을 남겨 두어 우리의 오래된 stderr를 나옵니다.

$output = `cmd 3>&1 1>&2 2>&3 3>&-`;        # either with backticks
$pid = open(PH, "cmd 3>&1 1>&2 2>&3 3>&-|");# or with an open pipe
while (<PH>) { }                            #    plus a read

명령의 stdout과 stderr를 별도로 읽으려면 파일로 별도로 리디렉션 한 다음 프로그램이 완료되면 해당 파일에서 읽는 것이 가장 쉽습니다.

system("program args 1>program.stdout 2>program.stderr");

이 모든 예에서 주문은 중요합니다. 쉘은 파일 디스크립터 리디렉션을 엄격하게 왼쪽에서 올바른 순서로 처리하기 때문입니다.

system("prog args 1>tmpfile 2>&1");
system("prog args 2>&1 1>tmpfile");

첫 번째 명령은 표준 아웃 및 표준 오류를 임시 파일로 보냅니다. 두 번째 명령은 이전 표준 출력 만 보내고 이전 표준 오류는 이전 표준에 나타납니다.

확인하다 Perlvar ~을 위한 $?. 0으로 설정되면 신호가없고 프로그램의 리턴 코드도 0입니다. 아마 당신이 원하는 것일 것입니다.

이 경우 사용할 수도 있습니다 체계 STDOUT 및 STDERR을 /dev /null로 리디렉션하면서 반환 값을 0으로 확인하십시오.

Diff 오류가 STDERR에서 발생한다고 가정하면 오류를 검사하거나 로그인하려면 CPAN 모듈 캡처 :: tiny를 권장합니다.

use Capture::Tiny 'capture';
my ($out, $err) = capture { system($command) };

그것은 백 틱과 같지만 stdout과 stderr를 별도로 제공합니다.

Backticks-Englosed 명령의 출력으로 작업하는 흥미로운 방법 목록이 있습니다. perldoc 사이트. 아래로 스크롤하거나 "QX/String/"을 검색해야합니다 (따옴표없이).

당신은 또한 수:

my @output = `$command 2>\&1`;

코드를 더 쉽게 읽을 수 있도록 'diff -d'의 출력을 통해 실행해 볼 수도 있습니다.

foreach (`diff -d $args`){
  if (/^Only in/){
     do_whatever();
  }
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top