Perl передает данные в stdin и читает из stdout и stderr - PullRequest
1 голос
/ 03 октября 2011

Здесь может быть много вопросов, касающихся того же самого, но на данный момент у меня не работает ни один.

У меня есть программа на C следующим образом:

#include <stdio.h>
#include <sys/stat.h>

long size(FILE *st_in) {
    struct stat st;
    if (fstat(fileno(st_in), &st) == 0)
        return st.st_size;
    return -1;
}

int main (){
   FILE *file = stdin;
   long s1, s2; 

   s1 = size(file);
   printf("Size is %ld\n", s1);
   fprintf(stderr, "%d", 1);
   return 0;
}

Я компилирую еев качестве выхода.

У меня есть XML-файл 'sample.xml'

<sample>
    <tag>Hello</tag>
    <tag>Cool</tag>
</sample>

Тогда у меня есть этот perl-код

#!/usr/bin/perl
use warnings;
use IPC::Open2;
open FILE, "sample.xml" or die $!;
my @xmlfile = <FILE>;
my $pid = open2(*Reader, *Writer, "./a.out");
print Writer "@xmlfile";
waitpid($pid, 0);
my @got = <Reader>;
close Writer;
close Reader;
close $pid;
print "Output got is\n";
print @got;

Если я запускаю программу на C, передавая простые.xml через stdin, я получаю следующее:

[bharath@xml 18:22:34]$ ./a.out < sample.xml 
Size is 60

Когда я запускаю код perl, я ожидаю размер как 60. Но я получаю как 0.

[bharath@xml 18:22:42]$ ./firmware.pl 
Output got is
Size is 0

Так какрешить это?Мне нужно передать файл sample.xml из @array в perl.И целое число stderr из программы на C должно храниться в отдельной переменной, а стандартный вывод из программы на C должен храниться в другой отдельной переменной в perl.Я думаю, что это может потребовать использования open3, но я не знаю, как использовать.Любой рабочий пример будет высоко оценен.

Ответы [ 2 ]

4 голосов
/ 03 октября 2011

ОБНОВЛЕНИЕ : что касается ваших комментариев, Ильмари Каронен уже объяснил вам, что канал не имеет размера файла, потому что это поток данных, программа не знает, насколько большим может быть этот поток.

У вас две проблемы: ваша C-программа не работает, а также ваша Perl-программа не работает, потому что она зашла в тупик.Вы не можете проверить две вещи вместе.Разделите две проблемы.Например, сначала попробуйте свою программу с каналом из оболочки.

cat sample.xml | ./a.out 
Size is 60

Первоначально она не работала.Чтобы это работало, я использовал эту модифицированную программу на C: размер можно рассчитать по потоку, посчитав все полученные символы до EOF.

#include <stdio.h>

int main (){
    long size = 0;
    int ch;
    FILE *file = stdin;
    if (!file) {
        return 2;
    }
    while ((ch = getc(file)) != EOF) {
        ++size;
    }
    printf("Size is %ld\n", size);
    fprintf(stderr, "%d", 1);
    return 0;
}

Что касается вашей Perl-программы, у вас был тупик, потому что обе программынаходились в состоянии ожидания, чтобы решить его, я немного изменил порядок инструкций:

#!/usr/bin/perl -w

use strict;
use IPC::Open2;

open FILE, "sample.xml" or die $!;
my @xmlfile = <FILE>;

my $pid = open2(*Reader, *Writer, './a.out 2> /dev/null');
print Writer @xmlfile;
close(Writer);

my @got = <Reader>;
close(Reader);
waitpid($pid, 0);

print "Output got is: ";
print @got;

Как вы можете видеть, я закрываю писатель перед тем, как начать читать, потому что моя программа на C предназначена для получениявсе ввод, а затем сделать вывод.И теперь все межпроцессное взаимодействие будет работать:

./program.pl
Output got is: Size is 60

В качестве примечания вам не нужно закрывать $ pid, поскольку это просто число, представляющее идентификатор процесса дочернего элемента.В других случаях вы можете изучить неблокирующие операции чтения , но это усложнит логику.

ОРИГИНАЛЬНЫЙ ОТВЕТ : не удалось решить проблему с постером, потому что онхотел использовать IPC.

Можете ли вы просто добавить имя файла как sample.xml к $ cmd?Вы можете просто использовать оператор backtick для захвата вывода, chomp удаляет символ новой строки и вывод будет в $ out.

#!/usr/bin/perl
$cmd = './a.out < sample.xml 2> /dev/null';
$out = `$cmd`;
chomp $out;
print "out='$out'\n";

Я думаю, что ваш пример - найти способ связи между C и Perlпотому что, конечно, если это просто размер файла, то в Perl все гораздо проще:

#!/usr/bin/perl
print -s 'sample.xml';
print "\n";
2 голосов
/ 03 октября 2011

Я почти уверен, что проблема не в вашем Perl-коде, а в C-программе. Попробуйте запустить

cat sample.xml | ./a.out

в оболочке, и вы должны получить тот же вывод, что и из вашей Perl-программы. Проблема в том, что в обоих случаях stdin будет каналом, а не файлом, и fstat(), очевидно, не сможет вернуть какой-либо значимый размер для трубы.

В любом случае, вызов fstat() на stdin кажется мне плохой практикой & mdash; Вы не должны полагаться на то, что по сути является оптимизацией, сделанной оболочкой. Единственная реальная гарантия, которую вы получаете о stdin, заключается в том, что вы можете (пытаться) прочитать данные с нее; кроме этого, это может быть что угодно: файл, канал, tty и т. д.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...