如何编写一个脚本,在后台运行子进程的5个实例(间隔为5秒)并进行连续检查以查看是否有任何子进程完成它启动另一个实例同一过程直到子进程执行了20个实例。
答案 0 :(得分:2)
嗯,我不完全确定你在问什么,但我会尽力引导你走上正确的道路......
你可以在脚本中分叉进程,如下所示:
/path/to/executable &
等待5秒钟:
sleep 5
您可以通过ps查看当前正在运行的程序实例数:
ps aux | grep executable | wc -l
要跟踪已运行的实例数,请使用循环和递增值:
#!/bin/bash
count = 0
while [ $count -lt 20 ]
do
if [ `ps aux | grep executable | wc -l` -lt 5 ]
then
/path/to/executable &
let "count += 1"
sleep 5
fi
done
描述有些模糊,我不确定你是否希望在随后的15个实例中继续进行5秒的间隙,如果你只希望一次最多运行5个?这就是我解释它的方式。有很多方法可以实现这种逻辑。
答案 1 :(得分:0)
这应该在大多数POSIX-ish shell中运行(我用破折号测试(956b4bd ...来自Git),ksh(来自Mac OS X 10.4的“1993-12-28 p”),bash(2.05b和4.0.35) ,zsh(4.3.10-dev-1;实际上是8a04e94 ......来自Git)):
#!/usr/bin/env dash
# usage: run-em <num> <num-simul> <start-gap> <executable> [<args ...]
test -n "$ZSH_VERSION" && setopt sh_word_split
pids=''
num="$1"
num_started=0
num_simul="$2"
start_gap="$3"
shift 3
poll_gap=1 # polling interval
while test "$num_started" -lt "$num" ||
test -n "$pids"; do
alive_pids=''
for pid in $pids; do
if kill -0 "$pid" > /dev/null 2>&1; then
alive_pids="$pid
$alive_pids"
else
printf 'PID %s is gone\n' "$pid" 1>&2
fi
done
pids="$alive_pids"
new_pid=''
if test "$num_started" -lt "$num" &&
test "$(printf "$pids" | wc -l)" -lt "$num_simul"; then
exec 3>&1
new_pid="$("$@" 1>&3 3>&- & echo "$!")"
exec 3>&-
num_started="$((num_started+1))"
printf 'Started PID %s as #%s\n' "$new_pid" "$num_started" 1>&2
pids="$new_pid
$pids"
if test -n "$start_gap" &&
test "$num" -gt 0; then
printf 'Waiting %s seconds...' "$start_gap" 1>&2
sleep "$start_gap"
printf 'done\n' 1>&2
fi
fi
test -z "$start_gap$new_pid" && sleep "$poll_gap"
test "$num_started" -ge "$num_simul" && start_gap=''
done
经过测试:run-em 5 2 4 sh -c 'echo "[[$$ starting]]";sleep 13;echo "[[$$ ending]]"'
如果你想把自己绑定到一个特定的shell,你可以在SIGCHLD上使用作业控制和陷阱而不是使用kill -0
进行双重分叉和探测(ksh和zsh似乎能够做到这一点,破折号和bash似乎已经破坏了; zsh还有一个jobstates参数,如果SIGCHLD陷阱在那里被破坏,可用于检查正在运行的作业)。在某些语言(例如Perl)中,您可以使用waitpid(2)
或wait4(2)
等待任何子进程,以便您可以收集实际的退出代码。不幸的是,大多数shell似乎只让你等待一个特定的子进程,这只有在你提前知道哪个进程将首先完成时才会起作用。