2016-07-20 15 views
1

Das funktioniert tatsächlich für einen Moment, aber auf einmal hört es auf zu arbeiten. Stuck hier für eine Stunde und weiß immer noch nicht warum.Externe Befehlsfehler über SSH in eine Datei leiten

Ich habe

system("ssh -t machine command > stdout.log 2> error.log &") 

immer einen Fehler immer sagen Pseudo-terminal will not be allocated because stdin is not a terminal

=== === UPDATE

Ich habe versucht, -T (dies einfach nicht mich zurückgibt Fehler) und -t -t anstelle von -t und nicht direkt Fehler in error.log entweder

=== MEHR UPDA TE ===

-t -t und -tt gibt mir den Fehler "tcgetattr: Unpassende ioctl für das Gerät serverCmd = 'ssh -x-n machine', und mein vorgesehenes Programm startet überhaupt nicht. Dropping & oder qx Verwendung gibt mir den gleichen Fehler Pseudo-terminal will not be allocated because stdin is not a terminal solange ich -t

+0

Das sieht nicht wie ein Fehler aus. – melpomene

+0

Haben Sie versucht, Ihren Befehl in einem normalen Shell-Skript auszuführen? Ich denke nicht, dass es ein Perl-Problem ist, sondern ein SSH-Problem. – dgw

Antwort

0

Short   Verwenden fork + exec (empfohlen) haben, oder die Nutzung offen verrohrt oder -t Pseudo-Terminal fallen


Hier ist viel los. Sie starten ssh, die sich mit (Pseudo-) Terminal-Geschäft befassen müssen, mit Streams, die manipuliert werden - und für einen Hintergrundprozess. Es ist dieses letzte Stück, das es schwierig macht. Ich bekomme das gleiche Verhalten wie du.

Hier sind drei Lösungen/Workarounds, die für mich arbeiten. Ich empfehle das erste.

Der Punkt der & ist, dass Ihr Skript die Kontrolle sofort zurück erhält. Das können wir im Skript gut erreichen. Das ist viel sauberer und hängt nicht von Systemdetails ab. Lassen Sie also & fallen und stellen Sie den (ssh) Prozess selbst in den Hintergrund.

use warnings; 
use strict; 

my $cmd = 'ssh -t machine command >stdout.log 2>error.log'; 

my $pid = fork; 
die "Can't fork: $!" if not defined $pid; 

if ($pid == 0) { # child 
    exec($cmd); 
    die "exec shouldn't have returned: $! "; 
} 
# Parent only. Child became $cmd, which went its own way, never to return. 
# Rest of your code, executed right away ... 

Die error.log enthält wahrscheinlich die Linie Connection to machine closed. (es für mich tut). Eine grundlegende Erklärung von fork + exec ist am Ende, falls erforderlich.


Nachfolgend sind Abhilfen, die Probleme und können nicht überall arbeiten kann, aber sie erreichen, was in meinen Tests benötigt wird.

  • Wenn command braucht nicht die Steuerung tty Tropfen -t. Die Umleitung und & funktionieren immer noch für mich.

  • Trick das STDIN Problem, indem den (SSH) Prozess beginnend Verwendung verrohrt offene

    my $cmd = 'ssh -t machine command >stdout.log 2>error.log &'; 
    my $pid = open my $fh, '|-', $cmd // die "Can't fork: $!; 
    # your other code ... 
    close $fh; 
    

    Diese 'öffnet' (Gabeln) ein Verfahren, das $cmd so ausführt, dass $fh sein ist STDIN und unser Skript kann es bei Bedarf einspeisen. So bieten wir die STDIN und ssh Pseudo-Terminal hat kein Problem damit. Wenn der Befehl keine Eingabe benötigt, können Sie dies ignorieren und der Rest funktioniert nach Bedarf.

    Dies ist eine sehr saubere Art und Weise ein weiteres Verfahren und Rohr gabeln/oder von seinem STDINSTDOUT siehe tutorial perlopentut Bezug open, und für weitere Einzelheiten Safe Pipe Opens in perlipc. In diesem Fall würde ich jedoch lieber mit fork + exec oben gehen.


Die fork erstellt einen neuen Prozess und gibt deren ID. Dieser neue Prozess ist ein Klon des übergeordneten Elements, außer dass für diesen Prozess $pid Null ist, während es für das übergeordnete Element eine (große) Ganzzahl ist. (Es gibt einige andere, wesentlich kleinere Unterschiede.) Also gibt das Kind den nächsten if ($pid == 0) { } Block ein, während der Elternteil das nicht tut. Auf diese Weise trennen wir Kind und Eltern, sodass jeder den ihm zugewiesenen Code ausführen kann. Wir erhalten parallele Ausführung (im Prinzip und auch meistens in der Praxis).

Im Innern des if Block, der durch das Kind Prozess ausgeführt Programm wird von exec, in diesem Fall von Ihrem ssh Befehl insgesamt durch das Programm ausgeführt ersetzt. Die exec wird einfach nie zurückgegeben (außer der Anruf selbst schlägt fehl). Das Parent läuft nach dem if weiter und führt normalerweise jeden Code aus, der ohne Blockierung vorhanden ist. Auf diese Weise können wir ein anderes Programm ausgliedern, während Ihr Programm mit seinem Geschäft fortfahren kann, ohne auf den Abschluss des anderen warten zu müssen.

+0

@ user3669481 Ich habe die Antwort erheblich erweitert und zwei weitere Problemumgehungen hinzugefügt. Ich empfehle immer noch fork + exec. – zdim

+0

Probier mal fork und exec aber hab immernoch den selben Fehler (hab nicht fallen lassen &, wenn ich es ablege, kann ein Widget auf meiner Schnittstelle nicht geöffnet werden) .. habe es nochmal mit -tt und -t -t versucht, gib mir der Fehler "tcgetattr unpassende ioctl für Gerät" und die Verbindung geschlossen, bevor das gewünschte Programm gestartet – user3669481

+0

@ user3669481 Richtig, es ist die '&' das ist beunruhigend. Der Punkt von fork + exec ist, dass Sie es dann nicht brauchen - das Skript startet 'ssh ...' und fährt fort, es blockiert nicht. Anscheinend liegt das Problem bei "_command_" und/oder bei der von Ihnen genannten Schnittstelle. Warum benötigt das speziell das '&'? Können Sie Ihre Frage bearbeiten, um zu erklären, was Sie tun? Ist das machbar? Wenn nicht, ist vielleicht eine andere Frage geeignet. Wenn Sie einen Befehl ausführen, der 'STDOUT' und' STDERR' auf nicht blockierende Weise protokolliert, haben Sie hier die Antwort (en). Schließlich, versuchst du 'ssh' _without_' -t', pro erste Kugel? – zdim