我有一个长期运行的BASH脚本,我在Windows上运行CYGWIN.
我想限制脚本运行30秒,如果超过此限制则自动终止.理想情况下,我希望能够对任何命令执行此操作.
例如:
sh-3.2$ limittime -t 30 'myscript.sh'
要么
sh-3.2$ limittime -t 30 'grep func *.c'
在cygwin下,ulimit命令似乎不起作用.
我对任何想法持开放态度.
请参阅http://www.pixelbeat.org/scripts/timeout脚本,其功能已集成到较新的coreutils中:
#!/bin/sh # Execute a command with a timeout # License: LGPLv2 # Author: # http://www.pixelbeat.org/ # Notes: # Note there is a timeout command packaged with coreutils since v7.0 # If the timeout occurs the exit status is 124. # There is an asynchronous (and buggy) equivalent of this # script packaged with bash (under /usr/share/doc/ in my distro), # which I only noticed after writing this. # I noticed later again that there is a C equivalent of this packaged # with satan by Wietse Venema, and copied to forensics by Dan Farmer. # Changes: # V1.0, Nov 3 2006, Initial release # V1.1, Nov 20 2007, Brad Greenlee# Make more portable by using the 'CHLD' # signal spec rather than 17. # V1.3, Oct 29 2009, Ján Sáreník # Even though this runs under dash,ksh etc. # it doesn't actually timeout. So enforce bash for now. # Also change exit on timeout from 128 to 124 # to match coreutils. # V2.0, Oct 30 2009, Ján Sáreník # Rewritten to cover compatibility with other # Bourne shell implementations (pdksh, dash) if [ "$#" -lt "2" ]; then echo "Usage: `basename $0` timeout_in_seconds command" >&2 echo "Example: `basename $0` 2 sleep 3 || echo timeout" >&2 exit 1 fi cleanup() { trap - ALRM #reset handler to default kill -ALRM $a 2>/dev/null #stop timer subshell if running kill $! 2>/dev/null && #kill last job exit 124 #exit with 124 if it was running } watchit() { trap "cleanup" ALRM sleep $1& wait kill -ALRM $$ } watchit $1& a=$! #start the timeout shift #first param was timeout for sleep trap "cleanup" ALRM INT #cleanup after timeout "$@"& wait $!; RET=$? #start the job wait for it and save its return value kill -ALRM $a #send ALRM signal to watchit wait $a #wait for watchit to finish cleanup exit $RET #return the value
以下脚本显示了如何使用后台任务执行此操作.第一部分在10秒限制后杀死60秒的过程.第二次尝试杀死已经退出的进程.请记住,如果您将超时设置得非常高,那么进程ID可能会翻转并且您将杀死错误的进程,但这更像是一个理论问题 - 超时必须非常大而且您必须是开始很多流程.
#!/usr/bin/bash sleep 60 & pid=$! sleep 10 kill -9 $pid sleep 3 & pid=$! sleep 10 kill -9 $pid
这是我的Cygwin盒子上的输出:
$ ./limit10 ./limit10: line 9: 4492 Killed sleep 60 ./limit10: line 11: kill: (4560) - No such process
如果您只想等到该过程完成,则需要输入循环并检查.这稍微不准确,因为sleep 1
其他命令实际上需要超过一秒(但不多).使用此脚本替换上面的第二部分(" echo $proc
"和" date
"命令用于调试,我不希望在最终解决方案中使用它们).
#!/usr/bin/bash date sleep 3 & pid=$! ((lim = 10)) while [[ $lim -gt 0 ]] ; do sleep 1 proc=$(ps -ef | awk -v pid=$pid '$2==pid{print}{}') echo $proc ((lim = lim - 1)) if [[ -z "$proc" ]] ; then ((lim = -9)) fi done date if [[ $lim -gt -9 ]] ; then kill -9 $pid fi date
它基本上循环,检查进程是否仍然每秒运行.如果没有,它会以特殊值退出循环,不会尝试杀死孩子.否则它会超时并杀死孩子.
这是一个输出sleep 3
:
Mon Feb 9 11:10:37 WADT 2009 pax 4268 2476 con 11:10:37 /usr/bin/sleep pax 4268 2476 con 11:10:37 /usr/bin/sleep Mon Feb 9 11:10:41 WADT 2009 Mon Feb 9 11:10:41 WADT 2009
和a sleep 60
:
Mon Feb 9 11:11:51 WADT 2009 pax 4176 2600 con 11:11:51 /usr/bin/sleep pax 4176 2600 con 11:11:51 /usr/bin/sleep pax 4176 2600 con 11:11:51 /usr/bin/sleep pax 4176 2600 con 11:11:51 /usr/bin/sleep pax 4176 2600 con 11:11:51 /usr/bin/sleep pax 4176 2600 con 11:11:51 /usr/bin/sleep pax 4176 2600 con 11:11:51 /usr/bin/sleep pax 4176 2600 con 11:11:51 /usr/bin/sleep pax 4176 2600 con 11:11:51 /usr/bin/sleep pax 4176 2600 con 11:11:51 /usr/bin/sleep Mon Feb 9 11:12:03 WADT 2009 Mon Feb 9 11:12:03 WADT 2009 ./limit10: line 20: 4176 Killed sleep 60
看看这个链接.这个想法只是你将myscript.sh
作为脚本的子进程运行并记录它的PID,如果它运行得太长就杀掉它.