簡體   English   中英

本地在標准流/裸字文件句柄上做什么:STDIN?

[英]What does local do on the standard streams / bareword word filehandles: STDIN?

我正在考慮做

open(*STDIN, "<", "/dev/null" );
open(my $fh, "-|", "/bin/bash", "/tmp/foo");
print for <$fh>;'

但是,我想在之后恢復*STDIN ,所以我嘗試了。

{
  open(local *STDIN, "<", "/dev/null" );
  open(my $fh, "-|", "/bin/bash", "/tmp/foo");
  print for <$fh>;
}

您可以使用cat嘗試使用和不使用local關鍵字這樣的方法,

{
  # remove local and it works,
  open(local *STDIN, "<", "/dev/null" );
  open(my $fh, "-|", "/bin/cat");
  print for <$fh>;
}

只有沒有local才會cat/dev/null讀取。 那么local在裸字文件句柄上實際上做了什么?

open ...,'-|' 從標准輸入讀取的system調用將嘗試從文件描述符 0 讀取。如果您不搞砸,外部程序將從與 perl 的標准輸入相同的輸入流中讀取。

# reads from standard input
open my $fh, '-|', "/bin/cat";
while (<fh>) { print }

# reads from /tmp/foo
open STDIN, "<", "/tmp/foo";       # replaces fd0 with handle to /tmp/foo
open my $fh, '-|', "/bin/cat";
while (<$fh>) { print }

# reads from standard input
open local *STDIN, "<", "/tmp/foo";  # doesn't close fd0, creates new fd
open my $fh, '-|',  "/bin/cat";
while (<$fh>) { print }

# reads from /tmp/foo
close STDIN;
open FOO, "<", "/tmp/foo";       # fileno(FOO) should be 0 now
open my $fh, '-|', "/bin/cat";
while (<$fh>) { print }

有系統文件句柄(稱為文件描述符,或“fd”),還有 Perl 文件句柄。 Perl 文件句柄通常包裝系統文件句柄,但情況並非總是如此。 例如, open(my $fh, '<', \\$buf)創建一個與任何系統文件句柄無關的 Perl 句柄。

其他進程對您的進程變量一無所知,因此它們對 Perl 文件句柄一無所知。 任何作為 fd 0 打開的句柄都將用作 STDIN,fd 1 作為 STDOUT,而 fd 2 作為 STDERR。 [1]

open傳遞一個現有的 Perl 句柄時,這個句柄將被關閉。 如果創建一個新的系統文件句柄,它將被賦予與原始 fd 相同的編號(如果原始句柄有一個)或最低的可用編號(如果沒有)。 [2]

因此,當您使用open(*STDIN, ...) ,與*STDIN{IO}關聯的新句柄也將是 fd 0。

$ perl -e'
   CORE::say fileno(*STDIN);
   open(*STDIN, "<", "/dev/null") or die $!;
   CORE::say fileno(*STDIN);
'
0
0

cat從 fd 0 讀取,因此會注意到變化。

local *STDIN創建 glob 的備份並將*STDIN與新的 glob 關聯。 原始*STDIN仍在內存中,因此沒有釋放與*STDIN關聯的資源。 這意味着與*STDIN關聯的任何文件句柄仍處於打開狀態。

當您使用open(local *STDIN, ...) ,新的 fd 將具有可用的最低數字。 fd 0 仍在內存中某個地方的原始*STDIN使用,因此 fd 0 不可用。 也許這次 fd 3 將是第一個可用的 fd(STDOUT 和 STDERR 使用 1 和 2)。

$ perl -e'
   CORE::say fileno(*STDIN);
   {  
      open(local *STDIN, "<", "/dev/null") or die $!;
      CORE::say fileno(*STDIN);
   }
   CORE::say fileno(*STDIN);
'
0
3
0

cat從 fd 0 讀取,將從原始句柄讀取。

Perl 可以使與 STDIN、STDOUT 和 STDERR 關聯的任何句柄在執行cat之前變為 fd 0、1 和 2,但事實並非如此。 這是留給你的。


  1. 當我描述 unixy 系統中的工作方式時,Windows 中的工作方式類似。

  2. open傳遞一個包裝系統文件句柄的句柄並且也正在創建一個新的系統文件句柄的情況下,unixy 系統上使用的內部機制如下:

    1. 使用open創建一個新的 fd。 它將具有最低的可用數字。
    2. dup2用於創建與原始 fd 具有相同編號的新 fd 的副本。
    3. open創建的 fd 是關閉的。

    這意味着如果發生錯誤,原始文件不會關閉。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM