我正在尝试编写一个脚本,该脚本将在几台服务器上执行命令,并在运行时显示已用时间。
这是我的代码,但实际上并不起作用......
echo "Starting..."
server_num=4
cnt=1
SECONDS=0
for ((i=1; i<=$server_num; i++)) ;do
read -r pid[$i] < <(
ssh server$i 'nohup "yes | yes | command" > logfile & echo $!'
)
echo
while kill -0 ${pid[@]} 2> /dev/null; do
sleep 1
duration=$SECONDS
echo -n "Please wait... $(($duration / 60)) minutes and $(($duration % 60)) seconds elapsed." $'\r'
let cnt=cnt+1
done
done
wait
sleep 5
echo "completed..."
我做错了什么?我正在获取已执行命令的pid,但似乎它们没有在主机上执行。
答案 0 :(得分:1)
脚本的主要问题是后台作业在远程系统上启动,但检查进度是在本地完成的。 编写这样的脚本并不容易,因为需要考虑许多问题(例如本地命令,远程命令持续时间,网络延迟,连接问题,命令输出,可重用的pid等)。 每个人都在职业生涯中的某个时刻写过这样的剧本,每个人都从中学习,所以我试图用两种方式纠正你的剧本,保持你的想法并删除一些不必要的东西,这样你也可以提高你的知识。
版本1:在远程服务器上执行命令,并在后台作业中保持连接打开。一旦命令在所有主机上启动,然后循环,同时作业数大于0,显示每秒重复的消息。 Pro:更简单的代码,易于检查 Con:如果在执行期间网络中断,作业将被中断。
server_num=4
SECONDS=0
echo "Starting..."
# Start jobs in background wich will execute remote commands that take long
for ((i=1; i<=$server_num; i++)); do
ssh server$i "sleep 5" &
done
# Now check the progress until all finish
while [[ $(jobs | wc -l) -gt 0 ]]; do
echo "Please wait... $(jobs | wc -l) jobs still running... $((SECONDS/60)) minutes and $((SECONDS%60)) seconds elapsed."
sleep 1
jobs >/dev/null 2>&1
done
echo "completed..."
版本2:在后台启动远程服务器上的作业,在启动后立即关闭连接,但保留每个主机的作业PID。然后在运行作业的计数器大于0时循环,每次连接到每个主机并检查具有保存的PID的进程是否仍然存活,如果是,则递增计数器并最终显示消息。 Pro:不需要保持持久连接(如果网络中断,作业是安全的。 Con:如果在主机上作业将完成,则仍然在该主机上执行检查(如果在此期间重复使用PID,则脚本可能需要更长时间检查错误的内容)。
server_num=4
SECONDS=0
echo "Starting..."
# Start jobs on remote hosts in background wich will take long
for ((i=1; i<=$server_num; i++)); do
# save the process ID for each case
pid[$i]=$(ssh server$i 'nohup bash -c "sleep 12" >logfile 2>&1 & echo $!')
done
# Now check the progress on each host untill all jobs finish
count=${#pid[@]}
while [[ $count -gt 0 ]]; do
count=0
for ((i=1; i<=$server_num; i++)); do
# remotely check if the process id is still in use
ssh server$i ps -p ${pid[$i]} >/dev/null 2>&1
if [[ $? -eq 0 ]]; then
((count=count+1))
fi
done
echo "Please wait... $count jobs still running... $((SECONDS/60)) minutes and $((SECONDS%60)) seconds elapsed."
sleep 1
done
echo "completed..."
如果您将这些脚本用于实际工作,那么您将发现可以纠正的其他问题。最终建议使用专门为处理此类任务而构建的其他工具(parallels,dsh等) 祝你好运!