Скажите, что ваша R-программа
#! /usr/bin/env r
require(Hmisc)
cat(argv[1], "\n")
, который оказывается удивительно болтливым:
$ ./prog.r foo
Loading required package: Hmisc
Loading required package: methods
Loading required package: survival
Loading required package: stats
Loading required package: utils
Loading required package: graphics
Loading required package: splines
Attaching package: 'Hmisc'
The following object(s) are masked from package:survival :
untangle.specials
The following object(s) are masked from package:base :
format.pval,
round.POSIXt,
trunc.POSIXt,
units
foo
Здесь вы можете отказаться от стандартной ошибки или объединить ее с другим потоком.
Отказ от стандартной ошибки
Один из способов отбросить стандартную ошибку - использовать перенаправление оболочки 2>/dev/null
. Это общий механизм, а 2 - это дескриптор файла стандартной ошибки . Например:
#! /usr/bin/perl
use warnings;
use strict;
open my $command_out, "-|", "./prog.r foo 2>/dev/null"
or die "$0: could not start prog.r";
while (<$command_out>) {
print "got: $_";
}
Оболочка также будет обрабатывать backtick или qx//
выражения
#! /usr/bin/perl
use warnings;
use strict;
(my $command_out = `./prog.r foo 2>/dev/null`) =~ s/^/got: /mg;
print $command_out;
и скалярная команда, переданная system
#! /usr/bin/perl
use warnings;
use strict;
system("./prog.r foo 2>/dev/null") == 0
or warn "$0: prog.r exited " . ($? >>8);
Для всех этих выводов
$ ./prog.pl
got: foo
Но иногда вы не хотите, чтобы оболочка надевала свои грязные руки на вашу команду. Может быть, он содержит метасимволы или кавычки, которые вы не хотите использовать для экранирования. Это когда безопасный открытый трубопровод полезен:
#! /usr/bin/perl
use warnings;
use strict;
my $pid = open my $command_out, "-|";
die "$0: fork: $!" unless defined $pid;
if ($pid == 0) {
# child
open STDERR, ">", "/dev/null" or die "$0: open: $!";
exec "./prog.r", "foo & bar" or exit 1; # STDERR silent now
}
while (<$command_out>) {
print "got: $_";
}
close $command_out or warn "$0: prog.r exited " . ($? >> 8);
Открытие дескриптора на "-|"
разветвляет дочернего элемента и соединяет стандартный выход дочернего элемента с этим дескриптором. Как и fork
, он возвращает 0 дочернему элементу, ненулевой идентификатор процесса для родительского элемента или неопределенное значение при ошибке.
В дочернем процессе мы сначала перенаправляем STDERR
на /dev/null
, а затем используем exec
для замены дочернего элемента нашей программой R. Обратите внимание, что мы передали команду в виде списка, чтобы обойти оболочку:
Если в LIST имеется более одного аргумента или если LIST является массивом с более чем одним значением, он вызывает execvp (3) с аргументами в LIST.
Поскольку мы больше не видим стандартную ошибку, важно явно close $command_out
проверить, что ребенок бежал счастливо. В противном случае вы получите загадочный тихий сбой.
Пример прогона:
$ ./prog.pl
got: foo & bar
Объединить STDERR
в STDOUT
Чтобы увидеть стандартную ошибку на вашем дескрипторе, используйте 2>&1
вместо , например, ,
open my $command_out, "-|", "./prog.r foo 2>&1" or die;
При безопасном открытии трубы dup
стандартная ошибка на стандартном выходе:
if ($pid == 0) {
# child
open STDERR, ">&", \*STDOUT or die "$0: open: $!";
exec "./prog.r", "foo & bar" or die "$0: exec: $!";
}
Документация open
охватывает это:
Вы также можете, в традиции оболочки Bourne, указать EXPR, начинающийся с >&
, и в этом случае остальная часть строки интерпретируется как имя дескриптора файла (или дескриптора файла, если числовой), который должен быть дублирован ( как dup (2) ) и открыто.
Даже если вы можете увидеть стандартную ошибку таким образом, все же будет хорошей идеей проверить состояние выхода ребенка с помощью close
.
Теперь все приходит $command_out
:
got: Loading required package: Hmisc
got: Loading required package: methods
got: Loading required package: survival
got: Loading required package: stats
got: Loading required package: utils
got: Loading required package: graphics
got: Loading required package: splines
got:
got: Attaching package: 'Hmisc'
got:
got:
got: The following object(s) are masked from package:survival :
got:
got: untangle.specials
got:
got:
got: The following object(s) are masked from package:base :
got:
got: format.pval,
got: round.POSIXt,
got: trunc.POSIXt,
got: units
got:
got: foo & bar