mob*_*mob 110
1:在bash中,$!保存已执行的最后一个后台进程的PID.无论如何,这将告诉您要监控的流程.
4:wait <n>等待ID完成的进程完成(它将阻塞直到进程完成,所以你可能不想在确定进程完成之前调用它).后<n>返回时,进程的退出代码在变量返回ps
2,3:ps | grep " $! "或者ps | grep可以告诉你进程是否仍在运行.由您决定如何理解输出并决定它与完成的接近程度.($!不是白痴.如果你有时间,你可以想出一个更健壮的方法来判断这个过程是否还在运行).
这是一个骨架脚本:
# simulate a long process that will have an identifiable exit code
(sleep 15 ; /bin/false) &
my_pid=$!
while ps | grep " $my_pid " # might also need | grep -v grep here
do
echo $my_pid is still in the ps output. Must still be running.
sleep 3
done
echo Oh, it looks like the process is done.
wait $my_pid
# The variable $? always holds the exit code of the last command to finish.
# Here it holds the exit code of $my_pid, since wait exits with that code.
my_status=$?
echo The exit status of the process was $my_status
Run Code Online (Sandbox Code Playgroud)
Bjo*_*orn 45
这就是我遇到类似需求时的解决方法:
# Some function that takes a long time to process
longprocess() {
# Sleep up to 14 seconds
sleep $((RANDOM % 15))
# Randomly exit with 0 or 1
exit $((RANDOM % 2))
}
pids=""
# Run five concurrent processes
for i in {1..5}; do
( longprocess ) &
# store PID of process
pids+=" $!"
done
# Wait for all processes to finnish, will take max 14s
for p in $pids; do
if wait $p; then
echo "Process $p success"
else
echo "Process $p fail"
fi
done
Run Code Online (Sandbox Code Playgroud)
#/bin/bash
#pgm to monitor
tail -f /var/log/messages >> /tmp/log&
# background cmd pid
pid=$!
# loop to monitor running background cmd
while :
do
ps ax | grep $pid | grep -v grep
ret=$?
if test "$ret" != "0"
then
echo "Monitored pid ended"
break
fi
sleep 5
done
wait $pid
echo $?
Run Code Online (Sandbox Code Playgroud)
我看到几乎所有答案都使用外部工具(大多数ps)来轮询后台进程的状态.有一个更多的unixesh解决方案,捕获SIGCHLD信号.在信号处理程序中,必须检查哪个子进程已停止.它可以通过kill -0 <PID>内置(通用)或检查/proc/<PID>目录的存在(特定jobs于Linux)或使用内置(特定于bash.jobs -l还报告pid来完成.在这种情况下,输出的第3个字段可以是Stopped | Running |完成|退出.).
这是我的例子.
调用已启动的进程loop.sh.它接受-x或数字作为参数.对于-x具有退出代码1的退出.对于数字,它等待数*5秒.每5秒打印一次PID.
启动程序进程称为launch.sh:
#!/bin/bash
handle_chld() {
local tmp=()
for((i=0;i<${#pids[@]};++i)); do
if [ ! -d /proc/${pids[i]} ]; then
wait ${pids[i]}
echo "Stopped ${pids[i]}; exit code: $?"
else tmp+=(${pids[i]})
fi
done
pids=(${tmp[@]})
}
set -o monitor
trap "handle_chld" CHLD
# Start background processes
./loop.sh 3 &
pids+=($!)
./loop.sh 2 &
pids+=($!)
./loop.sh -x &
pids+=($!)
# Wait until all background processes are stopped
while [ ${#pids[@]} -gt 0 ]; do echo "WAITING FOR: ${pids[@]}"; sleep 2; done
echo STOPPED
Run Code Online (Sandbox Code Playgroud)
有关更多说明,请参阅:从bash脚本启动进程失败
背景子进程的pid存储在$!中!.您可以将所有子进程的pid存储到数组中,例如PIDS [].
wait [-n] [jobspec or pid …]
Run Code Online (Sandbox Code Playgroud)
等到每个进程ID pid或作业规范jobspec指定的子进程退出并返回等待的最后一个命令的退出状态.如果给出了作业规范,则等待作业中的所有进程.如果未给出参数,则等待所有当前活动的子进程,并且返回状态为零.如果提供了-n选项,则wait等待任何作业终止并返回其退出状态.如果jobspec和pid都没有指定shell的活动子进程,则返回状态为127.
使用wait命令可以等待所有子进程完成,同时你可以通过$获得每个子进程的退出状态?并将状态存储到STATUS []中.然后你可以根据状态做一些事情.
我尝试了以下两种解决方案,运行良好.solution01更简洁,而solution02有点复杂.
#!/bin/bash
# start 3 child processes concurrently, and store each pid into array PIDS[].
process=(a.sh b.sh c.sh)
for app in ${process[@]}; do
./${app} &
PIDS+=($!)
done
# wait for all processes to finish, and store each process's exit code into array STATUS[].
for pid in ${PIDS[@]}; do
echo "pid=${pid}"
wait ${pid}
STATUS+=($?)
done
# after all processed finish, check their exit codes in STATUS[].
i=0
for st in ${STATUS[@]}; do
if [[ ${st} -ne 0 ]]; then
echo "$i failed"
else
echo "$i finish"
fi
((i+=1))
done
Run Code Online (Sandbox Code Playgroud)
#!/bin/bash
# start 3 child processes concurrently, and store each pid into array PIDS[].
i=0
process=(a.sh b.sh c.sh)
for app in ${process[@]}; do
./${app} &
pid=$!
PIDS[$i]=${pid}
((i+=1))
done
# wait for all processes to finish, and store each process's exit code into array STATUS[].
i=0
for pid in ${PIDS[@]}; do
echo "pid=${pid}"
wait ${pid}
STATUS[$i]=$?
((i+=1))
done
# after all processed finish, check their exit codes in STATUS[].
i=0
for st in ${STATUS[@]}; do
if [[ ${st} -ne 0 ]]; then
echo "$i failed"
else
echo "$i finish"
fi
((i+=1))
done
Run Code Online (Sandbox Code Playgroud)
我会稍微改变您的方法。而不是每隔几秒钟检查一次命令是否仍在运行并报告消息,而是让另一个进程每几秒钟报告一次该命令仍在运行,然后在命令完成时终止该进程。例如:
#!/ bin / sh
cmd(){睡眠5; 出口24; }
cmd&#运行长时间运行的进程
pid = $!#记录pid
#生成一个进程,最终报告该命令仍在运行
而回声“ $(日期):$ pid仍在运行”;睡1 完成&
echoer = $!
#设置陷阱以在过程结束时杀死报告程序
陷阱'kill $ echoer'0
#等待过程完成
如果等待$ pid; 然后
回声“ cmd成功”
其他
回声“ cmd FAILED !!(返回$?)”
科幻