[英]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.