Проблема заключается в том, что если целевая папка коротка на количестве ожидаемых файлов, исключение diff throw не выводится как результат, создавая ложные проходы.
Ответ 2
Там ответ в perlfaq8: Как я могу захватить STDERR из внешней команды?
Существует три основных способа запуска внешних команд:
system $cmd; # using system()
$output = `$cmd`; # using backticks (``)
open (PIPE, "cmd |"); # using open()
С системой() STDOUT и STDERR будут находиться в том же месте, что и script STDOUT и STDERR, если команда system() не перенаправляет их. Backticks и open() читают только STDOUT вашей команды.
Вы также можете использовать функцию open3() из IPC:: Open3. Бенджамин Голдберг дает пример кода:
Чтобы захватить программу 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 отдельно, вы можете перенаправить их в временные файлы, запустить команду, затем прочитать временные файлы:
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> ) {}
Но нет никакой реальной необходимости, чтобы оба были tempfiles... следующее должно работать так же хорошо, без взаимоблокировки:
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:
$output = `$cmd 2>some_file`;
open (PIPE, "cmd 2>some_file |");
Вы также можете использовать перенаправление файла-дескриптора, чтобы сделать STDERR дубликат STDOUT:
$output = `$cmd 2>&1`;
open (PIPE, "cmd 2>&1 |");
Обратите внимание, что вы не можете просто открывать STDERR, чтобы быть дублером STDOUT в вашей программе Perl, и избегать вызова оболочки для перенаправления. Это не работает:
open(STDERR, ">&STDOUT");
$alloutput = `cmd args`; # stderr still escapes
Это не работает, потому что open() заставляет STDERR перейти туда, где STDOUT шел во время open(). Затем обратные шаги заставляют STDOUT перейти к строке, но не меняют STDERR (который все еще идет на старый STDOUT).
Обратите внимание, что вы должны использовать синтаксис перенаправления оболочки Bourne (sh (1)) в backticks, а не csh (1)! Подробная информация о том, почему Perl system() и backtick и pipe открывается, все используют оболочку Bourne в статье versus/csh.whynot в коллекции "Far More Than You Want Want To To Know" в 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
Чтобы обменять команду STDOUT и STDERR, чтобы захватить 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");
Первая команда отправляет стандартную и стандартную ошибку во временный файл. Вторая команда отправляет туда только старый стандартный вывод, а старая стандартная ошибка отображается на старом стандартном выходе.