hi Pedro, these are interesting questions. As for fetching the exit code from spawn, SEC does that and produces a warning message if it is non-zero, but there is no equivalent to bash $? variable. Firstly, command lines are executed asynchronously by spawn, and secondly, many such command lines may be running simultaneously. It is therefore difficult to tell which command's exit code $? is currently holding. For addressing this issue, it is probably best to write a simple wrapper script around the program that needs execution, and pass the exit code value to SEC as a synthetic event (just like program's standard output is passed). For example, the following simple script creates "TEST_EXIT_<code>" synthetic event:
#!/bin/bash /bin/false echo TEST_EXIT_$? However, running a child process from SEC for at most given number of seconds is a trickier issue. Although the spawn action does not have parameters for setting this timeout, this task can again be handled with a wrapper script, and there is a relevant example in the SEC FAQ: http://simple-evcorr.github.io/FAQ.html#20 The example wrapper is universal and works not only for spawn but also other actions that fork child processes from SEC. Also, in addition to limiting the run time of child processes, one can define a signal which is used for terminating the child process. However, since in your case you also need to capture the standard output and exit code of the command that was started by spawn, I have modified the example wrapper from FAQ a bit: #!/usr/bin/perl -w # # wrapper.pl if (scalar(@ARGV) < 3) { exit(1); } $int = shift @ARGV; $sig = shift @ARGV; $cmd = join(" ", @ARGV); $SIG{TERM} = sub { $term{$$} = 1; }; if (!pipe(READ, WRITE)) { exit(1); } $pid = fork(); if ($pid == -1) { exit(1); } elsif ($pid == 0) { $SIG{TERM} = 'DEFAULT'; if (exists($term{$$})) { exit(0); } close(READ); if (!open(STDOUT, ">&WRITE")) { exit(1); } exec($cmd); exit(1); } else { $SIG{TERM} = sub { kill TERM, $pid; exit(0); }; if (exists($term{$$})) { kill TERM, $pid; exit(0); }; $SIG{ALRM} = sub { kill $sig, $pid; print "Command $cmd timed out\n"; exit(0); }; alarm($int); close(WRITE); @lines = <READ>; chomp(@lines); waitpid($pid, 0); $exitcode = $? >> 8; print "Command $cmd output: ", join(" ", @lines), "\n"; print "Command $cmd exit code: $exitcode\n"; exit($exitcode); } The first parameter of the wrapper is timeout in seconds, the second parameter the number of the signal which is sent to child process on timeout expiration, and the rest of the parameters define the command line to be executed. The wrapper forks the command line as a child process, acting as an intermediary between SEC and command line. The wrapper sets a timer for itself with the alarm() system call, delivering the signal to child when the timer expires, and reporting child standard output and exit code back to SEC if the child process finishes before timeout. Child standard output is collected through a pipe and reported in two lines, with the first line representing entire standard output and the second line the exit code of the child. If SEC is shut down, the wrapper also forwards the TERM signal received from SEC to child process, so that the command line would not stay in the process table after SEC has finished. Here is an example ruleset that utilizes the wrapper for starting command lines with spawn, and collecting their outputs and exit codes: type=Single ptype=RegExp pattern=start (\d+) (.+) desc=allow child process to run for $1 seconds and terminate it with TERM (15) signal action=spawn ./wrapper.pl $1 15 $2 type=Single ptype=RegExp2 pattern=Command (.+) output: (.*)\nCommand \1 exit code: (\d+) desc=Catch the output and exit code of the child process action=write - command $1, output $2, exit code $3 type=Single ptype=RegExp pattern=Command (.+) timed out desc=Child process has timed out action=write - command $1 has timed out The first rule runs a command line via wrapper, e.g., if line "start 1 sleep 60" is provided to SEC, command line "sleep 60" is allowed to run for 1 second. Since this command line runs for 1 minute, it gets terminated after 1 second with TERM signal (signal number 15), and wrapper generates the following synthetic event "Command sleep 60 timed out". This event is matched by the third rule which writes the string "command sleep 60 has timed out" to standard output. On the other hand, if line "start 5 /bin/date" is provided to SEC, /bin/date is allowed to run for 5 seconds which is more than enough for successful completion. Therefore, the wrapper reports back output and exit code from /bin/date which are matched by the second rule, and a string similar to the following gets written to standard output: "command /bin/date, output Tue Jul 30 00:44:16 EEST 2019, exit code 0" (the second rule utilizes the RegExp2 pattern for matching two consecutive synthetic events received from wrapper). Finally, the wrapper doesn't have to be written in Perl, but any other language could be used for putting it together. Hopefully these examples are helpful. kind regards, risto Kontakt Pedro Samarra (<julio.sama...@yandex.com>) kirjutas kuupƤeval E, 29. juuli 2019 kell 02:32: > Hello, > > I was looking into spawn to get both the output of a command and it's > exit code. Output is obvious, but exit code I cannot find documentation. > I'm looking for the Bash equivalent of '$?'. > > Also, if the command hangs, is there a timeout setting that kills the > command and sets a context for the fact that the timeout threshold was > reached? > > Thanks. > _______________________________________________ > Simple-evcorr-users mailing list > Simple-evcorr-users@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/simple-evcorr-users >
_______________________________________________ Simple-evcorr-users mailing list Simple-evcorr-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/simple-evcorr-users