簡體   English   中英

在 perl 中通過 ssh 將外部命令錯誤定向到文件

[英]Directing external command errors to a file via ssh in perl

這實際上對我有用,但突然間它停止工作。 現在在這里卡了一個小時,但仍然不知道為什么。

我有

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

總是收到一個錯誤,說Pseudo-terminal will not be allocated because stdin is not a terminal

===更新===

我已經嘗試過-T (這根本不會返回任何錯誤)和-t -t而不是-t並且不會在 error.log 中直接錯誤

===更多更新===

-t -t-tt給了我錯誤“tcgetattr:設備 serverCmd 的 ioctl 不合適 = 'ssh -x -n 機器',我想要的程序根本沒有啟動。刪除&或使用qx會給我同樣的錯誤Pseudo-terminal will not be allocated because stdin is not a terminal只要我有-t Pseudo-terminal will not be allocated because stdin is not a terminal

使用 fork+exec(推薦),或使用管道打開,或 drop -t偽終端


這里發生了很多事情。 您啟動ssh ,它需要處理(偽)終端業務,處理流 - 以及后台進程。 正是這最后一點使它變得棘手。 我的行為和你一樣。

以下是三個對我有用的解決方案/變通方法。 我推薦第一個。

命令中&的要點是您的腳本可以立即獲得控制權。 我們可以在腳本中很好地實現這一點。 這要干凈得多,並且不依賴於系統詳細信息。 所以刪除&並將(ssh)進程放在后台。

use warnings;
use strict;

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

my $pid = fork // die "Can't fork: $!";

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

error.log可能包含Connection to machine closed.這一行Connection to machine closed. (它對我有用)。 如果需要,最后是對 fork+exec 的基本解釋。


以下是可能有問題且可能無法在所有地方工作的解決方法,但它們實現了我的測試所需的功能。

  • 如果command不需要控制 tty drop -t 重定向和&仍然對我有用。

  • 通過使用管道打開啟動 (ssh) 進程來解決STDIN問題

    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;

    這會“打開”(分叉)一個執行$cmd的進程,以便$fh是它的STDIN ,如果需要,我們的腳本可以為其提供輸入。 所以我們提供了STDIN ,ssh的偽終端沒有問題。 如果命令不需要輸入,您可以忽略它,其余的根據需要工作。

    這是一個非常干凈的方法來分叉另一個進程和管道到/從它的STDINSTDOUT ,請參閱教程perlopentut ,參考open以及更多詳細信息安全管道打開 perlipc 但是,在這種情況下,我寧願使用上面的 fork+exec。


在這種情況下fork的基本注意事項

fork創建一個新進程並將其 ID 返回給父進程,將 0 返回給子進程。 (這是唯一一次返回兩次的調用。)這個新進程是父進程的克隆,除了該進程的$pid為零,而對於父進程,它是一個(大)整數。 (還有一些其他小得多的差異。)

所以孩子確實進入了下一個if ($pid == 0) { }塊,而父母沒有。 這樣我們就可以將孩子和父母分開,這樣每個人都可以運行專用於他們的代碼。 我們得到並行執行(原則上,也主要是在實踐中)。

if塊中,子進程被exec執行的程序完全替換,在本例中由您的ssh命令替換。 exec根本不會返回(除非調用本身失敗)。 父級繼續在if之后運行,正常執行那里的任何代碼而不會阻塞。

這樣我們就可以分離出另一個程序,而您的程序可以繼續其業務,而無需等待另一個程序完成。

暫無
暫無

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

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