代码之家  ›  专栏  ›  技术社区  ›  A.Ellett

通过stdin重定向的输入未按预期工作

  •  0
  • A.Ellett  · 技术社区  · 7 年前

    我写了一些代码,我以为我在测试是否有性传播疾病。但是代码的工作与我所期望的相反。

    这是我写的代码,我叫它 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<(回音A;回音B) 具有以下输出

      command line arguments: "/dev/fd/63" as expected
      ( -t STDIN ) returns TRUE
    

    Zit<<(回音A;回音B) 具有以下输出

      command line arguments: "EMPTY" as expected
      ( -t STDIN ) returns FALSE
      But, I can iterate over <STDIN>!  Huh?? Behold:
    >> a
    >> b
    

    我真的很困惑。这并不像我想象的那样。如果 (-T STDIN) 是假的,为什么 虽然 循环工作?

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

    我以前编辑过这篇文章,这样就不那么令人困惑了。

    1 回复  |  直到 7 年前
        1
  •  4
  •   melpomene    7 年前
    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 表示法告诉shell打开指定的文件进行读取,并将stdin重定向到该文件。

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