如果 python 脚本在 2 分钟内没有向终端输出任何内容,我想终止它

如果 python 脚本在 2 分钟内没有向终端输出任何内容,我想终止它

这是我当前的 bash,它只是一个循环

while true ; do 
     python3 /Users/Name/Desktop/pythoncode.py
done

pythoncode.py如果 2 分钟内没有向终端输出任何内容,我想终止

答案1

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
}

使用bash,您可以执行类似的操作:

(
  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
}

这些检查该脚本是否将任何内容写入标准输出,而不是专门写入终端。

如果您还想在命令已写入内容时停止,但停​​止并且在两分钟内没有输出任何内容,或者换句话说,在 2 分钟不活动后终止命令,那么您可以使用socat

socat -T120 'exec:python3 /Users/Name/Desktop/pythoncode.py' -

或者与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
}

答案2

使用bash,您可以使用进程替换和重定向以及while带超时的循环read -t。当while循环由于超时而退出时(这意味着当 python 脚本没有输出,看起来不活动,持续 2 分钟),子 shell 将不再存在。

while IFS= read -r -t120 x; do
    printf "%s\n" "$x"
done < <(python3 script.py)

注意:我假设本示例中是面向行的输出(或者是逐个字符的输出)readprintf


这种结构与使用管道的区别在于我们这里有一个命令。当该命令退出时,从文件描述符的文件输入结束,子shell中写入该描述符的命令也结束。所以python脚本被杀死了超时后

当像这样管道时:

python3 script.py | { 
    while IFS= read -r -t120 x; do
        printf "%s\n" "$x"
    done
}

我们执行两个命令,如果第二个命令退出(由于超时),第一个命令将继续运行,直到再次尝试写入管道。当发生这种情况时,由于管道损坏,它将终止,不再写入任何内容。所以这里python脚本被杀死了超时后尝试再次写入时

答案3

如果可接受的精度是~1 秒,您可以用它date +%s来收集实际时间并检查脚本没有输出的时间(将其收集为 shell 变量):

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

答案4

您可能想查看 GNUtimeout命令。它将持续时间作为参数,后跟命令。这是一个简单的调用:

timeout 5s ping www.website.com

从它的联机帮助页来看:

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.
...

您还可以指定在超时结束时发送到进程的信号类型(如 HUP、9、SIGTERM 等)。

HTH。

相关内容