我写了一些代码,以为我正在测试是否有STDIN。但是代码的工作与我的预期相反。
这是我编写的代码,我称之为zit
#!/usr/bin/perl
use strict 'vars';
my @a = @ARGV ? @ARGV : "EMPTY";
printf " command line arguments: \"%s\" as expected\n", @a;
if ( -t STDIN )
{
print " ( -t STDIN ) returns TRUE\n";
}
else
{
print " ( -t STDIN ) returns FALSE\n";
print " But, I can iterate over <STDIN>! Huh?? Behold:\n";
}
这就是我的想法:
zit <(echo a;echo b)
将导致( -t STDIN )
为FALSE
。
zit < <(echo a;echo b)
将导致( -t STDIN )
为TRUE
。
因此,为了弄清楚到底发生了什么,我通过添加一个if-then
循环来修改了while
代码(根据我的理解,我把它放在应该认为会产生问题的地方)。
#!/usr/bin/perl
use strict 'vars';
my @a = @ARGV ? @ARGV : "EMPTY";
printf " command line arguments: \"%s\" as expected\n", @a;
if ( -t STDIN )
{
print " ( -t STDIN ) returns TRUE\n";
}
else
{
print " ( -t STDIN ) returns FALSE\n";
print " But, I can iterate over <STDIN>! Huh?? Behold:\n";
while ( <STDIN> )
{
print ">> $_";
}
}
这是此代码的输出
zit <(echo a;echo b)
具有以下输出
command line arguments: "/dev/fd/63" as expected
( -t STDIN ) returns TRUE
zit < <(echo a;echo b)
具有以下输出
command line arguments: "EMPTY" as expected
( -t STDIN ) returns FALSE
But, I can iterate over <STDIN>! Huh?? Behold:
>> a
>> b
我对此感到非常困惑。这不是我想的那样。如果( -t STDIN )
为假,为什么while
循环起作用?
有人可以解释这里发生了什么吗?
为了避免混淆,我从前重新编辑了这篇文章。
答案 0 :(得分:4)
use strict 'vars';
您为什么要这样做?您实际上应该只use strict;
并启用所有三个限制,而不仅仅是vars
。您还应该use warnings;
。
如果您选中perldoc -f -t
,则会看到文档中的内容:
-t Filehandle is opened to a tty.
换句话说,它不是在测试是否有STDIN(始终有STDIN(除非您的父进程是顽皮的,并且在启动之前将其关闭)),而是在测试STDIN是否引用了终端(缩写“ tty”)最初指的是teletype,但是当它们被text terminals和后来的terminal emulators(例如xterm)替换时,名称就卡住了。用C术语表示,它对应于对isatty
的调用。
在第一个示例中,您有zit <(echo a;echo b)
。 <( ... )
表示法使bash将其STDOUT重定向到管道来运行指定的命令。然后,它将<( ... )
替换为引用管道(管道的读取端)的文件名。
具体地说,它运行zit /dev/fd/63
(其中文件描述符63指向管道的读取端,其写入端由echo a; echo b
馈送)。 STDIN没有任何反应,因此zit
从shell继承了其标准流,因此STDIN引用了一个终端,这就是-t STDIN
返回true的原因。
在第二个示例中,您有zit < <(echo a;echo b)
。这非常相似,但是现在生成的命令为zit < /dev/fd/63
。 < FILE
表示外壳程序打开指定的文件以读取并将STDIN重定向到该文件。
因此,它在STDIN连接到管道(另一端由zit
供电)下运行echo a; echo b
(没有任何命令行参数)。这实际上与( echo a; echo b ) | zit
相同。这里zit的STDIN是指管道,而不是终端,因此-t STDIN
返回false。当然,您仍然可以从中读取内容:您可以读取的大多数内容都不是终端,例如普通文件,管道或套接字。