Когда вы работаете в CGI, стандартные файловые дескрипторы (STDIN, STDOUT, STDERR) возвращаются на веб-сервер. Вы должны закрыть их в своем дочернем процессе:
my $pid = fork();
if (! defined $pid) {
...
} elsif (0 == $pid) {
# child
close(STDIN);
close(STDOUT);
chose(STDERR);
exec { 'scp' } 'scp', 'file', 'user@host:/path/to/file';
} else {
...
}
В качестве альтернативы, вы можете открыть их где-нибудь более полезным (например, STDIN из / dev / null, STDOUT и STDERR в свой собственный файл журнала):
open STDIN, '<', '/dev/null'
or confess "Failed to reopen STDIN";
Вы также можете использовать FD_CLOEXEC
с fcntl
(и это, вероятно, даже сработает, если вы сохраните существующий вызов system
вместо того, чтобы перейти к явному fork / exec).
В зависимости от веб-сервера вам может потребоваться выполнить другие действия (например, стать лидером сеанса с помощью POSIX::setsid
.
Все это удобно для вас сделать с помощью модуля Proc::Daemon
.
Я предлагаю вам также взглянуть на IPC::Run3
, особенно если вы хотите захватить scp
вывод и отправить его в браузер. Это позволит вам легко вернуть эти выходные данные в скаляр, который вы затем сможете легко отформатировать и распечатать.