簡體   English   中英

我可以確定是否正在從終端運行 Perl 腳本嗎?

[英]Can I detect if a Perl script is being run from a terminal for sure?

我可以確定是否正在從終端運行 Perl 腳本嗎?

如果我不確定,我寧願默認假設它是從瀏覽器運行的。 但是,如果有辦法確保它 100% 從終端運行,我會很高興(出於調試目的)。

非常感謝

這是直接取自 ExtUtils::MakeMaker 的prompt函數的源代碼。 我想,有可能有人不遺余力地欺騙它。 但在某些時候,破損必須歸斷路器所有。

對於大多數目的,這應該足夠了:

 my $isa_tty = -t STDIN && (-t STDOUT || !(-f STDOUT || -c STDOUT)) ;

首先,它檢查 STDIN 是否對 TTY 開放。 如果是,請檢查 STDOUT 是否是。 如果不是 STDOUT,則它也不能打開到文件或字符特殊文件。

更新:

IO::Prompt::Tiny 使用以下內容:

# Copied (without comments) from IO::Interactive::Tiny by Daniel Muey,
# based on IO::Interactive by Damian Conway and brian d foy

sub _is_interactive {
    my ($out_handle) = ( @_, select );
    return 0 if not -t $out_handle;
    if ( tied(*ARGV) or defined( fileno(ARGV) ) ) {
        return -t *STDIN if defined $ARGV && $ARGV eq '-';
        return @ARGV > 0 && $ARGV[0] eq '-' && -t *STDIN if eof *ARGV;
        return -t *ARGV;
    }
    else {
        return -t *STDIN;
    }
}

IO::Interactive::Tiny 添加了注釋來解釋正在發生的事情:

sub is_interactive {
    my ($out_handle) = (@_, select);    # Default to default output handle

    # Not interactive if output is not to terminal...
    return 0 if not -t $out_handle;

    # If *ARGV is opened, we're interactive if...
    if ( tied(*ARGV) or defined(fileno(ARGV)) ) { # IO::Interactive::Tiny: this is the only relavent part of Scalar::Util::openhandle() for 'openhandle *ARGV'
        # ...it's currently opened to the magic '-' file
        return -t *STDIN if defined $ARGV && $ARGV eq '-';

        # ...it's at end-of-file and the next file is the magic '-' file
        return @ARGV>0 && $ARGV[0] eq '-' && -t *STDIN if eof *ARGV;

        # ...it's directly attached to the terminal 
        return -t *ARGV;
    }

    # If *ARGV isn't opened, it will be interactive if *STDIN is attached 
    # to a terminal.
    else {
        return -t *STDIN;
    }
}

我已經驗證了 IO::Interactive 中的邏輯反映了 IO::Interactive::Tiny 的邏輯。 因此,如果您的目標是在適當的地方進行提示,請考慮使用 IO::Prompt::Tiny。 如果您的需求比 IO::Prompt::Tiny 支持的更細微,您可以使用 IO::Interactive::Tiny 來提供此特定功能。

雖然您使用自己的解決方案可能是最安全的,但使用這些 CPAN 模塊之一的優勢在於,它們可能是積極維護的,並且如果結果證明它們不足以達到其宣傳的目的,則會收到報告和最終更新。

使用文件測試運算符-t來測試文件句柄是否附加到終端。 例如:

if (-t STDIN) {
  print "Running with a terminal as input."
}

設備文件/dev/tty代表進程的控制終端。 如果您的進程未連接到終端(是守護進程,用完cron / at等),則它無法“打開”這個特殊設備。 所以

sub isatty {
    no autodie;
    return open(my $tty, '+<', '/dev/tty');
}

/dev/tty可以代表虛擬控制台設備( /dev/ttyN )、pty( xtermssh )、串口(COM1)等,並且不受重定向的影響,所以這應該是可靠的。

如果這經常運行,也許使用這個版本

use feature qw(state);

sub isatty { 
    no autodie; 
    state $isatty = open(my $tty, '+<', '/dev/tty'); 
    return $isatty;
}

這應該更有效(在我的簡單基准測試中超過一個數量級)。

這些僅適用於 Unix-y 系統(或在 Windows 之上運行的 POSIX 應用程序,或在 Window 的 POSIX 子系統中)。

暫無
暫無

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

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