![](/img/trans.png)
[英]Why my perl script requires to export packages path into @INC to run remotely via ssh
[英]perl fork doesn't work properly when run remotely (via ssh)
我有一個 perl 腳本 script.pl,它在運行時執行 fork,父進程將其 pid 輸出到文件然后退出,而子進程將某些內容輸出到 STOUT,然后進入 while 循環。
$pid = fork();
if ( ! defined $pid )
{
die "Failed to fork.";
}
#Parent process
elsif($pid)
{
if(!open (PID, ">>running_PIDs"))
{
warn "Error opening file to append PID";
}
print PID "$pid \n";
close PID;
}
#child process
else
{
print "Output started";
while($loopControl)
{
#Do some stuff
}
}
當我在本地調用它時,這工作正常,即:perl script.pl。
該腳本打印出一些內容,然后將控制權返回給 shell。 (而子進程在后台進入其循環)。
但是,當我通過 ssh 調用它時,控件永遠不會返回到 shell(也不會打印“輸出開始”行。
即: $ ssh username@example.com 'perl script.pl'
然而,有趣的是,子進程確實運行了(輸入 ps 時可以看到)。
誰能解釋一下這是怎么回事?
編輯:
我在調試下運行它並得到這個:
###forked,但不知道如何創建一個新的TTY。由於兩個調試器爭奪同一個 TTY,輸入會嚴重糾纏。
我只知道如何在 xterms 和 OS/2 控制台中將輸出切換到不同的窗口。 對於手動開關,將創建的 TTY 的名稱放在 $DB::fork_TTY 中,或者定義一個函數 DB::get_fork_TTY() 返回它。
在類 UNIX 系統上,可以通過鍵入 tty 來獲取給定窗口的 TTY 名稱,並通過 sleep 1000000 將 shell 與 TTY 斷開連接。
每當您通過非交互式 ssh 命令啟動后台作業時,您都需要關閉或以其他方式綁定 stdin、stdout 和 stderr。 否則 ssh 將等待后台進程退出。 常見問題。
這稱為與控制終端分離或分離,是編寫后台作業時的一般最佳實踐,而不僅僅是 SSH。
因此,不會使整個命令靜音的最簡單更改是添加:
#close std fds inherited from parent
close STDIN;
close STDOUT;
close STDERR;
在您print "Output started";
. 如果您的子進程需要在運行期間定期打印輸出,那么您需要重定向到日志文件。
ssh username@example.com 'nohup perl script.pl'
您無法退出,因為仍有附加的進程。 你需要nohup
它。
發生的事情是 ssh 直接將“perl script.pl”作為命令執行。 如果您有可用的“屏幕”,則可以執行以下操作:
$ ssh username@example.com 'screen -d -m perl script.pl'
讓它在分離的屏幕上運行,然后用 screen -r 重新連接
為了更好地理解這一點,我建議閱讀@Jax 的解決方案
這與 Perl 無關。 這是因為 SSH 處理您嘗試后台運行的任何長時間運行的進程的方式。
我需要從 bash 腳本啟動 script.pl(在目標主機上定義必要的局部變量):
$ ssh username@example.com /path/to/launcher.sh
/path/to/launcher.sh 正在調用 Perl 腳本:
CMD="/path/to/script.pl -some_arg=$VALUE -other_arg"
$CMD &
它在本地工作,但是當通過 ssh 運行時它沒有返回。
我在 Perl 腳本中嘗試了 @pra 的解決方案,但在我的情況下不起作用。
使用@Jax 的解決方案,我將$CMD &
替換$CMD &
:
nohup $CMD > /path/to/output.log 2>&1 < /dev/null &
它工作得很好。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.