Я использую Windows MATLAB для запуска команд SSH, но время от времени команда SSH зависает на неопределенный срок, а затем и мой сценарий MATLAB (иногда при работе на ночь). Как я могу получить тайм-аут команды после определенного времени ожидания? Например, предположим, что я не хочу ждать более 3 секунд, пока команда SSH завершит выполнение, прежде чем сломать ее и двигаться дальше:
% placeholder for a command that sometimes hangs
[status,result] = system('ssh [email protected] sleep 10')
% placeholder for something I still want to run if the above command hangs
[status,result] = system('ssh [email protected] ls')
Я хотел бы сделать функцию sys_with_timeout
, которую можно использовать следующим образом:
timeoutDuration = 3;
[status,result] = sys_with_timeout('ssh [email protected] sleep 10', timeoutDuration)
[status,result] = sys_with_timeout('ssh [email protected] ls', timeoutDuration)
Я попробовал функцию тайм-аута из FEX, но, похоже, она не работает для команды system/SSH.
Я не думаю, что команда system
очень гибкая, и я не вижу способа сделать с ее помощью то, что вы хотите.
Но мы можем использовать для этого функциональность Java, встроенную в MATLAB, согласно этому ответу Андре Карона.
Вот как вы будете ждать завершения процесса с тайм-аутом:
runtime = java.lang.Runtime.getRuntime();
process = runtime.exec('sleep 20');
process.waitFor(10, java.util.concurrent.TimeUnit.SECONDS);
if process.isAlive()
disp("Done waiting for this...")
process.destroyForcibly();
end
process.exitValue()
В примере мы запускаем команду оболочки sleep 20
, затем waitFor()
ждем завершения программы, но не более 10 секунд. Мы опрашиваем, чтобы убедиться, что процесс все еще работает, и убиваем его, если это так. exitValue()
возвращает статус, если вам это нужно.
Бегу sleep 5
вижу:
ans =
0
Бегу sleep 20
вижу:
Done waiting for this...
ans =
137
Спасибо, я никогда не знал о запуске команд Java из MATLAB. Это очень полезно. Я использовал разные части вашего ответа, чтобы создать нужную мне функцию, и опубликовал ее как новый ответ.
@MountainDrew Очень мило!
Основываясь на ответе @Cris Luengo, вот функция sys_with_timeout()
. Я не использовал функцию process.waitFor()
, потому что предпочитаю ждать в цикле while и отображать вывод по мере его поступления. Цикл while прерывается после завершения команды или истечет время ожидания, в зависимости от того, что наступит раньше.
function [status,cmdout] = sys_with_timeout(command,timeoutSeconds,streamOutput,errorOnTimeout)
arguments
command char
timeoutSeconds {mustBeNonnegative} = Inf
streamOutput logical = true % display output as it comes in
errorOnTimeout logical = false % if false, display warning only
end
% launch command as java process (does not wait for output)
process = java.lang.Runtime.getRuntime().exec(command);
% start the timeout timer!
timeoutTimer = tic();
% Output reader (from https://www.mathworks.com/matlabcentral/answers/257278)
outputReader = java.io.BufferedReader(java.io.InputStreamReader(process.getInputStream()));
errorReader = java.io.BufferedReader(java.io.InputStreamReader(process.getErrorStream()));
% initialize output char array
cmdout = '';
while true
% If any lines are ready to read, append them to output
% and display them if streamOutput is true
if outputReader.ready() || errorReader.ready()
if outputReader.ready()
nextLine = char(outputReader.readLine());
elseif errorReader.ready()
nextLine = char(errorReader.readLine());
end
cmdout = [cmdout,nextLine,newline()];
if streamOutput == true
disp(nextLine);
end
continue
else
% if there are no lines ready in the reader, and the
% process is no longer running, then we are done
if ~process.isAlive()
break
end
% Check for timeout. If timeout is reached, destroy
% the process and break
if toc(timeoutTimer) > timeoutSeconds
timeoutMessage = ['sys_with_timeout(''',command, ''',', num2str(timeoutSeconds), ')',...
' failed after timeout of ',num2str(toc(timeoutTimer)),' seconds'];
if errorOnTimeout == true
error(timeoutMessage)
else
warning(timeoutMessage)
end
process.destroyForcibly();
break
end
end
end
if ~isempty(cmdout)
cmdout(end) = []; % remove trailing newline of command output
end
status = process.exitValue(); % return
end
Заменив ssh [email protected]
на wsl
(конечно, требуется WSL) для простоты, вот пример функции, время ожидания которой истекло:
>> [status,cmdout] = sys_with_timeout('wsl echo start! && sleep 2 && echo finished!',1)
start!
Warning: sys_with_timeout('wsl echo start! && sleep 2 && echo finished!',1) failed after timeout of 1.0002 seconds
> In sys_with_timeout (line 41)
status =
1
cmdout =
'start!'
и вот пример функции, которая не истекает по тайм-ауту:
>> [status,cmdout] = sys_with_timeout('wsl echo start! && sleep 2 && echo finished!',3)
start!
finished!
status =
0
cmdout =
'start!
finished!'
Я видел подобные вопросы в прошлом, но я думаю, что ни один из них не имеет удовлетворительного ответа.