簡體   English   中英

Perl將數據傳遞到stdin並從stdout和stderr讀取

[英]Perl passing data to stdin and reading from stdout and stderr

此處可能有許多關於同一問題的問題,但到目前為止,對我來說,這些問題都不起作用。

我有一個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;
}

我將其編譯為輸出a.out。

我有一個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;

如果運行通過stdin傳遞simple.xml的C程序,則會得到以下信息:

[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

那么我該如何解決呢? 我需要從perl中的@array傳遞sample.xml。 來自C程序的stderr整數應存儲在單獨的變量中,而來自C程序的stdout應存儲在perl中的另一個獨立變量中。 我認為這可能需要使用open3,但我不知道如何使用。 任何工作示例將不勝感激。

更新 :關於您的評論,Ilmari Karonen已經向您解釋了管道沒有文件大小,因為它是數據流,程序不知道該流有多大。

您有兩個問題: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,因為它只是表示子進程ID的數字。 在其他情況下,您可能希望探索非阻塞讀取 ,但會使邏輯更加復雜。

原始答復 :未能解決張貼者問題,因為他想使用IPC。

您可以僅將文件名作為sample.xml添加到$ cmd嗎? 您可以只使用反引號運算符捕獲輸出,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";

我很確定問題不在您的Perl代碼中,而是在C程序中。 嘗試跑步

cat sample.xml | ./a.out

在shell中,您應該獲得與Perl程序相同的輸出。 問題在於,在兩種情況下, stdin都是管道而不是文件,並且fstat()顯然無法為管道返回任何有意義的大小。

無論如何,在stdin上調用fstat()對我來說似乎是一種不好的做法-您不應該依賴於本質上由Shell進行的優化。 關於stdin的唯一真正保證是您可以(嘗試)從stdin中讀取數據。 除此之外,它可能是任何東西:文件,管道,tty等。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM