一些说明:
chmod +x
在这里是无用的。你可以直接运行 sh command1.sh &
。
- 你必须独立地终止所有子任务。
- 由于这个问题标记了 shell,我的答案不使用 bashisms。所有脚本都在 bash、dash 和 busybox 下测试过。
可以像这样:
#!/bin/sh
for cmd in ./command1.sh ./command2.sh;do
exec $cmd &
PIDS="$PIDS $!"
done
trap "kill $PIDS;exit" 15
wait
当然,在
for cmd in
和
;do
之间,你可以放置任意多个
commandXX.sh
(只要你保持行长度在你安装的操作系统支持的最大长度范围内)。
测试脚本:
这是一个快速的bash测试脚本,它在2.0到12.99秒之间随机睡眠,然后在退出之前打印done.
:
#!/bin/bash
declare -i toSleep
case $1 in '' | *[!0-9]* ) toSleep='RANDOM%10+2' ;; * ) toSleep=$1 ;; esac
exec {dummy}<> <(:)
read -t $toSleep.$RANDOM -u $dummy _
echo done.
我已将此保存到
command1.sh
中,运行
chmod +x ..
并链接到
command2.sh
...
更便携的包装器:
#!/bin/sh
for cmd in "$@";do
exec $cmd &
PIDS="$PIDS $!"
done
printf "You have to: kill -TERM %d\nto end %d tasks: %s\n" \
$$ $(echo $PIDS|wc -w) "$PIDS"
trap "kill $PIDS;echo 'Process $$ killed.';exit" 15
wait
echo "Process $$ running $@ ended normally"
您可以将此
shell脚本保存到名为
simpleParallel.sh
的文件中,例如:
chmod +x simpleParallel.sh
./simpleParallel.sh ./command1.sh ./command2.sh
You have to: kill -TERM 741297
to end 2 tasks: 741298 741299
然后,如果你从其他地方运行
kill -TERM 741297
,
Process 741297 killed.
但如果你不这样做,你可能会读到类似这样的东西:
./simpleParallel.sh ./command1.sh ./command2.sh
You have to: kill -TERM 741968
to end 2 tasks: 741969 741970
done.
done.
Process 741968 running ./command1.sh ./command2.sh ended normally
注意:如果你在一个进程已经完成的情况下发送了你的终止命令,你可能会看到错误消息,例如:
./simpleParallel.sh: 1: kill: No such process
看一下
bash 的版本就能避免这个 bug。
从另一个终端控制台中跟进
在运行
./simpleParallel.sh
之前,你可以运行不带参数的
tty
命令:
tty
/dev/pts/2
然后在一个新的空闲窗口中,您可以运行:
watch ps --tty pts/2
在使用另一个窗口运行
kill
命令时。
带有一些的bash,现在:
在最近的bash中,有很多特殊功能。
- 您可以使用数组来储存后台任务的PID。
- 从5.0版本开始,有一个
$EPOCHREALTIME
变量,它展开为自Unix纪元以来的秒数,具有微秒精度。
- 从5.0版本开始,关联数组允许包含空格的下标。
- 从5.1版本开始,
wait
有一个新的[-p VARNAME]
选项,该选项存储由wait -n
或没有参数的wait
返回的PID
。
我的脚本可以变成:
#!/bin/bash
declare -A PIDS ENDED
started=$EPOCHREALTIME
for cmd; do
exec "$cmd" &
PIDS["$cmd"]=$!
CMDS[$!]="$cmd"
done
printf "You have to: kill -TERM %d\nto end %d tasks: %s\n" \
$$ ${#PIDS[@]} "${PIDS[*]}"
trapExit(){
kill "${PIDS[@]}"
printf 'Process %s + %d task killed: %s\n' $$ ${#PIDS[@]} "${!PIDS[*]}"
showDone
exit 1
}
trap trapExit 15
showDone() {
for cmd in "${!ENDED[@]}";do
read -r elap < <(bc -l <<<"${ENDED["$cmd"]}-$started")
printf "Elapsed: %.4f sec for %s\n" "$elap" "$cmd"
done
}
while ((${#PIDS[@]}));do if wait -n -p pid ;then
printf "Process %d done (%s).\n" "$pid" "${CMDS[pid]}"
ENDED["${CMDS[pid]}"]=$EPOCHREALTIME
unset PIDS["${CMDS[pid]}"] CMDS[pid]
fi; done
echo "Process $$ running $* ended normally"
showDone
输出可能看起来像这样:
./simpleParallel.bash ./command{1,2}.sh
You have to: kill -TERM 1309816
to end 2 tasks: 1309817 1309818
done.
Process 1309817 done (./command1.sh).
done.
Process 1309818 done (./command2.sh).
Process 1309816 running ./command1.sh ./command2.sh ended normally
Elapsed: 3.1644 sec for ./command1.sh
Elapsed: 4.2488 sec for ./command2.sh
或者
./simpleParallel.bash ./command{1,2}.sh
You have to: kill -TERM 1310031
to end 2 tasks: 1310032 1310033
done.
Process 1310033 done (./command2.sh).
done.
Process 1310032 done (./command1.sh).
Process 1310031 running ./command1.sh ./command2.sh ended normally
Elapsed: 9.1868 sec for ./command1.sh
Elapsed: 3.2310 sec for ./command2.sh
如果你早期“杀死”它们:
./simpleParallel.bash ./command{1,2}.sh
You have to: kill -TERM 1294577
to end 2 tasks: 1294578 1294579
Process 1294577 + 2 task killed: ./command1.sh ./command2.sh
如果你之后“杀”了他们:
./simpleParallel.bash ./command{1,2}.sh
You have to: kill -TERM 1294958
to end 2 tasks: 1294959 1294960
done.
Process 1294959 done (./command1.sh).
Process 1294958 + 1 task killed: ./command2.sh
Elapsed: 3.1779 sec for ./command1.sh
或者
./simpleParallel.bash ./command{1,2}.sh
You have to: kill -TERM 1294971
to end 2 tasks: 1294972 1294973
done.
Process 1294973 done (./command2.sh).
Process 1294971 + 1 task killed: ./command1.sh
Elapsed: 6.9344 sec for ./command2.sh
没有关于尝试杀死不存在的进程ID的错误消息。
./command1.sh&./command2.sh&wait
。 - William PursellexitCode
。如果你希望得到完整的答案,你需要展示完整的代码。你的陷阱也需要将信号传递给子进程,他们需要迅速响应信号。 - William Pursell