Here's my current bash which is just a loop
while true ; do
python3 /Users/Name/Desktop/pythoncode.py
done
I want to terminate pythoncode.py if it doesn’t output anything to the terminal in 2 min
Here's my current bash which is just a loop
while true ; do
python3 /Users/Name/Desktop/pythoncode.py
done
I want to terminate pythoncode.py if it doesn’t output anything to the terminal in 2 min
With zsh:
zmodload zsh/system
(
echo $sysparam[pid]
exec python3 /Users/Name/Desktop/pythoncode.py
) | {
read pid
if sysread -o 1 -s 1 -t120; then
cat
else
kill -s PIPE $pid 2> /dev/null
fi
}
With bash, you can do something similar with:
(
echo "$BASHPID"
exec python3 /Users/Name/Desktop/pythoncode.py
) | {
read pid
if LC_ALL=C IFS= read -rd '' -n1 -t120 byte; then
if [ -n "$byte" ]; then
printf %s "$byte"
else
printf '\0'
fi
cat
else
kill -s PIPE "$pid" 2> /dev/null
fi
}
Those check whether that script writes anything to stdout, not specifically to the terminal.
If you also want to stop if the command has written something, but stopped and hasn't output anything within two minutes, or in other words, kill the command after 2 minutes of inactivity, then you could just use socat:
socat -T120 'exec:python3 /Users/Name/Desktop/pythoncode.py' -
Or with zsh:
zmodload zsh/system
(
echo $sysparam[pid]
exec python3 /Users/Name/Desktop/pythoncode.py
) | {
read pid
while
sysread -o 1 -t 120; ret=$?
(( ret == 0 ))
do continue; done
# 5 means EOF
(( ret == 5 )) || kill $pid
}
With bash, you can use process substitution and redirection, and a while loop with read -t timeout. The subshell will be no more, when the while loop exits because of the timeout (That means when the python script has no output, seems inactive, for 2 minutes).
while IFS= read -r -t120 x; do
printf "%s\n" "$x"
done < <(python3 script.py)
Note: I have assumed line-oriented output into this example (or else read and printf char by char).
The difference of this structure to using a pipe, is that we have one command here. When this command exits, the file input from the file descriptor is over, the command in the subshell writing into this descriptor is over. So the python script is killed just after the timeout.
When piping like this:
python3 script.py | {
while IFS= read -r -t120 x; do
printf "%s\n" "$x"
done
}
we execute two commands, and if the second one exits (because of the timeout), the first one will continue to run, until trying to write to the pipe again. When this happens, it will terminate, without writing anything more, because of broken pipe. So here the python script is killed when trying to write again after the timeout.
If the acceptable accuracy is ~1 second, you could use date +%s to collect the actual time and check how long there's no output from your script (collecting it as a shell variable):
ELAPSED_T=0 # the time that has passed since last output
LAST_OUT_T=`date +%s` # avoid to stop if the first iteration has empty output
while [ "$ELAPSED_T" -lt 120 ]; do # continue if the last output was printed less than 120 seconds ago
OUT=`python3 /Users/Name/Desktop/pythoncode.py` # run the script and collect the output
echo "$OUT" # print the output on screen
if [ -n "$OUT" ]; then # if the output is not empty, update the last output time
LAST_OUT_T=`date +%s`
else # otherwise, evaluate how much time has passed since last output
NOW_T=`date +%s`
ELAPSED_T=$((NOW_T - LAST_OUT_T))
fi
done
You might want to check out the GNU timeout command. It takes the duration as an argument followed by the command. Here is a simple invocation:
timeout 5s ping www.website.com
From its manpage:
TIMEOUT(1) User Commands TIMEOUT(1)
NAME
timeout - run a command with a time limit
SYNOPSIS
timeout [OPTION] DURATION COMMAND [ARG]...
timeout [OPTION]
DESCRIPTION
Start COMMAND, and kill it if still running after DURATION.
...
You can also specify the type of signal to send to the process (like HUP, 9, SIGTERM, etc.) at the end of the timeout.
HTH.