这个简短的例子说明了我在Perl中遇到的一个问题.这个想法是stdin默认处理或使用输入文件(如果指定).
#!/usr/bin/env perl
qx{echo "a file" > a};
qx{echo "b file" > b};
qx{echo "c file" > c};
process('a');
process('c');
sub process {
my $name = shift;
my $fp = *STDIN;
open $fp, '<', $name if $name;
process('b') if $name eq 'a';
print "Processing file '$name' (fp=$fp)\n";
print while(<$fp>);
}
Run Code Online (Sandbox Code Playgroud)
我得到的输出是:
$ ./curious.pl
Processing file 'b' (fp=*main::STDIN)
b file
Processing file 'a' (fp=*main::STDIN)
Processing file 'c' (fp=*main::STDIN)
c file
Run Code Online (Sandbox Code Playgroud)
应该是:
$ ./curious.pl
Processing file 'b' (fp=*main::STDIN)
b file
Processing file 'a' (fp=*main::STDIN)
a file
Processing file 'c' (fp=*main::STDIN)
c file
Run Code Online (Sandbox Code Playgroud)
我可能错过了两件事:
$fp等于*main::STDIN而不是当前打开的文件?'a'不读取内容?逻辑上,$fp是子程序的本地.它首先被分配,*STDIN然后open用文件指针改变a.然后我处理b.当我返回处理时,b我仍然应该有一个指向a内部的指针$fp.
我在这里读到传递给它的处理程序open必须是一个未定义的标量.然而,它似乎与b和c.
这必须与重新分配有关STDIN:
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
qx{echo "a file" > a};
qx{echo "b file" > b};
qx{echo "c file" > c};
process('a');
process('c');
sub process {
my $name = shift;
print "Starting process with $name from ", scalar caller(), " \n";
my $fp; # = *STDIN;
print "Process before open $name: ", Dumper($fp), "\n";
open $fp, '<', $name if $name;
print "Process after open $name: ", Dumper($fp), "\n";
process('b') if $name eq 'a';
print "Processing file '$name' (fp=$fp)\n";
print "Contents of $name:\n";
print while (<$fp>);
print "Done with $name\n\n\n";
}
Run Code Online (Sandbox Code Playgroud)
这给出了输出:
Starting process with a from main
Process before open a: $VAR1 = undef;
Process after open a: $VAR1 = \*{'::$fp'};
Starting process with b from main
Process before open b: $VAR1 = undef;
Process after open b: $VAR1 = \*{'::$fp'};
Processing file 'b' (fp=GLOB(0x136412c))
Contents of b:
"b file"
Done with b
Processing file 'a' (fp=GLOB(0x606f54))
Contents of a:
"a file"
Done with a
Starting process with c from main
Process before open c: $VAR1 = undef;
Process after open c: $VAR1 = \*{'::$fp'};
Processing file 'c' (fp=GLOB(0x136412c))
Contents of c:
"c file"
Done with c
Run Code Online (Sandbox Code Playgroud)
如果你这样做,只需将那一行改回:
my $fp = *STDIN;
Run Code Online (Sandbox Code Playgroud)
并且您获得Dumper报告(其余输出为简洁起见):
Process before open a: $VAR1 = *::STDIN
Process after open a: $VAR1 = *::STDIN;
Run Code Online (Sandbox Code Playgroud)
然而它显然是开放的,因为它打印文件内容.
如果你启动strace并运行这两个过程(因此减少):
#!/usr/bin/env perl
my $fh;
open ( $fh, "<", "fishfile" ) or warn $!;
print <$fh>;
Run Code Online (Sandbox Code Playgroud)
运行这个strace myscript.(注意 - strace是一个特定于Linux的工具 - 其他平台还有其他工具)
(注意 - 我正在使用一个fishfile带有内容的文件,fish因为这样我很确定我能找到文本:))
做两次 - 一旦进行分配,STDIN你会发现open操作周围存在一些差异.同时运行它们diff你会看到很多它但有趣的部分是:
没有STDIN作业:
open ( "fishfile", O_RDONLY) = 3
read (3, "fish\n", 8192 ) = 5
write ( 1, "fish\n", 5 ) = 5
Run Code Online (Sandbox Code Playgroud)
随着STDIN任务:
open ( "fishfile", O_RDONLY) = 3
dup2 ( 3, 0 ) = 0
close ( 3 ) = 0
read (0, "fish\n", 8192 ) = 5
write ( 1, "fish\n", 5 ) = 5
Run Code Online (Sandbox Code Playgroud)
(注意 - 返回代码open是文件描述符号 - 例如3)
那么它实际上做的是:
STDIN)上复制它STDIN.1或STDOUT.(2是STDERR).所以结果 - 因为你是 - 通过这样做 - STDIN用自己的文件描述符破坏,并且因为STDIN是全局范围的(而不是你$fh的词法范围):
STDIN子进程b,然后读取它直到EOF,这意味着什么时候a开始阅读它,那里什么也没有.然而,如果你移动open到后调用b:
sub process {
my $name = shift;
print "Starting process with $name from ", scalar caller(), " \n";
my $fp = *STDIN;
process('b') if $name eq 'a';
print "Process before open $name: ", Dumper($fp), "\n";
open $fp, '<', $name if $name;
print "Process after open $name: ", Dumper($fp), "\n";
print "Processing file '$name' (fp=$fp)\n";
print "Contents of $name:\n";
print while (<$fp>);
print "Done with $name\n\n\n";
}
Run Code Online (Sandbox Code Playgroud)
这成功了.我假设根据您之前的问题,这与处理文件,然后根据内容打开子流程有关.
因此,解决方案将测试$name克隆之前是否存在,STDIN您将不会遇到问题.