通过 STDIN 重定向的输入未按预期运行



我写了一些代码,我认为我正在测试是否存在STDIN。 但是代码与我的预期相反。

这是我写的代码,我称之为zit

#!/usr/bin/perl
use strict 'vars';
my @a = @ARGV ? @ARGV : "EMPTY";
printf "  command line arguments: "%s" as expectedn", @a;
if ( -t STDIN )
{
print "  ( -t STDIN ) returns TRUEn";
}
else
{
print "  ( -t STDIN ) returns FALSEn";
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

因此,为了弄清楚可能发生了什么,我通过添加while循环来修改if-then代码(根据我的理解,我将其放在我认为应该产生问题的地方)。

#!/usr/bin/perl
use strict 'vars';
my @a = @ARGV ? @ARGV : "EMPTY";
printf "  command line arguments: "%s" as expectedn", @a;
if ( -t STDIN )
{
print "  ( -t STDIN ) returns TRUEn";
}
else
{
print "  ( -t STDIN ) returns FALSEn";
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循环有效?

有人可以解释一下这里发生了什么吗?

我已经重新编辑了之前的这篇文章,以减少混乱。

use strict 'vars';

你为什么要这么做?您实际上应该只是use strict;并启用所有三个限制,而不仅仅是vars。您还应该use warnings;.


如果您检查perldoc -f -t,您将看到文档说:

-t Filehandle is opened to a tty.

换句话说,它不是测试是否存在 STDIN(总是有一个 STDIN(除非你的父进程很顽皮并在启动你之前关闭了它)),而是 STDIN 是否指的是终端(缩写"tty"最初指的是电传打字机,但当它们被文本终端和后来的终端仿真器(如 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表示法告诉 shell 打开指定的文件进行读取并将 STDIN 重定向到该文件。

因此,它运行zit(没有任何命令行参数),STDIN 连接到管道(其另一端由echo a; echo b馈送)。这实际上与( echo a; echo b ) | zit相同。这里 zit 的 STDIN 指的是管道,而不是终端,所以-t STDIN返回 false。当然,您仍然可以从中读取:您可以从中读取的大多数内容都不是终端,例如普通文件,管道或套接字。

最新更新