2011-01-12 12 views
9

Was sind die Unterschiede zwischen diesen beiden Beispielen?Was ist der Unterschied zwischen dem Schreiben auf STDOUT und einem Dateihandle, das für "/ dev/tty" geöffnet wurde?

#!/usr/bin/perl 
use warnings; 
use 5.012; 
my $str = "\x{263a}"; 


open my $tty, '>:encoding(utf8)', '/dev/tty' or die $!; 
say $tty $str; 
close $tty; 

open $tty, '>:bytes', '/dev/tty' or die $!; 
say $tty $str; 
close $tty; 

# ------------------------------------------------------- 

binmode STDOUT, ':encoding(utf8)' or die $!; 
say $str; 

binmode STDOUT, ':bytes' or die $!; 
say $str; 
+2

Einer schreibt an/dev/tty, einer von ihnen schreibt an STDOUT. Wolltest du das wissen? –

+0

@JB - es ist keine triviale Unterscheidung für Leute, die mit Unix nicht sehr vertraut sind – DVK

+0

@DVK Sie haben Recht. Ich war verwirrt von der Perl-Orientierung der Frage, als der Kern davon Unix war. Danke für die Aufklärung! –

Antwort

12

Der Unterschied ist, dass Sie zwei verschiedene und (von Perl und Ihr Programm Sicht) unabhängige Datei-Handles schreiben.

  • Die erste ist eine Datei-Handle zu einer speziellen „device“ Datei auf Unixy OS geöffnet, die „für den Steueranschluss eines Prozesses ein Synonym, falls vorhanden“ ist (Zitat aus this Linux document). Bitte beachten Sie, dass, während es allgemein als "Bildschirm" betrachtet wird, es nicht sein muss (z. B. könnte das Terminal stattdessen mit der Gerätedatei eines seriellen Ports verknüpft sein); und es kann nicht existieren oder nicht geöffnet werden.

  • Der zweite ist eine Datei, die standardmäßig mit dem Dateideskriptor # 1 für den Prozess verknüpft ist.

Sie scheinen mag auf den ersten Blick identisch sein aufgrund der Tatsache, dass in einer typischen Situation, ein Unix-Shell wird standardmäßig 1 seinen Dateideskriptor # assoziieren (und damit ein jeder Prozess ohne Umleitungen startet) mit /dev/tty.

Die beiden haben nichts gemeinsam von Perl Sicht, ANDERE als die Tatsache, dass diese beiden am Ende aufgrund der Art, wie Unix-Shells standardmäßig funktionieren.

Das funktionale Verhalten der beiden zitierten Codeabschnitte wird aufgrund dieser Vorgabe oft identisch aussehen, aber das ist nur "zufällig".

Unter praktischen Unterschiede:

  • /dev/tty nicht unbedingt existieren auf nicht-Unixy oss. Es ist daher sehr un portabel, um tty zu verwenden. Windows entspricht CON: IIRC.

  • STDOUT eines Programms kann von jedem, der das Programm aufgerufen hat, mit ALLEN verknüpft werden. Könnte einer Datei zugeordnet sein, könnte eine Pipe zum STDIN eines anderen Prozesses sein.


Sie können überprüfen, ob Ihr STDOUT an einen tty verbunden ist durch die Verwendung von -t operator:

if (-t STDOUT) { say 'STDOUT is connected to a tty' } 

Als weiteren beiseite, bitte beachten Sie, dass Sie sicherstellen können, dass Ihr STDOUT schreibt /dev/tty indem das STDOUT-Dateihandle explizit geschlossen und erneut geöffnet wird, so dass es auf /dev/tty zeigt:

+2

Beachten Sie auch, dass es viele Fälle gibt, in denen '/ dev/tty' überhaupt nicht verwendet werden kann (da es kein kontrollierendes Terminal gibt) - ein gängiges Beispiel ist ein Befehl, der über ssh als' ssh somehost somecommand' aufgerufen wird - ssh will, by Standard, verbinden Sie STDIN, STDOUT und STDERR, aber erstellen Sie kein Terminal. – bdonlan

+0

@bdolan - richtig (also das ", wenn überhaupt" hinzugefügt in der Definition, die ich zitierte). Oder, für ein einfacheres Beispiel, unter Windows :) – DVK

+0

@JB - Danke für '-t' edit! Nebenbei kann IIRC nicht zwischen "/ dev/tty" oder irgendeinem anderen Endgerät unterscheiden. – DVK

4

Zusätzlich zu dem, was der DVK, können Sie den einfachen Unterschied von

perl -le 'open $o, ">:encoding(utf8)", "/dev/tty"; print "STDOUT"; print $o "/dev/tty"' > /dev/null 

Der Schreib zu STDOUT geht zu /dev/null sagen, aber das Schreiben auf $o geht auf den Bildschirm.

+0

+1 Schönes Beispiel von dem, was DVK gesagt hat. – sebthebert

4

Ein Programm, das von einer interaktiven Shell gestartet wird, schreibt normalerweise die Standardausgabe an ein Terminal, das /dev/tty und als dasselbe Ziel darstellt. Es gibt jedoch mehrere Umstände, unter denen die Ausgabe an STDOUT an ein anderes Ziel geschrieben werden kann.

STDOUT kann in einer separaten Datei geführt werden:

perl someprogram.pl > a/file 
perl someprogram.pl >> a/file 

STDOUT kann

perl someprogram.pl | /usr/bin/mailx -s "Program Output" [email protected] 

auch an den Eingang eines anderen Programms geleitet werden, könnte das Programm von einer nicht-interaktive Shell gestartet werden , wie ein Cron-Job oder ein anderer Daemon, der auf Ihrem System läuft. Die Umgebungen für diese Programme haben keinen Zugriff auf ein /dev/tty Gerät, und STDOUT in diesen Programmen werden woanders (oder nirgends) weitergeleitet.