Perl:让open3继承STDIN,STDOUT,STDERR

Ole*_*nge 3 perl popen3

这个打印1..10两次:

seq 10 > /tmp/ten
perl -e 'fork();seek(STDIN,0,0); print <STDIN>' </tmp/ten
Run Code Online (Sandbox Code Playgroud)

我想使用IPC :: Open3做同样的事情,但我不能让它工作:

perl -MIPC::Open3 -e 'fork();seek(STDIN,0,0); open3(0,1,2,"cat");' < /tmp/ten
perl -MIPC::Open3 -e 'fork();seek(STDIN,0,0); open3(STDIN,STDOUT,STDERR,"cat");' < /tmp/ten
perl -MIPC::Open3 -e 'fork();seek(STDIN,0,0); open3(*STDIN,*STDOUT,*STDERR,"cat");' < /tmp/ten
perl -MIPC::Open3 -e 'fork();seek(STDIN,0,0); open3(\*STDIN,\*STDOUT,\*STDERR,"cat");' < /tmp/ten
Run Code Online (Sandbox Code Playgroud)

ike*_*ami 5

首先,继承句柄的正确表示法是:

open3("<&STDIN", ">&STDOUT", ">&STDERR", "cat")
Run Code Online (Sandbox Code Playgroud)

但是打印1..10两次?你不应该依赖于那种情况!只有时机恰到好处才会发生.事实上,即使对于原始程序,它也很少发生在我身上.问题源于父进程和子进程共享相同的文件指针.

也许为了避免让人们依赖这种非常不可靠的行为,open3当它创建了一个副本时关闭第一个句柄.有可能欺骗它如下:

open(local *CHILD_STDIN, "<&", \*STDIN) or die $!;
open3("<&CHILD_STDIN", ">&STDOUT", ">&STDERR", "cat")
Run Code Online (Sandbox Code Playgroud)

这样,open3将关闭dup CHILD_STDIN,但不关闭STDIN本身.通过此更改,您将在幸运时将列表打印两次.

  • 就像我已经解释的那样,你要做的是时间依赖,这意味着它只会在时机恰到好处时发生.您的原始程序也是如此.你真的不应该做你想做的事!为了避免随机性,我用`my $ pid = fork()替换`fork();`; waitpid($ pid,0)if $ fork;`测试时.这确保了一个进程(父进程)在另一个进程(子进程)完成读取之后只调用`seek`,从而确保了双重打印. (2认同)