在少数服务器上远程执行命令并在运行时运行已用的计时器

时间:2016-12-20 20:50:18

标签: bash shell ssh

我正在尝试编写一个脚本,该脚本将在几台服务器上执行命令,并在运行时显示已用时间。

这是我的代码,但实际上并不起作用......

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,但似乎它们没有在主机上执行。

1 个答案:

答案 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等) 祝你好运!