2008-08-19 11 views
10

In Perl können Sie Systembefehle mit system() oder `` (backticks) ausführen. Sie können die Ausgabe des Befehls sogar in einer Variablen erfassen. Dies verdeckt jedoch die Ausführung des Programms im Hintergrund, so dass die Person, die das Skript ausführt, es nicht sehen kann.Wie kann Perls System() den Befehl ausgeben, der ausgeführt wird?

Normalerweise ist das nützlich, aber manchmal möchte ich sehen, was hinter den Kulissen passiert. Wie machen Sie es so, dass die ausgeführten Befehle auf das Terminal gedruckt werden und die Ausgabe dieser Programme auf das Terminal gedruckt wird? Dies wäre das .bat Äquivalent von "@echo on".

Antwort

8

Wie ich verstehe, wird system() das Ergebnis des Befehls drucken, aber nicht zuweisen. Z.B.

[[email protected] /]$ perl -e '$ls = system("ls"); print "Result: $ls\n"' 
bin dev home lost+found misc net proc sbin  srv System tools var 
boot etc lib media  mnt opt root selinux sys tmp  usr 
Result: 0 

Backticks wird die Ausgabe des Befehls erfassen und nicht drucken:

[[email protected] /]$ perl -e '$ls = `ls`; print "Result: $ls\n"' 
Result: bin 
boot 
dev 
etc 
home 
lib 

etc ...

Update: Wenn Sie den Namen des Befehls drucken ist System() 'd auch, ich denke, Rudd Ansatz ist gut. Wiederholte hier für die Konsolidierung:

sub execute { 
    my $cmd = shift; 
    print "$cmd\n"; 
    system($cmd); 
} 

my $cmd = $ARGV[0]; 
execute($cmd); 
4

Verwenden Sie stattdessen geöffnet. Dann können Sie die Ausgabe des Befehls erfassen.

open(LS,"|ls"); 
print LS; 
18

Ich weiß nicht jeder Standard Weg, dies zu tun, aber Sie können ein Unterprogramm definieren, um es für Sie tun:

sub execute { 
    my $cmd = shift; 
    print "$cmd\n"; 
    system($cmd); 
} 

my $cmd = $ARGV[0]; 
execute($cmd); 

Und dann sehen sie in Aktion :

pbook:~/foo rudd$ perl foo.pl ls 
ls 
file1 file2 foo.pl 
2

Hmm, interessant, wie verschiedene Leute diese verschiedenen Möglichkeiten beantworten. Es sieht für mich so aus wie mk und Daniel Fone interpretiert es als wollen/manipulieren die stdout des Befehls (keine ihrer Lösungen erfassen stderr fwiw). Ich denke, Rudd ist näher gekommen. Eine Wendung, die Sie bei Rudds Antwort machen könnten, besteht darin, den integrierten Befehl system() mit Ihrer eigenen Version zu überschreiben, so dass Sie den vorhandenen Code nicht neu schreiben müssen, um seinen Befehl execute() zu verwenden.

if ($DEBUG) { 
    *{"CORE::GLOBAL::system"} = \&{"main::execute"}; 
} 

denke ich, das wird funktionieren, aber ich muss zugeben, dass diese Voodoo ist und es war:

mit seinem execute() Unter von Rudds Post, Sie so etwas wie dies an der Spitze des Codes haben könnte eine Weile, seit ich diesen Code geschrieben habe. Hier ist der Code, den ich Jahre schrieb vor Systemaufrufen auf einem lokal (Aufruf Namespace) oder globale Ebene auf Modulladezeit abfangen:

# importing into either the calling or global namespace _must_ be 
    # done from import(). Doing it elsewhere will not have desired results. 
    delete($opts{handle_system}); 
    if ($do_system) { 
    if ($do_system eq 'local') { 
     *{"$callpkg\::system"} = \&{"$_package\::system"}; 
    } else { 
     *{"CORE::GLOBAL::system"} = \&{"$_package\::system"}; 
    } 
    } 
+0

Das große Problem mit dem globalen 'system' Befehl zu ersetzen ist, dass' system' einen komplexen Prototyp hat, die nicht von repliziert werden kann das benutzerspezifische Prototypsystem. Daher funktioniert ein Code einfach nicht, wenn Sie 'system' durch Ihre benutzerdefinierte Version ersetzen. – cjm

1

Eine andere Technik zu kombinieren mit dem anderen in den Antworten erwähnt wird, um den tee Befehl zu verwenden, . Zum Beispiel:

open(F, "ls | tee /dev/tty |"); 
while (<F>) { 
    print length($_), "\n"; 
} 
close(F); 

Dies druckt sowohl aus den Dateien im aktuellen Verzeichnis (als Folge von tee /dev/tty) und auch aus der Länge jeden Dateinamen drucken lesen.

4

Hier ein ausführen aktualisiert, dass die Ergebnisse gedruckt wird und bringt sie:

sub execute { 
    my $cmd = shift; 
    print "$cmd\n"; 
    my $ret = `$cmd`; 
    print $ret; 
    return $ret; 
}